From ac2cb6c0f82f1f24f3c421e622508d6a3eedd670 Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Fri, 6 Jun 2008 08:36:51 -0400 Subject: [PATCH] Import NSPR 4_7_1_RTM --- nsprpub/.cvsignore | 5 + nsprpub/Makefile.in | 152 + nsprpub/admin/explode.pl | 75 + nsprpub/admin/makeTargetDirs.sh | 79 + nsprpub/admin/repackage.sh | 211 + nsprpub/admin/symlinks.sh | 75 + nsprpub/build/autoconf/config.guess | 1481 ++++ nsprpub/build/autoconf/config.sub | 1595 +++++ nsprpub/build/autoconf/install-sh | 119 + nsprpub/build/cygwin-wrapper | 75 + nsprpub/config/.cvsignore | 11 + nsprpub/config/Makefile.in | 160 + nsprpub/config/autoconf.mk.in | 130 + nsprpub/config/config.mk | 164 + nsprpub/config/gcc_hidden.h | 2 + nsprpub/config/libc_r.h | 158 + nsprpub/config/make-system-wrappers.pl | 59 + nsprpub/config/nfspwd.pl | 50 + nsprpub/config/now.c | 142 + nsprpub/config/nsinstall.c | 602 ++ nsprpub/config/nspr-config.in | 143 + nsprpub/config/nspr.m4 | 82 + nsprpub/config/nsprincl.mk.in | 5 + nsprpub/config/nsprincl.sh.in | 5 + nsprpub/config/pathsub.h | 78 + nsprpub/config/prdepend.h | 44 + nsprpub/config/rules.mk | 527 ++ nsprpub/config/system-headers | 172 + nsprpub/configure | 6379 +++++++++++++++++ nsprpub/configure.in | 2907 ++++++++ nsprpub/lib/.cvsignore | 1 + nsprpub/lib/Makefile.in | 56 + nsprpub/lib/ds/.cvsignore | 2 + nsprpub/lib/ds/MANIFEST | 7 + nsprpub/lib/ds/Makefile.in | 197 + nsprpub/lib/ds/plarena.c | 446 ++ nsprpub/lib/ds/plarena.h | 213 + nsprpub/lib/ds/plarenas.h | 115 + nsprpub/lib/ds/plds.def | 83 + nsprpub/lib/ds/plds.rc | 101 + nsprpub/lib/ds/plds_symvec.opt | 37 + nsprpub/lib/ds/plhash.c | 541 ++ nsprpub/lib/ds/plhash.h | 165 + nsprpub/lib/ds/plvrsion.c | 125 + nsprpub/lib/libc/.cvsignore | 1 + nsprpub/lib/libc/Makefile.in | 56 + nsprpub/lib/libc/README | 20 + nsprpub/lib/libc/include/.cvsignore | 1 + nsprpub/lib/libc/include/MANIFEST | 9 + nsprpub/lib/libc/include/Makefile.in | 61 + nsprpub/lib/libc/include/README | 7 + nsprpub/lib/libc/include/plbase64.h | 98 + nsprpub/lib/libc/include/plerror.h | 66 + nsprpub/lib/libc/include/plgetopt.h | 156 + nsprpub/lib/libc/include/plresolv.h | 108 + nsprpub/lib/libc/include/plstr.h | 470 ++ nsprpub/lib/libc/src/.cvsignore | 2 + nsprpub/lib/libc/src/Makefile.in | 197 + nsprpub/lib/libc/src/README | 20 + nsprpub/lib/libc/src/base64.c | 428 ++ nsprpub/lib/libc/src/plc.def | 104 + nsprpub/lib/libc/src/plc.rc | 102 + nsprpub/lib/libc/src/plc_symvec.opt | 53 + nsprpub/lib/libc/src/plerror.c | 88 + nsprpub/lib/libc/src/plgetopt.c | 254 + nsprpub/lib/libc/src/plvrsion.c | 125 + nsprpub/lib/libc/src/strcat.c | 81 + nsprpub/lib/libc/src/strccmp.c | 115 + nsprpub/lib/libc/src/strchr.c | 88 + nsprpub/lib/libc/src/strcmp.c | 57 + nsprpub/lib/libc/src/strcpy.c | 84 + nsprpub/lib/libc/src/strcstr.c | 124 + nsprpub/lib/libc/src/strdup.c | 85 + nsprpub/lib/libc/src/strlen.c | 71 + nsprpub/lib/libc/src/strpbrk.c | 100 + nsprpub/lib/libc/src/strstr.c | 117 + nsprpub/lib/libc/src/strtok.c | 89 + nsprpub/lib/msgc/.cvsignore | 1 + nsprpub/lib/msgc/Makefile.in | 52 + nsprpub/lib/msgc/include/.cvsignore | 1 + nsprpub/lib/msgc/include/MANIFEST | 5 + nsprpub/lib/msgc/include/Makefile.in | 61 + nsprpub/lib/msgc/include/gcint.h | 129 + nsprpub/lib/msgc/include/prgc.h | 419 ++ nsprpub/lib/msgc/src/.cvsignore | 1 + nsprpub/lib/msgc/src/Makefile.in | 98 + nsprpub/lib/msgc/src/macgc.c | 75 + nsprpub/lib/msgc/src/os2gc.c | 83 + nsprpub/lib/msgc/src/prgcapi.c | 351 + nsprpub/lib/msgc/src/prmsgc.c | 3514 +++++++++ nsprpub/lib/msgc/src/unixgc.c | 155 + nsprpub/lib/msgc/src/win16gc.c | 77 + nsprpub/lib/msgc/src/win32gc.c | 129 + nsprpub/lib/msgc/tests/.cvsignore | 1 + nsprpub/lib/msgc/tests/Makefile.in | 314 + nsprpub/lib/msgc/tests/gc1.c | 257 + nsprpub/lib/msgc/tests/thrashgc.c | 274 + nsprpub/lib/prstreams/.cvsignore | 1 + nsprpub/lib/prstreams/Makefile.in | 206 + nsprpub/lib/prstreams/plvrsion.c | 125 + nsprpub/lib/prstreams/prstrms.cpp | 550 ++ nsprpub/lib/prstreams/prstrms.h | 153 + nsprpub/lib/prstreams/prstrms.rc | 101 + .../lib/prstreams/tests/testprstrm/.cvsignore | 1 + .../prstreams/tests/testprstrm/Makefile.in | 254 + .../prstreams/tests/testprstrm/testprstrm.cpp | 204 + nsprpub/lib/tests/.cvsignore | 1 + nsprpub/lib/tests/Makefile.in | 262 + nsprpub/lib/tests/arena.c | 401 ++ nsprpub/lib/tests/base64t.c | 3047 ++++++++ nsprpub/lib/tests/getopt.c | 40 + nsprpub/lib/tests/string.c | 3116 ++++++++ nsprpub/pkg/Makefile.in | 61 + nsprpub/pkg/linux/Makefile.in | 111 + nsprpub/pkg/linux/sun-nspr.spec | 81 + nsprpub/pkg/solaris/Makefile-devl.com | 66 + nsprpub/pkg/solaris/Makefile-devl.targ | 66 + nsprpub/pkg/solaris/Makefile.com | 69 + nsprpub/pkg/solaris/Makefile.in | 121 + nsprpub/pkg/solaris/Makefile.targ | 64 + nsprpub/pkg/solaris/SUNWpr/Makefile.in | 58 + nsprpub/pkg/solaris/SUNWpr/depend | 64 + nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl | 70 + nsprpub/pkg/solaris/SUNWpr/prototype_com | 71 + nsprpub/pkg/solaris/SUNWpr/prototype_i386 | 77 + nsprpub/pkg/solaris/SUNWpr/prototype_sparc | 83 + nsprpub/pkg/solaris/SUNWprd/Makefile.in | 58 + nsprpub/pkg/solaris/SUNWprd/depend | 59 + nsprpub/pkg/solaris/SUNWprd/pkginfo.tmpl | 70 + nsprpub/pkg/solaris/SUNWprd/prototype | 115 + nsprpub/pkg/solaris/bld_awk_pkginfo.ksh | 141 + nsprpub/pkg/solaris/common_files/copyright | 38 + nsprpub/pkg/solaris/proto64.mk | 50 + nsprpub/pr/.cvsignore | 1 + nsprpub/pr/Makefile.in | 49 + nsprpub/pr/include/.cvsignore | 1 + nsprpub/pr/include/MANIFEST | 52 + nsprpub/pr/include/Makefile.in | 59 + nsprpub/pr/include/gencfg.c | 309 + nsprpub/pr/include/md/.cvsignore | 1 + nsprpub/pr/include/md/Makefile.in | 90 + nsprpub/pr/include/md/_aix.h | 254 + nsprpub/pr/include/md/_aix32.cfg | 147 + nsprpub/pr/include/md/_aix64.cfg | 148 + nsprpub/pr/include/md/_beos.cfg | 152 + nsprpub/pr/include/md/_beos.h | 613 ++ nsprpub/pr/include/md/_bsdi.cfg | 202 + nsprpub/pr/include/md/_bsdi.h | 214 + nsprpub/pr/include/md/_darwin.cfg | 147 + nsprpub/pr/include/md/_darwin.h | 287 + nsprpub/pr/include/md/_dgux.cfg | 140 + nsprpub/pr/include/md/_dgux.h | 221 + nsprpub/pr/include/md/_freebsd.cfg | 337 + nsprpub/pr/include/md/_freebsd.h | 278 + nsprpub/pr/include/md/_hpux.h | 297 + nsprpub/pr/include/md/_hpux32.cfg | 144 + nsprpub/pr/include/md/_hpux64.cfg | 145 + nsprpub/pr/include/md/_irix.h | 470 ++ nsprpub/pr/include/md/_irix32.cfg | 151 + nsprpub/pr/include/md/_irix64.cfg | 150 + nsprpub/pr/include/md/_linux.cfg | 718 ++ nsprpub/pr/include/md/_linux.h | 625 ++ nsprpub/pr/include/md/_macos.h | 725 ++ nsprpub/pr/include/md/_ncr.cfg | 140 + nsprpub/pr/include/md/_ncr.h | 230 + nsprpub/pr/include/md/_nec.cfg | 140 + nsprpub/pr/include/md/_nec.h | 196 + nsprpub/pr/include/md/_netbsd.cfg | 289 + nsprpub/pr/include/md/_netbsd.h | 265 + nsprpub/pr/include/md/_nextstep.cfg | 255 + nsprpub/pr/include/md/_nextstep.h | 299 + nsprpub/pr/include/md/_nspr_pthread.h | 283 + nsprpub/pr/include/md/_nto.cfg | 152 + nsprpub/pr/include/md/_nto.h | 221 + nsprpub/pr/include/md/_openbsd.cfg | 385 + nsprpub/pr/include/md/_openbsd.h | 242 + nsprpub/pr/include/md/_openvms.cfg | 148 + nsprpub/pr/include/md/_openvms.h | 333 + nsprpub/pr/include/md/_os2.cfg | 153 + nsprpub/pr/include/md/_os2.h | 587 ++ nsprpub/pr/include/md/_os2_errors.h | 162 + nsprpub/pr/include/md/_osf1.cfg | 148 + nsprpub/pr/include/md/_osf1.h | 255 + nsprpub/pr/include/md/_pcos.h | 89 + nsprpub/pr/include/md/_pth.h | 304 + nsprpub/pr/include/md/_qnx.cfg | 96 + nsprpub/pr/include/md/_qnx.h | 215 + nsprpub/pr/include/md/_reliantunix.cfg | 145 + nsprpub/pr/include/md/_reliantunix.h | 270 + nsprpub/pr/include/md/_riscos.cfg | 143 + nsprpub/pr/include/md/_riscos.h | 209 + nsprpub/pr/include/md/_scoos.cfg | 140 + nsprpub/pr/include/md/_scoos.h | 204 + nsprpub/pr/include/md/_solaris.cfg | 203 + nsprpub/pr/include/md/_solaris.h | 806 +++ nsprpub/pr/include/md/_sony.cfg | 140 + nsprpub/pr/include/md/_sony.h | 204 + nsprpub/pr/include/md/_sunos4.cfg | 138 + nsprpub/pr/include/md/_sunos4.h | 236 + nsprpub/pr/include/md/_unix_errors.h | 171 + nsprpub/pr/include/md/_unixos.h | 633 ++ nsprpub/pr/include/md/_unixware.cfg | 140 + nsprpub/pr/include/md/_unixware.h | 219 + nsprpub/pr/include/md/_unixware7.cfg | 144 + nsprpub/pr/include/md/_win16.cfg | 177 + nsprpub/pr/include/md/_win16.h | 568 ++ nsprpub/pr/include/md/_win32_errors.h | 154 + nsprpub/pr/include/md/_win95.cfg | 300 + nsprpub/pr/include/md/_win95.h | 562 ++ nsprpub/pr/include/md/_winnt.cfg | 300 + nsprpub/pr/include/md/_winnt.h | 623 ++ nsprpub/pr/include/md/prosdep.h | 169 + nsprpub/pr/include/md/sunos4.h | 164 + nsprpub/pr/include/nspr.h | 75 + nsprpub/pr/include/obsolete/.cvsignore | 1 + nsprpub/pr/include/obsolete/Makefile.in | 60 + nsprpub/pr/include/obsolete/pralarm.h | 194 + nsprpub/pr/include/obsolete/probslet.h | 185 + nsprpub/pr/include/obsolete/protypes.h | 252 + nsprpub/pr/include/obsolete/prsem.h | 96 + nsprpub/pr/include/pratom.h | 224 + nsprpub/pr/include/prbit.h | 136 + nsprpub/pr/include/prclist.h | 140 + nsprpub/pr/include/prcmon.h | 98 + nsprpub/pr/include/prcountr.h | 557 ++ nsprpub/pr/include/prcvar.h | 126 + nsprpub/pr/include/prdtoa.h | 90 + nsprpub/pr/include/prenv.h | 157 + nsprpub/pr/include/prerr.h | 281 + nsprpub/pr/include/prerror.h | 326 + nsprpub/pr/include/prinet.h | 122 + nsprpub/pr/include/prinit.h | 242 + nsprpub/pr/include/prinrval.h | 175 + nsprpub/pr/include/prio.h | 2030 ++++++ nsprpub/pr/include/pripcsem.h | 133 + nsprpub/pr/include/private/.cvsignore | 1 + nsprpub/pr/include/private/Makefile.in | 61 + nsprpub/pr/include/private/pprio.h | 271 + nsprpub/pr/include/private/pprmwait.h | 135 + nsprpub/pr/include/private/pprthred.h | 373 + nsprpub/pr/include/private/primpl.h | 2149 ++++++ nsprpub/pr/include/private/prpriv.h | 53 + nsprpub/pr/include/prlink.h | 260 + nsprpub/pr/include/prlock.h | 121 + nsprpub/pr/include/prlog.h | 264 + nsprpub/pr/include/prlong.h | 445 ++ nsprpub/pr/include/prmem.h | 158 + nsprpub/pr/include/prmon.h | 113 + nsprpub/pr/include/prmwait.h | 412 ++ nsprpub/pr/include/prnetdb.h | 499 ++ nsprpub/pr/include/prolock.h | 210 + nsprpub/pr/include/prpdce.h | 118 + nsprpub/pr/include/prprf.h | 154 + nsprpub/pr/include/prproces.h | 118 + nsprpub/pr/include/prrng.h | 107 + nsprpub/pr/include/prrwlock.h | 120 + nsprpub/pr/include/prshm.h | 289 + nsprpub/pr/include/prshma.h | 271 + nsprpub/pr/include/prsystem.h | 140 + nsprpub/pr/include/prthread.h | 286 + nsprpub/pr/include/prtime.h | 315 + nsprpub/pr/include/prtpool.h | 115 + nsprpub/pr/include/prtrace.h | 678 ++ nsprpub/pr/include/prtypes.h | 569 ++ nsprpub/pr/include/prvrsion.h | 137 + nsprpub/pr/include/prwin16.h | 196 + nsprpub/pr/src/.cvsignore | 2 + nsprpub/pr/src/Makefile.in | 424 ++ nsprpub/pr/src/bthreads/.cvsignore | 1 + nsprpub/pr/src/bthreads/Makefile.in | 63 + nsprpub/pr/src/bthreads/bsrcs.mk | 49 + nsprpub/pr/src/bthreads/btcvar.c | 276 + nsprpub/pr/src/bthreads/btlocks.c | 116 + nsprpub/pr/src/bthreads/btmisc.c | 104 + nsprpub/pr/src/bthreads/btmon.c | 219 + nsprpub/pr/src/bthreads/btsem.c | 130 + nsprpub/pr/src/bthreads/btthread.c | 694 ++ nsprpub/pr/src/bthreads/objs.mk | 43 + nsprpub/pr/src/cplus/.cvsignore | 1 + nsprpub/pr/src/cplus/Makefile.in | 75 + nsprpub/pr/src/cplus/rcascii.h | 175 + nsprpub/pr/src/cplus/rcbase.cpp | 55 + nsprpub/pr/src/cplus/rcbase.h | 83 + nsprpub/pr/src/cplus/rccv.cpp | 97 + nsprpub/pr/src/cplus/rccv.h | 96 + nsprpub/pr/src/cplus/rcfileio.cpp | 199 + nsprpub/pr/src/cplus/rcfileio.h | 161 + nsprpub/pr/src/cplus/rcinrval.cpp | 69 + nsprpub/pr/src/cplus/rcinrval.h | 169 + nsprpub/pr/src/cplus/rcio.cpp | 46 + nsprpub/pr/src/cplus/rcio.h | 148 + nsprpub/pr/src/cplus/rclock.cpp | 72 + nsprpub/pr/src/cplus/rclock.h | 98 + nsprpub/pr/src/cplus/rcmon.h | 79 + nsprpub/pr/src/cplus/rcnetdb.cpp | 232 + nsprpub/pr/src/cplus/rcnetdb.h | 129 + nsprpub/pr/src/cplus/rcnetio.cpp | 195 + nsprpub/pr/src/cplus/rcnetio.h | 126 + nsprpub/pr/src/cplus/rcthread.cpp | 220 + nsprpub/pr/src/cplus/rcthread.h | 227 + nsprpub/pr/src/cplus/rctime.cpp | 66 + nsprpub/pr/src/cplus/rctime.h | 138 + nsprpub/pr/src/cplus/tests/.cvsignore | 1 + nsprpub/pr/src/cplus/tests/Makefile.in | 288 + nsprpub/pr/src/cplus/tests/fileio.cpp | 65 + nsprpub/pr/src/cplus/tests/interval.cpp | 133 + nsprpub/pr/src/cplus/tests/ranfile.cpp | 432 ++ nsprpub/pr/src/cplus/tests/switch.cpp | 266 + nsprpub/pr/src/cplus/tests/thread.cpp | 140 + nsprpub/pr/src/cplus/tests/time.cpp | 61 + nsprpub/pr/src/cplus/tests/tpd.cpp | 368 + nsprpub/pr/src/io/.cvsignore | 1 + nsprpub/pr/src/io/Makefile.in | 97 + nsprpub/pr/src/io/prdir.c | 164 + nsprpub/pr/src/io/prfdcach.c | 324 + nsprpub/pr/src/io/prfile.c | 845 +++ nsprpub/pr/src/io/prio.c | 202 + nsprpub/pr/src/io/priometh.c | 628 ++ nsprpub/pr/src/io/pripv6.c | 396 + nsprpub/pr/src/io/prlayer.c | 768 ++ nsprpub/pr/src/io/prlog.c | 586 ++ nsprpub/pr/src/io/prmapopt.c | 517 ++ nsprpub/pr/src/io/prmmap.c | 93 + nsprpub/pr/src/io/prmwait.c | 1491 ++++ nsprpub/pr/src/io/prpolevt.c | 530 ++ nsprpub/pr/src/io/prprf.c | 1235 ++++ nsprpub/pr/src/io/prscanf.c | 669 ++ nsprpub/pr/src/io/prsocket.c | 1858 +++++ nsprpub/pr/src/io/prstdio.c | 106 + nsprpub/pr/src/linking/.cvsignore | 1 + nsprpub/pr/src/linking/Makefile.in | 75 + nsprpub/pr/src/linking/prlink.c | 1980 +++++ nsprpub/pr/src/malloc/.cvsignore | 1 + nsprpub/pr/src/malloc/Makefile.in | 67 + nsprpub/pr/src/malloc/prmalloc.c | 1174 +++ nsprpub/pr/src/malloc/prmem.c | 726 ++ nsprpub/pr/src/md/.cvsignore | 1 + nsprpub/pr/src/md/Makefile.in | 64 + nsprpub/pr/src/md/beos/.cvsignore | 1 + nsprpub/pr/src/md/beos/Makefile.in | 60 + nsprpub/pr/src/md/beos/bcpu.c | 55 + nsprpub/pr/src/md/beos/beos.c | 264 + nsprpub/pr/src/md/beos/beos_errors.c | 1526 ++++ nsprpub/pr/src/md/beos/bfile.c | 905 +++ nsprpub/pr/src/md/beos/bmemory.c | 42 + nsprpub/pr/src/md/beos/bmisc.c | 123 + nsprpub/pr/src/md/beos/bmmap.c | 73 + nsprpub/pr/src/md/beos/bnet.c | 929 +++ nsprpub/pr/src/md/beos/bproc.c | 244 + nsprpub/pr/src/md/beos/brng.c | 72 + nsprpub/pr/src/md/beos/bseg.c | 54 + nsprpub/pr/src/md/beos/bsrcs.mk | 54 + nsprpub/pr/src/md/beos/btime.c | 75 + nsprpub/pr/src/md/beos/objs.mk | 43 + nsprpub/pr/src/md/mac/MANIFEST | 7 + nsprpub/pr/src/md/mac/MacErrorHandling.h | 668 ++ nsprpub/pr/src/md/mac/macdll.c | 587 ++ nsprpub/pr/src/md/mac/macdll.h | 57 + nsprpub/pr/src/md/mac/macio.c | 1949 +++++ nsprpub/pr/src/md/mac/macio.h | 51 + nsprpub/pr/src/md/mac/macrng.c | 52 + nsprpub/pr/src/md/mac/macsocket.h | 238 + nsprpub/pr/src/md/mac/macsockotpt.c | 2321 ++++++ nsprpub/pr/src/md/mac/macthr.c | 721 ++ nsprpub/pr/src/md/mac/mactime.c | 253 + nsprpub/pr/src/md/mac/mactime.h | 51 + nsprpub/pr/src/md/mac/mdcriticalregion.c | 173 + nsprpub/pr/src/md/mac/mdcriticalregion.h | 59 + nsprpub/pr/src/md/mac/mdmac.c | 776 ++ nsprpub/pr/src/md/mac/mdmac.h | 51 + nsprpub/pr/src/md/mac/prcpucfg.h | 136 + nsprpub/pr/src/md/os2/.cvsignore | 1 + nsprpub/pr/src/md/os2/Makefile.in | 85 + nsprpub/pr/src/md/os2/objs.mk | 65 + nsprpub/pr/src/md/os2/os2_errors.c | 1129 +++ nsprpub/pr/src/md/os2/os2cv.c | 441 ++ nsprpub/pr/src/md/os2/os2emx.s | 114 + nsprpub/pr/src/md/os2/os2gc.c | 90 + nsprpub/pr/src/md/os2/os2inrval.c | 112 + nsprpub/pr/src/md/os2/os2io.c | 998 +++ nsprpub/pr/src/md/os2/os2misc.c | 588 ++ nsprpub/pr/src/md/os2/os2poll.c | 382 + nsprpub/pr/src/md/os2/os2rng.c | 110 + nsprpub/pr/src/md/os2/os2sem.c | 93 + nsprpub/pr/src/md/os2/os2sock.c | 684 ++ nsprpub/pr/src/md/os2/os2thred.c | 405 ++ nsprpub/pr/src/md/os2/os2vaclegacy.s | 78 + nsprpub/pr/src/md/os2/os2vacpp.asm | 266 + nsprpub/pr/src/md/prosdep.c | 115 + nsprpub/pr/src/md/unix/.cvsignore | 1 + nsprpub/pr/src/md/unix/Makefile.in | 135 + nsprpub/pr/src/md/unix/aix.c | 333 + nsprpub/pr/src/md/unix/aixwrap.c | 65 + nsprpub/pr/src/md/unix/bsdi.c | 119 + nsprpub/pr/src/md/unix/darwin.c | 110 + nsprpub/pr/src/md/unix/dgux.c | 109 + nsprpub/pr/src/md/unix/freebsd.c | 119 + nsprpub/pr/src/md/unix/hpux.c | 261 + nsprpub/pr/src/md/unix/irix.c | 1680 +++++ nsprpub/pr/src/md/unix/linux.c | 123 + nsprpub/pr/src/md/unix/ncr.c | 395 + nsprpub/pr/src/md/unix/nec.c | 100 + nsprpub/pr/src/md/unix/netbsd.c | 121 + nsprpub/pr/src/md/unix/nextstep.c | 284 + nsprpub/pr/src/md/unix/nto.c | 66 + nsprpub/pr/src/md/unix/objs.mk | 63 + nsprpub/pr/src/md/unix/openbsd.c | 121 + nsprpub/pr/src/md/unix/openvms.c | 286 + nsprpub/pr/src/md/unix/os_AIX.s | 123 + nsprpub/pr/src/md/unix/os_BSD_386_2.s | 74 + nsprpub/pr/src/md/unix/os_Darwin_ppc.s | 96 + nsprpub/pr/src/md/unix/os_Darwin_x86.s | 109 + nsprpub/pr/src/md/unix/os_HPUX.s | 58 + nsprpub/pr/src/md/unix/os_HPUX_ia64.s | 112 + nsprpub/pr/src/md/unix/os_Irix.s | 166 + nsprpub/pr/src/md/unix/os_Linux_ia64.s | 103 + nsprpub/pr/src/md/unix/os_Linux_ppc.s | 107 + nsprpub/pr/src/md/unix/os_Linux_x86.s | 117 + nsprpub/pr/src/md/unix/os_Linux_x86_64.s | 98 + nsprpub/pr/src/md/unix/os_ReliantUNIX.s | 128 + nsprpub/pr/src/md/unix/os_SunOS.s | 71 + nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s | 205 + nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s | 205 + nsprpub/pr/src/md/unix/os_SunOS_x86.s | 158 + nsprpub/pr/src/md/unix/os_SunOS_x86_64.s | 95 + nsprpub/pr/src/md/unix/osf1.c | 107 + nsprpub/pr/src/md/unix/pthreads_user.c | 480 ++ nsprpub/pr/src/md/unix/qnx.c | 102 + nsprpub/pr/src/md/unix/reliantunix.c | 133 + nsprpub/pr/src/md/unix/riscos.c | 120 + nsprpub/pr/src/md/unix/scoos.c | 181 + nsprpub/pr/src/md/unix/solaris.c | 889 +++ nsprpub/pr/src/md/unix/sony.c | 109 + nsprpub/pr/src/md/unix/sunos4.c | 96 + nsprpub/pr/src/md/unix/unix.c | 3734 ++++++++++ nsprpub/pr/src/md/unix/unix_errors.c | 877 +++ nsprpub/pr/src/md/unix/unixware.c | 583 ++ nsprpub/pr/src/md/unix/uxpoll.c | 708 ++ nsprpub/pr/src/md/unix/uxproces.c | 1000 +++ nsprpub/pr/src/md/unix/uxrng.c | 341 + nsprpub/pr/src/md/unix/uxshm.c | 659 ++ nsprpub/pr/src/md/unix/uxwrap.c | 548 ++ nsprpub/pr/src/md/windows/.cvsignore | 1 + nsprpub/pr/src/md/windows/Makefile.in | 121 + nsprpub/pr/src/md/windows/ntdllmn.c | 88 + nsprpub/pr/src/md/windows/ntgc.c | 130 + nsprpub/pr/src/md/windows/ntinrval.c | 60 + nsprpub/pr/src/md/windows/ntio.c | 4650 ++++++++++++ nsprpub/pr/src/md/windows/ntmisc.c | 867 +++ nsprpub/pr/src/md/windows/ntsec.c | 279 + nsprpub/pr/src/md/windows/ntsem.c | 84 + nsprpub/pr/src/md/windows/ntthread.c | 560 ++ nsprpub/pr/src/md/windows/objs.mk | 94 + nsprpub/pr/src/md/windows/w16callb.c | 262 + nsprpub/pr/src/md/windows/w16error.c | 252 + nsprpub/pr/src/md/windows/w16fmem.c | 85 + nsprpub/pr/src/md/windows/w16gc.c | 86 + nsprpub/pr/src/md/windows/w16io.c | 855 +++ nsprpub/pr/src/md/windows/w16mem.c | 84 + nsprpub/pr/src/md/windows/w16null.c | 116 + nsprpub/pr/src/md/windows/w16proc.c | 77 + nsprpub/pr/src/md/windows/w16sock.c | 1170 +++ nsprpub/pr/src/md/windows/w16stdio.c | 169 + nsprpub/pr/src/md/windows/w16thred.c | 426 ++ nsprpub/pr/src/md/windows/w32ipcsem.c | 227 + nsprpub/pr/src/md/windows/w32poll.c | 351 + nsprpub/pr/src/md/windows/w32rng.c | 107 + nsprpub/pr/src/md/windows/w32shm.c | 355 + nsprpub/pr/src/md/windows/w95cv.c | 347 + nsprpub/pr/src/md/windows/w95dllmain.c | 71 + nsprpub/pr/src/md/windows/w95io.c | 1568 ++++ nsprpub/pr/src/md/windows/w95sock.c | 771 ++ nsprpub/pr/src/md/windows/w95thred.c | 306 + nsprpub/pr/src/md/windows/win32_errors.c | 565 ++ nsprpub/pr/src/memory/.cvsignore | 1 + nsprpub/pr/src/memory/Makefile.in | 69 + nsprpub/pr/src/memory/prgcleak.c | 122 + nsprpub/pr/src/memory/prseg.c | 93 + nsprpub/pr/src/memory/prshm.c | 156 + nsprpub/pr/src/memory/prshma.c | 142 + nsprpub/pr/src/misc/.cvsignore | 1 + nsprpub/pr/src/misc/Makefile.in | 111 + nsprpub/pr/src/misc/compile-et.pl | 140 + nsprpub/pr/src/misc/pralarm.c | 282 + nsprpub/pr/src/misc/pratom.c | 411 ++ nsprpub/pr/src/misc/prcountr.c | 506 ++ nsprpub/pr/src/misc/prdtoa.c | 3516 +++++++++ nsprpub/pr/src/misc/prenv.c | 109 + nsprpub/pr/src/misc/prerr.c | 129 + nsprpub/pr/src/misc/prerr.et | 140 + nsprpub/pr/src/misc/prerr.properties | 117 + nsprpub/pr/src/misc/prerror.c | 107 + nsprpub/pr/src/misc/prerrortable.c | 240 + nsprpub/pr/src/misc/prinit.c | 873 +++ nsprpub/pr/src/misc/prinrval.c | 157 + nsprpub/pr/src/misc/pripc.c | 132 + nsprpub/pr/src/misc/pripcsem.c | 130 + nsprpub/pr/src/misc/prlog2.c | 81 + nsprpub/pr/src/misc/prlong.c | 282 + nsprpub/pr/src/misc/prnetdb.c | 2364 ++++++ nsprpub/pr/src/misc/prolock.c | 100 + nsprpub/pr/src/misc/prrng.c | 76 + nsprpub/pr/src/misc/prsystem.c | 366 + nsprpub/pr/src/misc/prthinfo.c | 247 + nsprpub/pr/src/misc/prtime.c | 2015 ++++++ nsprpub/pr/src/misc/prtpool.c | 1219 ++++ nsprpub/pr/src/misc/prtrace.c | 920 +++ nsprpub/pr/src/nspr.def | 471 ++ nsprpub/pr/src/nspr.rc | 101 + nsprpub/pr/src/nspr_symvec.opt | 503 ++ nsprpub/pr/src/os2extra.def | 16 + nsprpub/pr/src/prvrsion.c | 127 + nsprpub/pr/src/pthreads/.cvsignore | 1 + nsprpub/pr/src/pthreads/Makefile.in | 74 + nsprpub/pr/src/pthreads/ptio.c | 4905 +++++++++++++ nsprpub/pr/src/pthreads/ptmisc.c | 71 + nsprpub/pr/src/pthreads/ptsynch.c | 1139 +++ nsprpub/pr/src/pthreads/ptthread.c | 1653 +++++ nsprpub/pr/src/threads/.cvsignore | 1 + nsprpub/pr/src/threads/Makefile.in | 94 + nsprpub/pr/src/threads/combined/.cvsignore | 1 + nsprpub/pr/src/threads/combined/Makefile.in | 79 + nsprpub/pr/src/threads/combined/README | 62 + nsprpub/pr/src/threads/combined/prucpu.c | 440 ++ nsprpub/pr/src/threads/combined/prucv.c | 681 ++ nsprpub/pr/src/threads/combined/prulock.c | 463 ++ nsprpub/pr/src/threads/combined/prustack.c | 206 + nsprpub/pr/src/threads/combined/pruthr.c | 1918 +++++ nsprpub/pr/src/threads/prcmon.c | 463 ++ nsprpub/pr/src/threads/prcthr.c | 446 ++ nsprpub/pr/src/threads/prdump.c | 153 + nsprpub/pr/src/threads/prmon.c | 222 + nsprpub/pr/src/threads/prrwlock.c | 512 ++ nsprpub/pr/src/threads/prsem.c | 174 + nsprpub/pr/src/threads/prtpd.c | 280 + nsprpub/pr/tests/.cvsignore | 1 + nsprpub/pr/tests/Makefile.in | 573 ++ nsprpub/pr/tests/README.TXT | 407 ++ nsprpub/pr/tests/accept.c | 524 ++ nsprpub/pr/tests/acceptread.c | 272 + nsprpub/pr/tests/acceptreademu.c | 302 + nsprpub/pr/tests/addrstr.c | 114 + nsprpub/pr/tests/affinity.c | 124 + nsprpub/pr/tests/alarm.c | 569 ++ nsprpub/pr/tests/anonfm.c | 343 + nsprpub/pr/tests/append.c | 158 + nsprpub/pr/tests/atomic.c | 215 + nsprpub/pr/tests/attach.c | 392 + nsprpub/pr/tests/bigfile.c | 318 + nsprpub/pr/tests/bigfile2.c | 127 + nsprpub/pr/tests/bigfile3.c | 126 + nsprpub/pr/tests/bug1test.c | 257 + nsprpub/pr/tests/cleanup.c | 131 + nsprpub/pr/tests/cltsrv.c | 1224 ++++ nsprpub/pr/tests/concur.c | 193 + nsprpub/pr/tests/cvar.c | 334 + nsprpub/pr/tests/cvar2.c | 1008 +++ nsprpub/pr/tests/dbmalloc.c | 347 + nsprpub/pr/tests/dbmalloc1.c | 141 + nsprpub/pr/tests/dceemu.c | 132 + nsprpub/pr/tests/depend.c | 153 + nsprpub/pr/tests/dll/.cvsignore | 1 + nsprpub/pr/tests/dll/Makefile.in | 116 + nsprpub/pr/tests/dll/my.def | 58 + nsprpub/pr/tests/dll/mygetval.c | 58 + nsprpub/pr/tests/dll/mysetval.c | 45 + nsprpub/pr/tests/dlltest.c | 221 + nsprpub/pr/tests/dtoa.c | 217 + nsprpub/pr/tests/env.c | 222 + nsprpub/pr/tests/errcodes.c | 167 + nsprpub/pr/tests/errset.c | 186 + nsprpub/pr/tests/exit.c | 137 + nsprpub/pr/tests/fdcach.c | 259 + nsprpub/pr/tests/fileio.c | 250 + nsprpub/pr/tests/foreign.c | 414 ++ nsprpub/pr/tests/forktest.c | 346 + nsprpub/pr/tests/formattm.c | 59 + nsprpub/pr/tests/freeif.c | 75 + nsprpub/pr/tests/fsync.c | 155 + nsprpub/pr/tests/getai.c | 64 + nsprpub/pr/tests/gethost.c | 291 + nsprpub/pr/tests/getproto.c | 114 + nsprpub/pr/tests/i2l.c | 133 + nsprpub/pr/tests/initclk.c | 109 + nsprpub/pr/tests/inrval.c | 242 + nsprpub/pr/tests/instrumt.c | 507 ++ nsprpub/pr/tests/intrio.c | 169 + nsprpub/pr/tests/intrupt.c | 373 + nsprpub/pr/tests/io_timeout.c | 299 + nsprpub/pr/tests/io_timeoutk.c | 233 + nsprpub/pr/tests/io_timeoutu.c | 234 + nsprpub/pr/tests/ioconthr.c | 146 + nsprpub/pr/tests/ipv6.c | 248 + nsprpub/pr/tests/join.c | 264 + nsprpub/pr/tests/joinkk.c | 193 + nsprpub/pr/tests/joinku.c | 199 + nsprpub/pr/tests/joinuk.c | 195 + nsprpub/pr/tests/joinuu.c | 197 + nsprpub/pr/tests/layer.c | 466 ++ nsprpub/pr/tests/lazyinit.c | 139 + nsprpub/pr/tests/libfilename.c | 129 + nsprpub/pr/tests/lltest.c | 859 +++ nsprpub/pr/tests/lock.c | 547 ++ nsprpub/pr/tests/lockfile.c | 276 + nsprpub/pr/tests/logger.c | 167 + nsprpub/pr/tests/makedir.c | 99 + nsprpub/pr/tests/many_cv.c | 150 + nsprpub/pr/tests/mbcs.c | 187 + nsprpub/pr/tests/multiacc.c | 252 + nsprpub/pr/tests/multiwait.c | 725 ++ nsprpub/pr/tests/nameshm1.c | 599 ++ nsprpub/pr/tests/nbconn.c | 592 ++ nsprpub/pr/tests/nblayer.c | 707 ++ nsprpub/pr/tests/nonblock.c | 273 + nsprpub/pr/tests/ntioto.c | 318 + nsprpub/pr/tests/ntoh.c | 125 + nsprpub/pr/tests/obsints.c | 83 + nsprpub/pr/tests/op_2long.c | 117 + nsprpub/pr/tests/op_excl.c | 156 + nsprpub/pr/tests/op_filnf.c | 96 + nsprpub/pr/tests/op_filok.c | 110 + nsprpub/pr/tests/op_noacc.c | 94 + nsprpub/pr/tests/op_nofil.c | 99 + nsprpub/pr/tests/openfile.c | 145 + nsprpub/pr/tests/parent.c | 157 + nsprpub/pr/tests/peek.c | 392 + nsprpub/pr/tests/perf.c | 485 ++ nsprpub/pr/tests/pipeping.c | 190 + nsprpub/pr/tests/pipeping2.c | 192 + nsprpub/pr/tests/pipepong.c | 92 + nsprpub/pr/tests/pipepong2.c | 130 + nsprpub/pr/tests/pipeself.c | 260 + nsprpub/pr/tests/poll_er.c | 244 + nsprpub/pr/tests/poll_nm.c | 399 ++ nsprpub/pr/tests/poll_to.c | 216 + nsprpub/pr/tests/pollable.c | 293 + nsprpub/pr/tests/prftest.c | 97 + nsprpub/pr/tests/prftest1.c | 152 + nsprpub/pr/tests/prftest2.c | 129 + nsprpub/pr/tests/primblok.c | 148 + nsprpub/pr/tests/priotest.c | 233 + nsprpub/pr/tests/provider.c | 1443 ++++ nsprpub/pr/tests/prpoll.c | 378 + nsprpub/pr/tests/prpollml.c | 168 + nsprpub/pr/tests/prselect.c | 372 + nsprpub/pr/tests/prttools.h | 43 + nsprpub/pr/tests/randseed.c | 163 + nsprpub/pr/tests/ranfile.c | 433 ++ nsprpub/pr/tests/rmdir.c | 127 + nsprpub/pr/tests/runtests.sh | 298 + nsprpub/pr/tests/runy2ktests.ksh | 269 + nsprpub/pr/tests/rwlocktest.c | 241 + nsprpub/pr/tests/sel_spd.c | 567 ++ nsprpub/pr/tests/selct_er.c | 234 + nsprpub/pr/tests/selct_nm.c | 320 + nsprpub/pr/tests/selct_to.c | 208 + nsprpub/pr/tests/select2.c | 354 + nsprpub/pr/tests/selintr.c | 81 + nsprpub/pr/tests/sem.c | 253 + nsprpub/pr/tests/sema.c | 180 + nsprpub/pr/tests/semaerr.c | 142 + nsprpub/pr/tests/semaerr1.c | 137 + nsprpub/pr/tests/semaping.c | 203 + nsprpub/pr/tests/semapong.c | 147 + nsprpub/pr/tests/sendzlf.c | 246 + nsprpub/pr/tests/server_test.c | 635 ++ nsprpub/pr/tests/servr_kk.c | 614 ++ nsprpub/pr/tests/servr_ku.c | 594 ++ nsprpub/pr/tests/servr_uk.c | 596 ++ nsprpub/pr/tests/servr_uu.c | 594 ++ nsprpub/pr/tests/short_thread.c | 90 + nsprpub/pr/tests/sigpipe.c | 131 + nsprpub/pr/tests/sleep.c | 134 + nsprpub/pr/tests/socket.c | 2354 ++++++ nsprpub/pr/tests/sockopt.c | 213 + nsprpub/pr/tests/sockping.c | 164 + nsprpub/pr/tests/sockpong.c | 115 + nsprpub/pr/tests/sprintf.c | 454 ++ nsprpub/pr/tests/sproc_ch.c | 119 + nsprpub/pr/tests/sproc_p.c | 101 + nsprpub/pr/tests/stack.c | 310 + nsprpub/pr/tests/stat.c | 119 + nsprpub/pr/tests/stdio.c | 83 + nsprpub/pr/tests/str2addr.c | 82 + nsprpub/pr/tests/strod.c | 106 + nsprpub/pr/tests/suspend.c | 231 + nsprpub/pr/tests/switch.c | 274 + nsprpub/pr/tests/system.c | 84 + nsprpub/pr/tests/testbit.c | 129 + nsprpub/pr/tests/testfile.c | 1011 +++ nsprpub/pr/tests/threads.c | 249 + nsprpub/pr/tests/thrpool_client.c | 392 + nsprpub/pr/tests/thrpool_server.c | 607 ++ nsprpub/pr/tests/thruput.c | 412 ++ nsprpub/pr/tests/time.c | 201 + nsprpub/pr/tests/timemac.c | 153 + nsprpub/pr/tests/timetest.c | 792 ++ nsprpub/pr/tests/tmoacc.c | 333 + nsprpub/pr/tests/tmocon.c | 404 ++ nsprpub/pr/tests/tpd.c | 334 + nsprpub/pr/tests/udpsrv.c | 566 ++ nsprpub/pr/tests/ut_ttools.h | 43 + nsprpub/pr/tests/vercheck.c | 111 + nsprpub/pr/tests/version.c | 123 + nsprpub/pr/tests/writev.c | 234 + nsprpub/pr/tests/xnotify.c | 389 + nsprpub/pr/tests/y2k.c | 840 +++ nsprpub/pr/tests/y2ktmo.c | 546 ++ nsprpub/pr/tests/yield.c | 88 + nsprpub/pr/tests/zerolen.c | 282 + nsprpub/tools/.cvsignore | 1 + nsprpub/tools/Makefile.in | 249 + nsprpub/tools/httpget.c | 466 ++ nsprpub/tools/tail.c | 166 + 714 files changed, 226137 insertions(+) create mode 100644 nsprpub/.cvsignore create mode 100644 nsprpub/Makefile.in create mode 100644 nsprpub/admin/explode.pl create mode 100644 nsprpub/admin/makeTargetDirs.sh create mode 100755 nsprpub/admin/repackage.sh create mode 100644 nsprpub/admin/symlinks.sh create mode 100755 nsprpub/build/autoconf/config.guess create mode 100755 nsprpub/build/autoconf/config.sub create mode 100755 nsprpub/build/autoconf/install-sh create mode 100755 nsprpub/build/cygwin-wrapper create mode 100644 nsprpub/config/.cvsignore create mode 100644 nsprpub/config/Makefile.in create mode 100644 nsprpub/config/autoconf.mk.in create mode 100644 nsprpub/config/config.mk create mode 100644 nsprpub/config/gcc_hidden.h create mode 100644 nsprpub/config/libc_r.h create mode 100644 nsprpub/config/make-system-wrappers.pl create mode 100644 nsprpub/config/nfspwd.pl create mode 100644 nsprpub/config/now.c create mode 100644 nsprpub/config/nsinstall.c create mode 100755 nsprpub/config/nspr-config.in create mode 100644 nsprpub/config/nspr.m4 create mode 100644 nsprpub/config/nsprincl.mk.in create mode 100644 nsprpub/config/nsprincl.sh.in create mode 100644 nsprpub/config/pathsub.h create mode 100644 nsprpub/config/prdepend.h create mode 100644 nsprpub/config/rules.mk create mode 100644 nsprpub/config/system-headers create mode 100755 nsprpub/configure create mode 100644 nsprpub/configure.in create mode 100644 nsprpub/lib/.cvsignore create mode 100644 nsprpub/lib/Makefile.in create mode 100644 nsprpub/lib/ds/.cvsignore create mode 100644 nsprpub/lib/ds/MANIFEST create mode 100644 nsprpub/lib/ds/Makefile.in create mode 100644 nsprpub/lib/ds/plarena.c create mode 100644 nsprpub/lib/ds/plarena.h create mode 100644 nsprpub/lib/ds/plarenas.h create mode 100644 nsprpub/lib/ds/plds.def create mode 100644 nsprpub/lib/ds/plds.rc create mode 100644 nsprpub/lib/ds/plds_symvec.opt create mode 100644 nsprpub/lib/ds/plhash.c create mode 100644 nsprpub/lib/ds/plhash.h create mode 100644 nsprpub/lib/ds/plvrsion.c create mode 100644 nsprpub/lib/libc/.cvsignore create mode 100644 nsprpub/lib/libc/Makefile.in create mode 100644 nsprpub/lib/libc/README create mode 100644 nsprpub/lib/libc/include/.cvsignore create mode 100644 nsprpub/lib/libc/include/MANIFEST create mode 100644 nsprpub/lib/libc/include/Makefile.in create mode 100644 nsprpub/lib/libc/include/README create mode 100644 nsprpub/lib/libc/include/plbase64.h create mode 100644 nsprpub/lib/libc/include/plerror.h create mode 100644 nsprpub/lib/libc/include/plgetopt.h create mode 100644 nsprpub/lib/libc/include/plresolv.h create mode 100644 nsprpub/lib/libc/include/plstr.h create mode 100644 nsprpub/lib/libc/src/.cvsignore create mode 100644 nsprpub/lib/libc/src/Makefile.in create mode 100644 nsprpub/lib/libc/src/README create mode 100644 nsprpub/lib/libc/src/base64.c create mode 100644 nsprpub/lib/libc/src/plc.def create mode 100644 nsprpub/lib/libc/src/plc.rc create mode 100644 nsprpub/lib/libc/src/plc_symvec.opt create mode 100644 nsprpub/lib/libc/src/plerror.c create mode 100644 nsprpub/lib/libc/src/plgetopt.c create mode 100644 nsprpub/lib/libc/src/plvrsion.c create mode 100644 nsprpub/lib/libc/src/strcat.c create mode 100644 nsprpub/lib/libc/src/strccmp.c create mode 100644 nsprpub/lib/libc/src/strchr.c create mode 100644 nsprpub/lib/libc/src/strcmp.c create mode 100644 nsprpub/lib/libc/src/strcpy.c create mode 100644 nsprpub/lib/libc/src/strcstr.c create mode 100644 nsprpub/lib/libc/src/strdup.c create mode 100644 nsprpub/lib/libc/src/strlen.c create mode 100644 nsprpub/lib/libc/src/strpbrk.c create mode 100644 nsprpub/lib/libc/src/strstr.c create mode 100644 nsprpub/lib/libc/src/strtok.c create mode 100644 nsprpub/lib/msgc/.cvsignore create mode 100644 nsprpub/lib/msgc/Makefile.in create mode 100644 nsprpub/lib/msgc/include/.cvsignore create mode 100644 nsprpub/lib/msgc/include/MANIFEST create mode 100644 nsprpub/lib/msgc/include/Makefile.in create mode 100644 nsprpub/lib/msgc/include/gcint.h create mode 100644 nsprpub/lib/msgc/include/prgc.h create mode 100644 nsprpub/lib/msgc/src/.cvsignore create mode 100644 nsprpub/lib/msgc/src/Makefile.in create mode 100644 nsprpub/lib/msgc/src/macgc.c create mode 100644 nsprpub/lib/msgc/src/os2gc.c create mode 100644 nsprpub/lib/msgc/src/prgcapi.c create mode 100644 nsprpub/lib/msgc/src/prmsgc.c create mode 100644 nsprpub/lib/msgc/src/unixgc.c create mode 100644 nsprpub/lib/msgc/src/win16gc.c create mode 100644 nsprpub/lib/msgc/src/win32gc.c create mode 100644 nsprpub/lib/msgc/tests/.cvsignore create mode 100644 nsprpub/lib/msgc/tests/Makefile.in create mode 100644 nsprpub/lib/msgc/tests/gc1.c create mode 100644 nsprpub/lib/msgc/tests/thrashgc.c create mode 100644 nsprpub/lib/prstreams/.cvsignore create mode 100644 nsprpub/lib/prstreams/Makefile.in create mode 100644 nsprpub/lib/prstreams/plvrsion.c create mode 100644 nsprpub/lib/prstreams/prstrms.cpp create mode 100644 nsprpub/lib/prstreams/prstrms.h create mode 100644 nsprpub/lib/prstreams/prstrms.rc create mode 100644 nsprpub/lib/prstreams/tests/testprstrm/.cvsignore create mode 100644 nsprpub/lib/prstreams/tests/testprstrm/Makefile.in create mode 100644 nsprpub/lib/prstreams/tests/testprstrm/testprstrm.cpp create mode 100644 nsprpub/lib/tests/.cvsignore create mode 100644 nsprpub/lib/tests/Makefile.in create mode 100644 nsprpub/lib/tests/arena.c create mode 100644 nsprpub/lib/tests/base64t.c create mode 100644 nsprpub/lib/tests/getopt.c create mode 100644 nsprpub/lib/tests/string.c create mode 100644 nsprpub/pkg/Makefile.in create mode 100644 nsprpub/pkg/linux/Makefile.in create mode 100644 nsprpub/pkg/linux/sun-nspr.spec create mode 100755 nsprpub/pkg/solaris/Makefile-devl.com create mode 100755 nsprpub/pkg/solaris/Makefile-devl.targ create mode 100644 nsprpub/pkg/solaris/Makefile.com create mode 100644 nsprpub/pkg/solaris/Makefile.in create mode 100644 nsprpub/pkg/solaris/Makefile.targ create mode 100644 nsprpub/pkg/solaris/SUNWpr/Makefile.in create mode 100644 nsprpub/pkg/solaris/SUNWpr/depend create mode 100644 nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl create mode 100644 nsprpub/pkg/solaris/SUNWpr/prototype_com create mode 100644 nsprpub/pkg/solaris/SUNWpr/prototype_i386 create mode 100644 nsprpub/pkg/solaris/SUNWpr/prototype_sparc create mode 100755 nsprpub/pkg/solaris/SUNWprd/Makefile.in create mode 100755 nsprpub/pkg/solaris/SUNWprd/depend create mode 100755 nsprpub/pkg/solaris/SUNWprd/pkginfo.tmpl create mode 100755 nsprpub/pkg/solaris/SUNWprd/prototype create mode 100644 nsprpub/pkg/solaris/bld_awk_pkginfo.ksh create mode 100644 nsprpub/pkg/solaris/common_files/copyright create mode 100644 nsprpub/pkg/solaris/proto64.mk create mode 100644 nsprpub/pr/.cvsignore create mode 100644 nsprpub/pr/Makefile.in create mode 100644 nsprpub/pr/include/.cvsignore create mode 100644 nsprpub/pr/include/MANIFEST create mode 100644 nsprpub/pr/include/Makefile.in create mode 100644 nsprpub/pr/include/gencfg.c create mode 100644 nsprpub/pr/include/md/.cvsignore create mode 100644 nsprpub/pr/include/md/Makefile.in create mode 100644 nsprpub/pr/include/md/_aix.h create mode 100644 nsprpub/pr/include/md/_aix32.cfg create mode 100644 nsprpub/pr/include/md/_aix64.cfg create mode 100644 nsprpub/pr/include/md/_beos.cfg create mode 100644 nsprpub/pr/include/md/_beos.h create mode 100644 nsprpub/pr/include/md/_bsdi.cfg create mode 100644 nsprpub/pr/include/md/_bsdi.h create mode 100644 nsprpub/pr/include/md/_darwin.cfg create mode 100644 nsprpub/pr/include/md/_darwin.h create mode 100644 nsprpub/pr/include/md/_dgux.cfg create mode 100644 nsprpub/pr/include/md/_dgux.h create mode 100644 nsprpub/pr/include/md/_freebsd.cfg create mode 100644 nsprpub/pr/include/md/_freebsd.h create mode 100644 nsprpub/pr/include/md/_hpux.h create mode 100644 nsprpub/pr/include/md/_hpux32.cfg create mode 100644 nsprpub/pr/include/md/_hpux64.cfg create mode 100644 nsprpub/pr/include/md/_irix.h create mode 100644 nsprpub/pr/include/md/_irix32.cfg create mode 100644 nsprpub/pr/include/md/_irix64.cfg create mode 100644 nsprpub/pr/include/md/_linux.cfg create mode 100644 nsprpub/pr/include/md/_linux.h create mode 100644 nsprpub/pr/include/md/_macos.h create mode 100644 nsprpub/pr/include/md/_ncr.cfg create mode 100644 nsprpub/pr/include/md/_ncr.h create mode 100644 nsprpub/pr/include/md/_nec.cfg create mode 100644 nsprpub/pr/include/md/_nec.h create mode 100644 nsprpub/pr/include/md/_netbsd.cfg create mode 100644 nsprpub/pr/include/md/_netbsd.h create mode 100644 nsprpub/pr/include/md/_nextstep.cfg create mode 100644 nsprpub/pr/include/md/_nextstep.h create mode 100644 nsprpub/pr/include/md/_nspr_pthread.h create mode 100644 nsprpub/pr/include/md/_nto.cfg create mode 100644 nsprpub/pr/include/md/_nto.h create mode 100644 nsprpub/pr/include/md/_openbsd.cfg create mode 100644 nsprpub/pr/include/md/_openbsd.h create mode 100644 nsprpub/pr/include/md/_openvms.cfg create mode 100644 nsprpub/pr/include/md/_openvms.h create mode 100644 nsprpub/pr/include/md/_os2.cfg create mode 100644 nsprpub/pr/include/md/_os2.h create mode 100644 nsprpub/pr/include/md/_os2_errors.h create mode 100644 nsprpub/pr/include/md/_osf1.cfg create mode 100644 nsprpub/pr/include/md/_osf1.h create mode 100644 nsprpub/pr/include/md/_pcos.h create mode 100644 nsprpub/pr/include/md/_pth.h create mode 100644 nsprpub/pr/include/md/_qnx.cfg create mode 100644 nsprpub/pr/include/md/_qnx.h create mode 100644 nsprpub/pr/include/md/_reliantunix.cfg create mode 100644 nsprpub/pr/include/md/_reliantunix.h create mode 100644 nsprpub/pr/include/md/_riscos.cfg create mode 100644 nsprpub/pr/include/md/_riscos.h create mode 100644 nsprpub/pr/include/md/_scoos.cfg create mode 100644 nsprpub/pr/include/md/_scoos.h create mode 100644 nsprpub/pr/include/md/_solaris.cfg create mode 100644 nsprpub/pr/include/md/_solaris.h create mode 100644 nsprpub/pr/include/md/_sony.cfg create mode 100644 nsprpub/pr/include/md/_sony.h create mode 100644 nsprpub/pr/include/md/_sunos4.cfg create mode 100644 nsprpub/pr/include/md/_sunos4.h create mode 100644 nsprpub/pr/include/md/_unix_errors.h create mode 100644 nsprpub/pr/include/md/_unixos.h create mode 100644 nsprpub/pr/include/md/_unixware.cfg create mode 100644 nsprpub/pr/include/md/_unixware.h create mode 100644 nsprpub/pr/include/md/_unixware7.cfg create mode 100644 nsprpub/pr/include/md/_win16.cfg create mode 100644 nsprpub/pr/include/md/_win16.h create mode 100644 nsprpub/pr/include/md/_win32_errors.h create mode 100644 nsprpub/pr/include/md/_win95.cfg create mode 100644 nsprpub/pr/include/md/_win95.h create mode 100644 nsprpub/pr/include/md/_winnt.cfg create mode 100644 nsprpub/pr/include/md/_winnt.h create mode 100644 nsprpub/pr/include/md/prosdep.h create mode 100644 nsprpub/pr/include/md/sunos4.h create mode 100644 nsprpub/pr/include/nspr.h create mode 100644 nsprpub/pr/include/obsolete/.cvsignore create mode 100644 nsprpub/pr/include/obsolete/Makefile.in create mode 100644 nsprpub/pr/include/obsolete/pralarm.h create mode 100644 nsprpub/pr/include/obsolete/probslet.h create mode 100644 nsprpub/pr/include/obsolete/protypes.h create mode 100644 nsprpub/pr/include/obsolete/prsem.h create mode 100644 nsprpub/pr/include/pratom.h create mode 100644 nsprpub/pr/include/prbit.h create mode 100644 nsprpub/pr/include/prclist.h create mode 100644 nsprpub/pr/include/prcmon.h create mode 100644 nsprpub/pr/include/prcountr.h create mode 100644 nsprpub/pr/include/prcvar.h create mode 100644 nsprpub/pr/include/prdtoa.h create mode 100644 nsprpub/pr/include/prenv.h create mode 100644 nsprpub/pr/include/prerr.h create mode 100644 nsprpub/pr/include/prerror.h create mode 100644 nsprpub/pr/include/prinet.h create mode 100644 nsprpub/pr/include/prinit.h create mode 100644 nsprpub/pr/include/prinrval.h create mode 100644 nsprpub/pr/include/prio.h create mode 100644 nsprpub/pr/include/pripcsem.h create mode 100644 nsprpub/pr/include/private/.cvsignore create mode 100644 nsprpub/pr/include/private/Makefile.in create mode 100644 nsprpub/pr/include/private/pprio.h create mode 100644 nsprpub/pr/include/private/pprmwait.h create mode 100644 nsprpub/pr/include/private/pprthred.h create mode 100644 nsprpub/pr/include/private/primpl.h create mode 100644 nsprpub/pr/include/private/prpriv.h create mode 100644 nsprpub/pr/include/prlink.h create mode 100644 nsprpub/pr/include/prlock.h create mode 100644 nsprpub/pr/include/prlog.h create mode 100644 nsprpub/pr/include/prlong.h create mode 100644 nsprpub/pr/include/prmem.h create mode 100644 nsprpub/pr/include/prmon.h create mode 100644 nsprpub/pr/include/prmwait.h create mode 100644 nsprpub/pr/include/prnetdb.h create mode 100644 nsprpub/pr/include/prolock.h create mode 100644 nsprpub/pr/include/prpdce.h create mode 100644 nsprpub/pr/include/prprf.h create mode 100644 nsprpub/pr/include/prproces.h create mode 100644 nsprpub/pr/include/prrng.h create mode 100644 nsprpub/pr/include/prrwlock.h create mode 100644 nsprpub/pr/include/prshm.h create mode 100644 nsprpub/pr/include/prshma.h create mode 100644 nsprpub/pr/include/prsystem.h create mode 100644 nsprpub/pr/include/prthread.h create mode 100644 nsprpub/pr/include/prtime.h create mode 100644 nsprpub/pr/include/prtpool.h create mode 100644 nsprpub/pr/include/prtrace.h create mode 100644 nsprpub/pr/include/prtypes.h create mode 100755 nsprpub/pr/include/prvrsion.h create mode 100644 nsprpub/pr/include/prwin16.h create mode 100644 nsprpub/pr/src/.cvsignore create mode 100644 nsprpub/pr/src/Makefile.in create mode 100644 nsprpub/pr/src/bthreads/.cvsignore create mode 100644 nsprpub/pr/src/bthreads/Makefile.in create mode 100644 nsprpub/pr/src/bthreads/bsrcs.mk create mode 100644 nsprpub/pr/src/bthreads/btcvar.c create mode 100644 nsprpub/pr/src/bthreads/btlocks.c create mode 100644 nsprpub/pr/src/bthreads/btmisc.c create mode 100644 nsprpub/pr/src/bthreads/btmon.c create mode 100644 nsprpub/pr/src/bthreads/btsem.c create mode 100644 nsprpub/pr/src/bthreads/btthread.c create mode 100644 nsprpub/pr/src/bthreads/objs.mk create mode 100644 nsprpub/pr/src/cplus/.cvsignore create mode 100644 nsprpub/pr/src/cplus/Makefile.in create mode 100644 nsprpub/pr/src/cplus/rcascii.h create mode 100644 nsprpub/pr/src/cplus/rcbase.cpp create mode 100644 nsprpub/pr/src/cplus/rcbase.h create mode 100644 nsprpub/pr/src/cplus/rccv.cpp create mode 100644 nsprpub/pr/src/cplus/rccv.h create mode 100644 nsprpub/pr/src/cplus/rcfileio.cpp create mode 100644 nsprpub/pr/src/cplus/rcfileio.h create mode 100644 nsprpub/pr/src/cplus/rcinrval.cpp create mode 100644 nsprpub/pr/src/cplus/rcinrval.h create mode 100644 nsprpub/pr/src/cplus/rcio.cpp create mode 100644 nsprpub/pr/src/cplus/rcio.h create mode 100644 nsprpub/pr/src/cplus/rclock.cpp create mode 100644 nsprpub/pr/src/cplus/rclock.h create mode 100644 nsprpub/pr/src/cplus/rcmon.h create mode 100644 nsprpub/pr/src/cplus/rcnetdb.cpp create mode 100644 nsprpub/pr/src/cplus/rcnetdb.h create mode 100644 nsprpub/pr/src/cplus/rcnetio.cpp create mode 100644 nsprpub/pr/src/cplus/rcnetio.h create mode 100755 nsprpub/pr/src/cplus/rcthread.cpp create mode 100644 nsprpub/pr/src/cplus/rcthread.h create mode 100644 nsprpub/pr/src/cplus/rctime.cpp create mode 100644 nsprpub/pr/src/cplus/rctime.h create mode 100644 nsprpub/pr/src/cplus/tests/.cvsignore create mode 100644 nsprpub/pr/src/cplus/tests/Makefile.in create mode 100644 nsprpub/pr/src/cplus/tests/fileio.cpp create mode 100644 nsprpub/pr/src/cplus/tests/interval.cpp create mode 100644 nsprpub/pr/src/cplus/tests/ranfile.cpp create mode 100644 nsprpub/pr/src/cplus/tests/switch.cpp create mode 100644 nsprpub/pr/src/cplus/tests/thread.cpp create mode 100644 nsprpub/pr/src/cplus/tests/time.cpp create mode 100644 nsprpub/pr/src/cplus/tests/tpd.cpp create mode 100644 nsprpub/pr/src/io/.cvsignore create mode 100644 nsprpub/pr/src/io/Makefile.in create mode 100644 nsprpub/pr/src/io/prdir.c create mode 100644 nsprpub/pr/src/io/prfdcach.c create mode 100644 nsprpub/pr/src/io/prfile.c create mode 100644 nsprpub/pr/src/io/prio.c create mode 100644 nsprpub/pr/src/io/priometh.c create mode 100644 nsprpub/pr/src/io/pripv6.c create mode 100644 nsprpub/pr/src/io/prlayer.c create mode 100644 nsprpub/pr/src/io/prlog.c create mode 100644 nsprpub/pr/src/io/prmapopt.c create mode 100644 nsprpub/pr/src/io/prmmap.c create mode 100644 nsprpub/pr/src/io/prmwait.c create mode 100644 nsprpub/pr/src/io/prpolevt.c create mode 100644 nsprpub/pr/src/io/prprf.c create mode 100644 nsprpub/pr/src/io/prscanf.c create mode 100644 nsprpub/pr/src/io/prsocket.c create mode 100644 nsprpub/pr/src/io/prstdio.c create mode 100644 nsprpub/pr/src/linking/.cvsignore create mode 100644 nsprpub/pr/src/linking/Makefile.in create mode 100644 nsprpub/pr/src/linking/prlink.c create mode 100644 nsprpub/pr/src/malloc/.cvsignore create mode 100644 nsprpub/pr/src/malloc/Makefile.in create mode 100644 nsprpub/pr/src/malloc/prmalloc.c create mode 100644 nsprpub/pr/src/malloc/prmem.c create mode 100644 nsprpub/pr/src/md/.cvsignore create mode 100644 nsprpub/pr/src/md/Makefile.in create mode 100644 nsprpub/pr/src/md/beos/.cvsignore create mode 100644 nsprpub/pr/src/md/beos/Makefile.in create mode 100644 nsprpub/pr/src/md/beos/bcpu.c create mode 100644 nsprpub/pr/src/md/beos/beos.c create mode 100644 nsprpub/pr/src/md/beos/beos_errors.c create mode 100644 nsprpub/pr/src/md/beos/bfile.c create mode 100644 nsprpub/pr/src/md/beos/bmemory.c create mode 100644 nsprpub/pr/src/md/beos/bmisc.c create mode 100644 nsprpub/pr/src/md/beos/bmmap.c create mode 100644 nsprpub/pr/src/md/beos/bnet.c create mode 100644 nsprpub/pr/src/md/beos/bproc.c create mode 100644 nsprpub/pr/src/md/beos/brng.c create mode 100644 nsprpub/pr/src/md/beos/bseg.c create mode 100644 nsprpub/pr/src/md/beos/bsrcs.mk create mode 100644 nsprpub/pr/src/md/beos/btime.c create mode 100644 nsprpub/pr/src/md/beos/objs.mk create mode 100644 nsprpub/pr/src/md/mac/MANIFEST create mode 100644 nsprpub/pr/src/md/mac/MacErrorHandling.h create mode 100644 nsprpub/pr/src/md/mac/macdll.c create mode 100644 nsprpub/pr/src/md/mac/macdll.h create mode 100644 nsprpub/pr/src/md/mac/macio.c create mode 100644 nsprpub/pr/src/md/mac/macio.h create mode 100644 nsprpub/pr/src/md/mac/macrng.c create mode 100644 nsprpub/pr/src/md/mac/macsocket.h create mode 100644 nsprpub/pr/src/md/mac/macsockotpt.c create mode 100644 nsprpub/pr/src/md/mac/macthr.c create mode 100644 nsprpub/pr/src/md/mac/mactime.c create mode 100644 nsprpub/pr/src/md/mac/mactime.h create mode 100644 nsprpub/pr/src/md/mac/mdcriticalregion.c create mode 100644 nsprpub/pr/src/md/mac/mdcriticalregion.h create mode 100644 nsprpub/pr/src/md/mac/mdmac.c create mode 100644 nsprpub/pr/src/md/mac/mdmac.h create mode 100644 nsprpub/pr/src/md/mac/prcpucfg.h create mode 100644 nsprpub/pr/src/md/os2/.cvsignore create mode 100644 nsprpub/pr/src/md/os2/Makefile.in create mode 100644 nsprpub/pr/src/md/os2/objs.mk create mode 100644 nsprpub/pr/src/md/os2/os2_errors.c create mode 100644 nsprpub/pr/src/md/os2/os2cv.c create mode 100644 nsprpub/pr/src/md/os2/os2emx.s create mode 100644 nsprpub/pr/src/md/os2/os2gc.c create mode 100644 nsprpub/pr/src/md/os2/os2inrval.c create mode 100644 nsprpub/pr/src/md/os2/os2io.c create mode 100644 nsprpub/pr/src/md/os2/os2misc.c create mode 100644 nsprpub/pr/src/md/os2/os2poll.c create mode 100644 nsprpub/pr/src/md/os2/os2rng.c create mode 100644 nsprpub/pr/src/md/os2/os2sem.c create mode 100644 nsprpub/pr/src/md/os2/os2sock.c create mode 100644 nsprpub/pr/src/md/os2/os2thred.c create mode 100644 nsprpub/pr/src/md/os2/os2vaclegacy.s create mode 100644 nsprpub/pr/src/md/os2/os2vacpp.asm create mode 100644 nsprpub/pr/src/md/prosdep.c create mode 100644 nsprpub/pr/src/md/unix/.cvsignore create mode 100644 nsprpub/pr/src/md/unix/Makefile.in create mode 100644 nsprpub/pr/src/md/unix/aix.c create mode 100644 nsprpub/pr/src/md/unix/aixwrap.c create mode 100644 nsprpub/pr/src/md/unix/bsdi.c create mode 100644 nsprpub/pr/src/md/unix/darwin.c create mode 100644 nsprpub/pr/src/md/unix/dgux.c create mode 100644 nsprpub/pr/src/md/unix/freebsd.c create mode 100644 nsprpub/pr/src/md/unix/hpux.c create mode 100644 nsprpub/pr/src/md/unix/irix.c create mode 100644 nsprpub/pr/src/md/unix/linux.c create mode 100644 nsprpub/pr/src/md/unix/ncr.c create mode 100644 nsprpub/pr/src/md/unix/nec.c create mode 100644 nsprpub/pr/src/md/unix/netbsd.c create mode 100644 nsprpub/pr/src/md/unix/nextstep.c create mode 100644 nsprpub/pr/src/md/unix/nto.c create mode 100644 nsprpub/pr/src/md/unix/objs.mk create mode 100644 nsprpub/pr/src/md/unix/openbsd.c create mode 100644 nsprpub/pr/src/md/unix/openvms.c create mode 100644 nsprpub/pr/src/md/unix/os_AIX.s create mode 100644 nsprpub/pr/src/md/unix/os_BSD_386_2.s create mode 100644 nsprpub/pr/src/md/unix/os_Darwin_ppc.s create mode 100644 nsprpub/pr/src/md/unix/os_Darwin_x86.s create mode 100644 nsprpub/pr/src/md/unix/os_HPUX.s create mode 100644 nsprpub/pr/src/md/unix/os_HPUX_ia64.s create mode 100644 nsprpub/pr/src/md/unix/os_Irix.s create mode 100644 nsprpub/pr/src/md/unix/os_Linux_ia64.s create mode 100644 nsprpub/pr/src/md/unix/os_Linux_ppc.s create mode 100644 nsprpub/pr/src/md/unix/os_Linux_x86.s create mode 100644 nsprpub/pr/src/md/unix/os_Linux_x86_64.s create mode 100644 nsprpub/pr/src/md/unix/os_ReliantUNIX.s create mode 100644 nsprpub/pr/src/md/unix/os_SunOS.s create mode 100644 nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s create mode 100644 nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s create mode 100644 nsprpub/pr/src/md/unix/os_SunOS_x86.s create mode 100644 nsprpub/pr/src/md/unix/os_SunOS_x86_64.s create mode 100644 nsprpub/pr/src/md/unix/osf1.c create mode 100644 nsprpub/pr/src/md/unix/pthreads_user.c create mode 100644 nsprpub/pr/src/md/unix/qnx.c create mode 100644 nsprpub/pr/src/md/unix/reliantunix.c create mode 100644 nsprpub/pr/src/md/unix/riscos.c create mode 100644 nsprpub/pr/src/md/unix/scoos.c create mode 100644 nsprpub/pr/src/md/unix/solaris.c create mode 100644 nsprpub/pr/src/md/unix/sony.c create mode 100644 nsprpub/pr/src/md/unix/sunos4.c create mode 100644 nsprpub/pr/src/md/unix/unix.c create mode 100644 nsprpub/pr/src/md/unix/unix_errors.c create mode 100644 nsprpub/pr/src/md/unix/unixware.c create mode 100644 nsprpub/pr/src/md/unix/uxpoll.c create mode 100644 nsprpub/pr/src/md/unix/uxproces.c create mode 100644 nsprpub/pr/src/md/unix/uxrng.c create mode 100644 nsprpub/pr/src/md/unix/uxshm.c create mode 100644 nsprpub/pr/src/md/unix/uxwrap.c create mode 100644 nsprpub/pr/src/md/windows/.cvsignore create mode 100644 nsprpub/pr/src/md/windows/Makefile.in create mode 100644 nsprpub/pr/src/md/windows/ntdllmn.c create mode 100644 nsprpub/pr/src/md/windows/ntgc.c create mode 100644 nsprpub/pr/src/md/windows/ntinrval.c create mode 100644 nsprpub/pr/src/md/windows/ntio.c create mode 100644 nsprpub/pr/src/md/windows/ntmisc.c create mode 100644 nsprpub/pr/src/md/windows/ntsec.c create mode 100644 nsprpub/pr/src/md/windows/ntsem.c create mode 100644 nsprpub/pr/src/md/windows/ntthread.c create mode 100644 nsprpub/pr/src/md/windows/objs.mk create mode 100644 nsprpub/pr/src/md/windows/w16callb.c create mode 100644 nsprpub/pr/src/md/windows/w16error.c create mode 100644 nsprpub/pr/src/md/windows/w16fmem.c create mode 100644 nsprpub/pr/src/md/windows/w16gc.c create mode 100644 nsprpub/pr/src/md/windows/w16io.c create mode 100644 nsprpub/pr/src/md/windows/w16mem.c create mode 100644 nsprpub/pr/src/md/windows/w16null.c create mode 100644 nsprpub/pr/src/md/windows/w16proc.c create mode 100644 nsprpub/pr/src/md/windows/w16sock.c create mode 100644 nsprpub/pr/src/md/windows/w16stdio.c create mode 100644 nsprpub/pr/src/md/windows/w16thred.c create mode 100644 nsprpub/pr/src/md/windows/w32ipcsem.c create mode 100644 nsprpub/pr/src/md/windows/w32poll.c create mode 100644 nsprpub/pr/src/md/windows/w32rng.c create mode 100644 nsprpub/pr/src/md/windows/w32shm.c create mode 100644 nsprpub/pr/src/md/windows/w95cv.c create mode 100644 nsprpub/pr/src/md/windows/w95dllmain.c create mode 100644 nsprpub/pr/src/md/windows/w95io.c create mode 100644 nsprpub/pr/src/md/windows/w95sock.c create mode 100644 nsprpub/pr/src/md/windows/w95thred.c create mode 100644 nsprpub/pr/src/md/windows/win32_errors.c create mode 100644 nsprpub/pr/src/memory/.cvsignore create mode 100644 nsprpub/pr/src/memory/Makefile.in create mode 100644 nsprpub/pr/src/memory/prgcleak.c create mode 100644 nsprpub/pr/src/memory/prseg.c create mode 100644 nsprpub/pr/src/memory/prshm.c create mode 100644 nsprpub/pr/src/memory/prshma.c create mode 100644 nsprpub/pr/src/misc/.cvsignore create mode 100644 nsprpub/pr/src/misc/Makefile.in create mode 100644 nsprpub/pr/src/misc/compile-et.pl create mode 100644 nsprpub/pr/src/misc/pralarm.c create mode 100644 nsprpub/pr/src/misc/pratom.c create mode 100644 nsprpub/pr/src/misc/prcountr.c create mode 100644 nsprpub/pr/src/misc/prdtoa.c create mode 100644 nsprpub/pr/src/misc/prenv.c create mode 100644 nsprpub/pr/src/misc/prerr.c create mode 100644 nsprpub/pr/src/misc/prerr.et create mode 100644 nsprpub/pr/src/misc/prerr.properties create mode 100644 nsprpub/pr/src/misc/prerror.c create mode 100644 nsprpub/pr/src/misc/prerrortable.c create mode 100644 nsprpub/pr/src/misc/prinit.c create mode 100644 nsprpub/pr/src/misc/prinrval.c create mode 100644 nsprpub/pr/src/misc/pripc.c create mode 100644 nsprpub/pr/src/misc/pripcsem.c create mode 100644 nsprpub/pr/src/misc/prlog2.c create mode 100644 nsprpub/pr/src/misc/prlong.c create mode 100644 nsprpub/pr/src/misc/prnetdb.c create mode 100644 nsprpub/pr/src/misc/prolock.c create mode 100644 nsprpub/pr/src/misc/prrng.c create mode 100644 nsprpub/pr/src/misc/prsystem.c create mode 100644 nsprpub/pr/src/misc/prthinfo.c create mode 100644 nsprpub/pr/src/misc/prtime.c create mode 100644 nsprpub/pr/src/misc/prtpool.c create mode 100644 nsprpub/pr/src/misc/prtrace.c create mode 100644 nsprpub/pr/src/nspr.def create mode 100644 nsprpub/pr/src/nspr.rc create mode 100644 nsprpub/pr/src/nspr_symvec.opt create mode 100644 nsprpub/pr/src/os2extra.def create mode 100644 nsprpub/pr/src/prvrsion.c create mode 100644 nsprpub/pr/src/pthreads/.cvsignore create mode 100644 nsprpub/pr/src/pthreads/Makefile.in create mode 100644 nsprpub/pr/src/pthreads/ptio.c create mode 100644 nsprpub/pr/src/pthreads/ptmisc.c create mode 100644 nsprpub/pr/src/pthreads/ptsynch.c create mode 100644 nsprpub/pr/src/pthreads/ptthread.c create mode 100644 nsprpub/pr/src/threads/.cvsignore create mode 100644 nsprpub/pr/src/threads/Makefile.in create mode 100644 nsprpub/pr/src/threads/combined/.cvsignore create mode 100644 nsprpub/pr/src/threads/combined/Makefile.in create mode 100644 nsprpub/pr/src/threads/combined/README create mode 100644 nsprpub/pr/src/threads/combined/prucpu.c create mode 100644 nsprpub/pr/src/threads/combined/prucv.c create mode 100644 nsprpub/pr/src/threads/combined/prulock.c create mode 100644 nsprpub/pr/src/threads/combined/prustack.c create mode 100644 nsprpub/pr/src/threads/combined/pruthr.c create mode 100644 nsprpub/pr/src/threads/prcmon.c create mode 100644 nsprpub/pr/src/threads/prcthr.c create mode 100644 nsprpub/pr/src/threads/prdump.c create mode 100644 nsprpub/pr/src/threads/prmon.c create mode 100644 nsprpub/pr/src/threads/prrwlock.c create mode 100644 nsprpub/pr/src/threads/prsem.c create mode 100644 nsprpub/pr/src/threads/prtpd.c create mode 100644 nsprpub/pr/tests/.cvsignore create mode 100644 nsprpub/pr/tests/Makefile.in create mode 100644 nsprpub/pr/tests/README.TXT create mode 100644 nsprpub/pr/tests/accept.c create mode 100644 nsprpub/pr/tests/acceptread.c create mode 100644 nsprpub/pr/tests/acceptreademu.c create mode 100644 nsprpub/pr/tests/addrstr.c create mode 100644 nsprpub/pr/tests/affinity.c create mode 100644 nsprpub/pr/tests/alarm.c create mode 100644 nsprpub/pr/tests/anonfm.c create mode 100644 nsprpub/pr/tests/append.c create mode 100644 nsprpub/pr/tests/atomic.c create mode 100644 nsprpub/pr/tests/attach.c create mode 100644 nsprpub/pr/tests/bigfile.c create mode 100644 nsprpub/pr/tests/bigfile2.c create mode 100644 nsprpub/pr/tests/bigfile3.c create mode 100644 nsprpub/pr/tests/bug1test.c create mode 100644 nsprpub/pr/tests/cleanup.c create mode 100644 nsprpub/pr/tests/cltsrv.c create mode 100644 nsprpub/pr/tests/concur.c create mode 100644 nsprpub/pr/tests/cvar.c create mode 100644 nsprpub/pr/tests/cvar2.c create mode 100644 nsprpub/pr/tests/dbmalloc.c create mode 100644 nsprpub/pr/tests/dbmalloc1.c create mode 100644 nsprpub/pr/tests/dceemu.c create mode 100644 nsprpub/pr/tests/depend.c create mode 100644 nsprpub/pr/tests/dll/.cvsignore create mode 100644 nsprpub/pr/tests/dll/Makefile.in create mode 100644 nsprpub/pr/tests/dll/my.def create mode 100644 nsprpub/pr/tests/dll/mygetval.c create mode 100644 nsprpub/pr/tests/dll/mysetval.c create mode 100644 nsprpub/pr/tests/dlltest.c create mode 100644 nsprpub/pr/tests/dtoa.c create mode 100644 nsprpub/pr/tests/env.c create mode 100644 nsprpub/pr/tests/errcodes.c create mode 100644 nsprpub/pr/tests/errset.c create mode 100644 nsprpub/pr/tests/exit.c create mode 100644 nsprpub/pr/tests/fdcach.c create mode 100644 nsprpub/pr/tests/fileio.c create mode 100644 nsprpub/pr/tests/foreign.c create mode 100644 nsprpub/pr/tests/forktest.c create mode 100644 nsprpub/pr/tests/formattm.c create mode 100644 nsprpub/pr/tests/freeif.c create mode 100644 nsprpub/pr/tests/fsync.c create mode 100644 nsprpub/pr/tests/getai.c create mode 100644 nsprpub/pr/tests/gethost.c create mode 100644 nsprpub/pr/tests/getproto.c create mode 100644 nsprpub/pr/tests/i2l.c create mode 100644 nsprpub/pr/tests/initclk.c create mode 100644 nsprpub/pr/tests/inrval.c create mode 100644 nsprpub/pr/tests/instrumt.c create mode 100644 nsprpub/pr/tests/intrio.c create mode 100644 nsprpub/pr/tests/intrupt.c create mode 100644 nsprpub/pr/tests/io_timeout.c create mode 100644 nsprpub/pr/tests/io_timeoutk.c create mode 100644 nsprpub/pr/tests/io_timeoutu.c create mode 100644 nsprpub/pr/tests/ioconthr.c create mode 100644 nsprpub/pr/tests/ipv6.c create mode 100644 nsprpub/pr/tests/join.c create mode 100644 nsprpub/pr/tests/joinkk.c create mode 100644 nsprpub/pr/tests/joinku.c create mode 100644 nsprpub/pr/tests/joinuk.c create mode 100644 nsprpub/pr/tests/joinuu.c create mode 100644 nsprpub/pr/tests/layer.c create mode 100644 nsprpub/pr/tests/lazyinit.c create mode 100644 nsprpub/pr/tests/libfilename.c create mode 100644 nsprpub/pr/tests/lltest.c create mode 100644 nsprpub/pr/tests/lock.c create mode 100644 nsprpub/pr/tests/lockfile.c create mode 100644 nsprpub/pr/tests/logger.c create mode 100644 nsprpub/pr/tests/makedir.c create mode 100644 nsprpub/pr/tests/many_cv.c create mode 100644 nsprpub/pr/tests/mbcs.c create mode 100644 nsprpub/pr/tests/multiacc.c create mode 100644 nsprpub/pr/tests/multiwait.c create mode 100644 nsprpub/pr/tests/nameshm1.c create mode 100644 nsprpub/pr/tests/nbconn.c create mode 100644 nsprpub/pr/tests/nblayer.c create mode 100644 nsprpub/pr/tests/nonblock.c create mode 100644 nsprpub/pr/tests/ntioto.c create mode 100644 nsprpub/pr/tests/ntoh.c create mode 100644 nsprpub/pr/tests/obsints.c create mode 100644 nsprpub/pr/tests/op_2long.c create mode 100644 nsprpub/pr/tests/op_excl.c create mode 100644 nsprpub/pr/tests/op_filnf.c create mode 100644 nsprpub/pr/tests/op_filok.c create mode 100644 nsprpub/pr/tests/op_noacc.c create mode 100644 nsprpub/pr/tests/op_nofil.c create mode 100644 nsprpub/pr/tests/openfile.c create mode 100644 nsprpub/pr/tests/parent.c create mode 100644 nsprpub/pr/tests/peek.c create mode 100644 nsprpub/pr/tests/perf.c create mode 100644 nsprpub/pr/tests/pipeping.c create mode 100644 nsprpub/pr/tests/pipeping2.c create mode 100644 nsprpub/pr/tests/pipepong.c create mode 100644 nsprpub/pr/tests/pipepong2.c create mode 100644 nsprpub/pr/tests/pipeself.c create mode 100755 nsprpub/pr/tests/poll_er.c create mode 100644 nsprpub/pr/tests/poll_nm.c create mode 100644 nsprpub/pr/tests/poll_to.c create mode 100644 nsprpub/pr/tests/pollable.c create mode 100644 nsprpub/pr/tests/prftest.c create mode 100644 nsprpub/pr/tests/prftest1.c create mode 100644 nsprpub/pr/tests/prftest2.c create mode 100644 nsprpub/pr/tests/primblok.c create mode 100644 nsprpub/pr/tests/priotest.c create mode 100644 nsprpub/pr/tests/provider.c create mode 100644 nsprpub/pr/tests/prpoll.c create mode 100644 nsprpub/pr/tests/prpollml.c create mode 100644 nsprpub/pr/tests/prselect.c create mode 100644 nsprpub/pr/tests/prttools.h create mode 100644 nsprpub/pr/tests/randseed.c create mode 100644 nsprpub/pr/tests/ranfile.c create mode 100644 nsprpub/pr/tests/rmdir.c create mode 100755 nsprpub/pr/tests/runtests.sh create mode 100644 nsprpub/pr/tests/runy2ktests.ksh create mode 100644 nsprpub/pr/tests/rwlocktest.c create mode 100644 nsprpub/pr/tests/sel_spd.c create mode 100755 nsprpub/pr/tests/selct_er.c create mode 100644 nsprpub/pr/tests/selct_nm.c create mode 100644 nsprpub/pr/tests/selct_to.c create mode 100644 nsprpub/pr/tests/select2.c create mode 100644 nsprpub/pr/tests/selintr.c create mode 100644 nsprpub/pr/tests/sem.c create mode 100644 nsprpub/pr/tests/sema.c create mode 100644 nsprpub/pr/tests/semaerr.c create mode 100644 nsprpub/pr/tests/semaerr1.c create mode 100644 nsprpub/pr/tests/semaping.c create mode 100644 nsprpub/pr/tests/semapong.c create mode 100644 nsprpub/pr/tests/sendzlf.c create mode 100644 nsprpub/pr/tests/server_test.c create mode 100644 nsprpub/pr/tests/servr_kk.c create mode 100644 nsprpub/pr/tests/servr_ku.c create mode 100644 nsprpub/pr/tests/servr_uk.c create mode 100644 nsprpub/pr/tests/servr_uu.c create mode 100644 nsprpub/pr/tests/short_thread.c create mode 100644 nsprpub/pr/tests/sigpipe.c create mode 100644 nsprpub/pr/tests/sleep.c create mode 100644 nsprpub/pr/tests/socket.c create mode 100644 nsprpub/pr/tests/sockopt.c create mode 100644 nsprpub/pr/tests/sockping.c create mode 100644 nsprpub/pr/tests/sockpong.c create mode 100644 nsprpub/pr/tests/sprintf.c create mode 100644 nsprpub/pr/tests/sproc_ch.c create mode 100644 nsprpub/pr/tests/sproc_p.c create mode 100644 nsprpub/pr/tests/stack.c create mode 100644 nsprpub/pr/tests/stat.c create mode 100644 nsprpub/pr/tests/stdio.c create mode 100644 nsprpub/pr/tests/str2addr.c create mode 100644 nsprpub/pr/tests/strod.c create mode 100644 nsprpub/pr/tests/suspend.c create mode 100644 nsprpub/pr/tests/switch.c create mode 100644 nsprpub/pr/tests/system.c create mode 100644 nsprpub/pr/tests/testbit.c create mode 100644 nsprpub/pr/tests/testfile.c create mode 100644 nsprpub/pr/tests/threads.c create mode 100644 nsprpub/pr/tests/thrpool_client.c create mode 100644 nsprpub/pr/tests/thrpool_server.c create mode 100644 nsprpub/pr/tests/thruput.c create mode 100644 nsprpub/pr/tests/time.c create mode 100644 nsprpub/pr/tests/timemac.c create mode 100644 nsprpub/pr/tests/timetest.c create mode 100644 nsprpub/pr/tests/tmoacc.c create mode 100644 nsprpub/pr/tests/tmocon.c create mode 100644 nsprpub/pr/tests/tpd.c create mode 100644 nsprpub/pr/tests/udpsrv.c create mode 100644 nsprpub/pr/tests/ut_ttools.h create mode 100644 nsprpub/pr/tests/vercheck.c create mode 100644 nsprpub/pr/tests/version.c create mode 100644 nsprpub/pr/tests/writev.c create mode 100644 nsprpub/pr/tests/xnotify.c create mode 100644 nsprpub/pr/tests/y2k.c create mode 100644 nsprpub/pr/tests/y2ktmo.c create mode 100644 nsprpub/pr/tests/yield.c create mode 100644 nsprpub/pr/tests/zerolen.c create mode 100644 nsprpub/tools/.cvsignore create mode 100644 nsprpub/tools/Makefile.in create mode 100644 nsprpub/tools/httpget.c create mode 100644 nsprpub/tools/tail.c diff --git a/nsprpub/.cvsignore b/nsprpub/.cvsignore new file mode 100644 index 00000000000..5a12c76549a --- /dev/null +++ b/nsprpub/.cvsignore @@ -0,0 +1,5 @@ +Makefile +config-defs.h +config.cache +config.log +config.status diff --git a/nsprpub/Makefile.in b/nsprpub/Makefile.in new file mode 100644 index 00000000000..c80d24a803b --- /dev/null +++ b/nsprpub/Makefile.in @@ -0,0 +1,152 @@ +#! gmake + +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +MOD_DEPTH = . +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +MAKE := $(patsubst -j%,,$(MAKE)) -j1 + +DIRS = config pr lib + +ifdef MOZILLA_CLIENT +# Make nsinstall use absolute symlinks by default for Mozilla OSX builds +# http://bugzilla.mozilla.org/show_bug.cgi?id=193164 +ifeq ($(OS_ARCH),Darwin) +ifndef NSDISTMODE +NSDISTMODE=absolute_symlink +export NSDISTMODE +endif +endif +endif + +DIST_GARBAGE = config.cache config.log config.status + +all:: config.status export + +include $(topsrcdir)/config/rules.mk + +config.status:: configure +ifeq ($(OS_ARCH),WINNT) + sh $(srcdir)/configure --no-create --no-recursion +else + ./config.status --recheck && ./config.status +endif + +# +# The -ll option of zip converts CR LF to LF. +# +ifeq ($(OS_ARCH),WINNT) +ZIP_ASCII_OPT = -ll +endif + +# Delete config/autoconf.mk last because it is included by every makefile. +distclean:: + @echo "cd pr/tests; $(MAKE) $@" + @$(MAKE) -C pr/tests $@ + rm -f config/autoconf.mk + rm -f `cat unallmakefiles` unallmakefiles + +release:: + echo $(BUILD_NUMBER) > $(RELEASE_DIR)/$(BUILD_NUMBER)/version.df + @if test -f imports.df; then \ + echo "cp -f imports.df $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df"; \ + cp -f imports.df $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df; \ + else \ + echo "echo > $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df"; \ + echo > $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df; \ + fi + cd $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \ + rm -rf META-INF; mkdir META-INF; cd META-INF; \ + echo "Manifest-Version: 1.0" > MANIFEST.MF; \ + echo "" >> MANIFEST.MF; \ + cd ..; rm -f mdbinary.jar; zip -r mdbinary.jar META-INF bin lib; \ + rm -rf META-INF; \ + cd include; \ + rm -rf META-INF; mkdir META-INF; cd META-INF; \ + echo "Manifest-Version: 1.0" > MANIFEST.MF; \ + echo "" >> MANIFEST.MF; \ + cd ..; rm -f mdheader.jar; zip $(ZIP_ASCII_OPT) -r mdheader.jar *; \ + rm -rf META-INF +ifeq ($(OS_ARCH),WINNT) + @if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); then \ + rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + echo "making directory $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)"; \ + mkdir -p $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + fi + @if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); then \ + rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + echo "making directory $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME)"; \ + mkdir -p $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + fi +else + @if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); then \ + rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + echo "making directory $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)"; \ + $(NSINSTALL) -D $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + chmod 775 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + fi + @if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); then \ + rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + echo "making directory $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME)"; \ + $(NSINSTALL) -D $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + chmod 775 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + fi +endif + cd $(RELEASE_DIR)/$(BUILD_NUMBER); \ + cp -f version.df imports.df $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/version.df; \ + chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/imports.df; \ + cd $(OBJDIR_NAME); \ + cp -f mdbinary.jar $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME)/mdbinary.jar; \ + cd include; \ + cp -f mdheader.jar $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME)/mdheader.jar + +package: + @echo "cd pkg; $(MAKE) publish" + $(MAKE) -C pkg publish + +depend: + @echo "NSPR20 has no dependencies. Skipped." diff --git a/nsprpub/admin/explode.pl b/nsprpub/admin/explode.pl new file mode 100644 index 00000000000..881f21b9bfd --- /dev/null +++ b/nsprpub/admin/explode.pl @@ -0,0 +1,75 @@ +#!/bin/perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# ----------------------------------------------------------------- +# +# explode.pl -- Unpack .jar files into bin, lib, include directories +# +# syntax: perl explode.pl +# +# Description: +# explode.pl unpacks the .jar files created by the NSPR build +# procedure. +# +# Suggested use: After copying the platform directories to +# /s/b/c/nspr20/. CD to /s/b/c/nspr20/ and +# run explode.pl. This will unpack the jar files into bin, lib, +# include directories. +# +# ----------------------------------------------------------------- + +@dirs = `ls -d *.OBJ*`; + +foreach $dir (@dirs) { + chop($dir); + if (-l $dir) { + print "Skipping symbolic link $dir\n"; + next; + } + print "Unzipping $dir/mdbinary.jar\n"; + system ("unzip", "-o", "$dir/mdbinary.jar", + "-d", "$dir"); + system ("rm", "-rf", "$dir/META-INF"); + mkdir "$dir/include", 0755; + print "Unzipping $dir/mdheader.jar\n"; + system ("unzip", "-o", "-aa", + "$dir/mdheader.jar", + "-d", "$dir/include"); + system ("rm", "-rf", "$dir/include/META-INF"); +} +# --- end explode.pl ---------------------------------------------- diff --git a/nsprpub/admin/makeTargetDirs.sh b/nsprpub/admin/makeTargetDirs.sh new file mode 100644 index 00000000000..4250ce4a0bc --- /dev/null +++ b/nsprpub/admin/makeTargetDirs.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# ----------------------------------------------------------------- +# makeTargetDirs.sh -- Create target directories for building NSPR +# +# syntax: makeTargetDirs.sh +# +# Description: +# makeTargetDirs.sh creates a set of directories intended for use +# with NSPR's autoconf based build system. +# +# The enumerated directories are the same as those built for NSPR +# 4.1.1. Adjust as needed. +# +# ----------------------------------------------------------------- + +mkdir AIX4.3_64_DBG.OBJ +mkdir AIX4.3_64_OPT.OBJ +mkdir AIX4.3_DBG.OBJ +mkdir AIX4.3_OPT.OBJ +mkdir HP-UXB.11.00_64_DBG.OBJ +mkdir HP-UXB.11.00_64_OPT.OBJ +mkdir HP-UXB.11.00_DBG.OBJ +mkdir HP-UXB.11.00_OPT.OBJ +mkdir IRIX6.5_n32_PTH_DBG.OBJ +mkdir IRIX6.5_n32_PTH_OPT.OBJ +mkdir Linux2.2_x86_glibc_PTH_DBG.OBJ +mkdir Linux2.2_x86_glibc_PTH_OPT.OBJ +mkdir Linux2.4_x86_glibc_PTH_DBG.OBJ +mkdir Linux2.4_x86_glibc_PTH_OPT.OBJ +mkdir OSF1V4.0D_DBG.OBJ +mkdir OSF1V4.0D_OPT.OBJ +mkdir SunOS5.6_DBG.OBJ +mkdir SunOS5.6_OPT.OBJ +mkdir SunOS5.7_64_DBG.OBJ +mkdir SunOS5.7_64_OPT.OBJ +mkdir WIN954.0_DBG.OBJ +mkdir WIN954.0_DBG.OBJD +mkdir WIN954.0_OPT.OBJ +mkdir WINNT4.0_DBG.OBJ +mkdir WINNT4.0_DBG.OBJD +mkdir WINNT4.0_OPT.OBJ +# --- end makeTargetDirs.sh --------------------------------------- diff --git a/nsprpub/admin/repackage.sh b/nsprpub/admin/repackage.sh new file mode 100755 index 00000000000..67942dab464 --- /dev/null +++ b/nsprpub/admin/repackage.sh @@ -0,0 +1,211 @@ +#! /bin/sh +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# ------------------------------------------------------------------ +# repackage.sh -- Repackage NSPR from /s/b/c to mozilla.org format +# +# syntax: repackage.sh +# +# Description: +# repackage.sh creates NSPR binary distributions for mozilla.org from +# the internal binary distributions in /share/builds/components/nspr20. +# There are reasons why we can't just push the internal binary distributions +# to mozilla.org. External developers prefer to use the common archive +# file format for their platforms, rather than the jar files we use internally. +# +# On Unix, we create a tar.gz file. On Windows, we create a zip file. +# For example: NSPR 4.1.1, these would be nspr-4.1.1.tar.gz and nspr-4.1.1.zip. +# +# When unpacked, nspr-4.1.1.tar.gz or nspr-4.1.1.zip should expand to a +# nspr-4.1.1 directory that contains three subdirectories: include, lib, +# and bin. The header files, with the correct line endings for the +# platform, are in nspr-4.1.1/include. The libraries are in nspr-4.1.1/lib. +# The executable programs are in nspr-4.1.1/bin. +# +# Note! Files written with Gnu tar are not readable by some non-Gnu +# versions. Sun, in particular. +# +# +# +# +# ------------------------------------------------------------------ + +FROMTOP=/share/builds/components/nspr20/v4.7.1 +TOTOP=./v4.7.1 +NSPRDIR=nspr-4.7.1 +SOURCETAG=NSPR_4_7_1_RTM + +# +# enumerate Unix object directories on /s/b/c +UNIX_OBJDIRS=" +HP-UXB.11.11_64_DBG.OBJ +HP-UXB.11.11_64_OPT.OBJ +HP-UXB.11.11_DBG.OBJ +HP-UXB.11.11_OPT.OBJ +HP-UXB.11.23_ia64_32_DBG.OBJ +HP-UXB.11.23_ia64_32_OPT.OBJ +HP-UXB.11.23_ia64_64_DBG.OBJ +HP-UXB.11.23_ia64_64_OPT.OBJ +Linux2.4_x86_glibc_PTH_DBG.OBJ +Linux2.4_x86_glibc_PTH_OPT.OBJ +Linux2.6_x86_64_glibc_PTH_DBG.OBJ +Linux2.6_x86_64_glibc_PTH_OPT.OBJ +Linux2.6_x86_glibc_PTH_DBG.OBJ +Linux2.6_x86_glibc_PTH_OPT.OBJ +SunOS5.9_64_DBG.OBJ +SunOS5.9_64_OPT.OBJ +SunOS5.9_DBG.OBJ +SunOS5.9_OPT.OBJ +" +# +# enumerate Windows object directories on /s/b/c +WIN_OBJDIRS=" +WIN954.0_DBG.OBJ +WIN954.0_DBG.OBJD +WIN954.0_OPT.OBJ +WINNT5.0_DBG.OBJ +WINNT5.0_DBG.OBJD +WINNT5.0_OPT.OBJ +" + +# +# Create the destination directory. +# +echo "removing directory $TOTOP" +rm -rf $TOTOP +echo "creating directory $TOTOP" +mkdir -p $TOTOP + +# +# Generate the tar.gz files for Unix platforms. +# +for OBJDIR in $UNIX_OBJDIRS; do + echo "removing directory $NSPRDIR" + rm -rf $NSPRDIR + echo "creating directory $NSPRDIR" + mkdir $NSPRDIR + + echo "creating directory $NSPRDIR/include" + mkdir $NSPRDIR/include + echo "copying $FROMTOP/$OBJDIR/include" + cp -r $FROMTOP/$OBJDIR/include $NSPRDIR + + echo "copying $FROMTOP/$OBJDIR/lib" + cp -r $FROMTOP/$OBJDIR/lib $NSPRDIR + + echo "copying $FROMTOP/$OBJDIR/bin" + cp -r $FROMTOP/$OBJDIR/bin $NSPRDIR + + echo "creating directory $TOTOP/$OBJDIR" + mkdir $TOTOP/$OBJDIR + echo "creating $TOTOP/$OBJDIR/$NSPRDIR.tar" + tar cvf $TOTOP/$OBJDIR/$NSPRDIR.tar $NSPRDIR + echo "gzipping $TOTOP/$OBJDIR/$NSPRDIR.tar" + gzip $TOTOP/$OBJDIR/$NSPRDIR.tar +done + +# +# Generate the zip files for Windows platforms. +# +for OBJDIR in $WIN_OBJDIRS; do + echo "removing directory $NSPRDIR" + rm -rf $NSPRDIR + echo "creating directory $NSPRDIR" + mkdir $NSPRDIR + + echo "creating directory $NSPRDIR/include" + mkdir $NSPRDIR/include + echo "creating directory $NSPRDIR/include/private" + mkdir $NSPRDIR/include/private + echo "creating directory $NSPRDIR/include/obsolete" + mkdir $NSPRDIR/include/obsolete + + # copy headers and adjust unix line-end to Windows line-end + # Note: Watch out for the "sed" command line. + # when editing the command, take care to preserve the "^M" as the literal + # cntl-M character! in vi, use "cntl-v cntl-m" to enter it! + # + headers=`ls $FROMTOP/$OBJDIR/include/*.h` + for header in $headers; do + sed -e 's/$/ /g' $header > $NSPRDIR/include/`basename $header` + done + headers=`ls $FROMTOP/$OBJDIR/include/obsolete/*.h` + for header in $headers; do + sed -e 's/$/ /g' $header > $NSPRDIR/include/obsolete/`basename $header` + done + headers=`ls $FROMTOP/$OBJDIR/include/private/*.h` + for header in $headers; do + sed -e 's/$/ /g' $header > $NSPRDIR/include/private/`basename $header` + done + + echo "copying $FROMTOP/$OBJDIR/lib" + cp -r $FROMTOP/$OBJDIR/lib $NSPRDIR + + echo "copying $FROMTOP/$OBJDIR/bin" + cp -r $FROMTOP/$OBJDIR/bin $NSPRDIR + + echo "creating directory $TOTOP/$OBJDIR" + mkdir -p $TOTOP/$OBJDIR + echo "creating $TOTOP/$OBJDIR/$NSPRDIR.zip" + zip -r $TOTOP/$OBJDIR/$NSPRDIR.zip $NSPRDIR +done + +# +# package the source from CVS +# +echo "Packaging source" +echo "removing directory $NSPRDIR" +rm -rf $NSPRDIR +echo "creating directory $NSPRDIR" +mkdir $NSPRDIR +myWD=`pwd` +cd $NSPRDIR +echo "Pulling source from CVS with tag $SOURCETAG" +cvs co -r $SOURCETAG mozilla/nsprpub +cd $myWD +mkdir $TOTOP/src +echo "Creating source tar file: $TOTOP/src/$NSPRDIR.tar" +tar cvf $TOTOP/src/$NSPRDIR.tar $NSPRDIR +echo "gzip $TOTOP/src/$NSPRDIR.tar" +gzip $TOTOP/src/$NSPRDIR.tar + +# +# Remove the working directory. +# +echo "removing directory $NSPRDIR" +rm -rf $NSPRDIR +# --- end repackage.sh --------------------------------------------- diff --git a/nsprpub/admin/symlinks.sh b/nsprpub/admin/symlinks.sh new file mode 100644 index 00000000000..f90582e2d35 --- /dev/null +++ b/nsprpub/admin/symlinks.sh @@ -0,0 +1,75 @@ +#!/bin/sh +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# ----------------------------------------------------------------- +# symlinks.sh -- create links from NSPR builds +# +# syntax: symlinks.sh +# +# Description: +# symlinks.sh creates some symbolic links for NSPR build targets +# that are not actually build, but for which there are NSPR +# binaries suitable for running on the intended target. ... got +# that? +# +# Suggested use: After copying NSPR binaries to +# /s/b/c/nspr20/ run symlinks.sh to create the links +# for all supported platforms. +# +# The symlinks in this script correspond to the NSPR 4.1.1 +# release. Adjust as necessary. +# +# ----------------------------------------------------------------- + +ln -s SunOS5.6_DBG.OBJ SunOS5.7_DBG.OBJ +ln -s SunOS5.6_OPT.OBJ SunOS5.7_OPT.OBJ + +ln -s SunOS5.6_DBG.OBJ SunOS5.8_DBG.OBJ +ln -s SunOS5.6_OPT.OBJ SunOS5.8_OPT.OBJ + +ln -s SunOS5.7_64_DBG.OBJ SunOS5.8_64_DBG.OBJ +ln -s SunOS5.7_64_OPT.OBJ SunOS5.8_64_OPT.OBJ + +ln -s OSF1V4.0D_DBG.OBJ OSF1V5.0_DBG.OBJ +ln -s OSF1V4.0D_OPT.OBJ OSF1V5.0_OPT.OBJ + +ln -s WINNT4.0_DBG.OBJ WINNT5.0_DBG.OBJ +ln -s WINNT4.0_DBG.OBJD WINNT5.0_DBG.OBJD +ln -s WINNT4.0_OPT.OBJ WINNT5.0_OPT.OBJ +# --- end symlinks.sh --------------------------------------------- + diff --git a/nsprpub/build/autoconf/config.guess b/nsprpub/build/autoconf/config.guess new file mode 100755 index 00000000000..a20b311747f --- /dev/null +++ b/nsprpub/build/autoconf/config.guess @@ -0,0 +1,1481 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-10-13' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; +#### MozillaHack +# Netscape's hacked uname + xx:WINNT:* | xx:WIN95:*) + echo i586-pc-msvc + exit ;; +### End MozillaHack + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; +#### MozillaHack + *:*OpenVMS*:*:*) + case "${UNAME_SYSTEM}" in + POSIX_for_OpenVMS_AXP) echo alpha-dec-openvmsposix ;; + POSIX_for_OpenVMS_VAX) echo vax-dec-openvmsposix ;; + OpenVMS) echo alpha-dec-openvms ;; + *) echo unknown-dec-openvms ;; + esac + exit ;; +#### End MozillaHack + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/nsprpub/build/autoconf/config.sub b/nsprpub/build/autoconf/config.sub new file mode 100755 index 00000000000..2d91b11c7f3 --- /dev/null +++ b/nsprpub/build/autoconf/config.sub @@ -0,0 +1,1595 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-10-13' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. +#### MozillaHack +# mips*el +#### End MozillaHack + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mips*el | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. +#### MozillaHack +# mips*el +#### End MozillaHack + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mips*el-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; +#### MozillaHack + i386-msvc | msvc) + basic_machine=i386-pc + os=-msvc + ;; +#### End MozillaHack + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. +#### MozillaHack +# msvc +#### End MozillaHack + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -msvc* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/nsprpub/build/autoconf/install-sh b/nsprpub/build/autoconf/install-sh new file mode 100755 index 00000000000..0ff4b6a08e8 --- /dev/null +++ b/nsprpub/build/autoconf/install-sh @@ -0,0 +1,119 @@ +#!/bin/sh + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0 diff --git a/nsprpub/build/cygwin-wrapper b/nsprpub/build/cygwin-wrapper new file mode 100755 index 00000000000..679f0a11005 --- /dev/null +++ b/nsprpub/build/cygwin-wrapper @@ -0,0 +1,75 @@ +#!/bin/sh +# +# Stupid wrapper to avoid win32 dospath/cygdrive issues +# Try not to spawn programs from within this file. If the stuff in here looks royally +# confusing, see bug: http://bugzilla.mozilla.org/show_bug.cgi?id=206643 +# and look at the older versions of this file that are easier to read, but +# do basically the same thing +# + +prog=$1 +shift +if test -z "$prog"; then + exit 0 +fi + +# If $CYGDRIVE_MOUNT was not set in configure, give $mountpoint the results of mount -p +mountpoint=$CYGDRIVE_MOUNT +if test -z "$mountpoint"; then + mountpoint=`mount -p` + if test -z "$mountpoint"; then + print "Cannot determine cygwin mount points. Exiting" + exit 1 + fi +fi + +# Delete everything but "/cygdrive" (or other mountpoint) from mount=`mount -p` +mountpoint=${mountpoint#*/} +mountpoint=/${mountpoint%%[!A-Za-z0-9_]*} +mountpoint=${mountpoint%/} + +args="" +up="" +if test "${prog}" = "-up"; then + up=1 + prog=${1} + shift +fi + +process=1 + +# Convert the mountpoint in parameters to Win32 filenames +# For instance: /cygdrive/c/foo -> c:/foo +for i in "${@}" +do + if test "${i}" = "-wrap"; then + process=1 + else + if test "${i}" = "-nowrap"; then + process= + else + if test -n "${process}"; then + if test -n "${up}"; then + pathname=${i#-I[a-zA-Z]:/} + if ! test "${pathname}" = "${i}"; then + no_i=${i#-I} + driveletter=${no_i%%:*} + i=-I${mountpoint}/${driveletter}/${pathname} + fi + else + eval 'leader=${i%%'${mountpoint}'/[a-zA-Z]/*}' + if ! test "${leader}" = "${i}"; then + eval 'pathname=${i#'${leader}${mountpoint}'/[a-zA-Z]/}' + eval 'no_mountpoint=${i#'${leader}${mountpoint}'/}' + driveletter=${no_mountpoint%%/*} + i=${leader}${driveletter}:/${pathname} + fi + fi + fi + + args="${args} ${i}" + fi + fi +done + +exec $prog $args diff --git a/nsprpub/config/.cvsignore b/nsprpub/config/.cvsignore new file mode 100644 index 00000000000..bb3ee4bcc99 --- /dev/null +++ b/nsprpub/config/.cvsignore @@ -0,0 +1,11 @@ +nfspwd +revdepth +my_config.mk +my_overrides.mk +autoconf.mk +nsprincl.mk +nsprincl.sh +now +Makefile +nsinstall +nspr-config diff --git a/nsprpub/config/Makefile.in b/nsprpub/config/Makefile.in new file mode 100644 index 00000000000..cbed0d6a863 --- /dev/null +++ b/nsprpub/config/Makefile.in @@ -0,0 +1,160 @@ +#! gmake +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +# Indicate that this directory builds build tools. +INTERNAL_TOOLS = 1 + +# For sanity's sake, we compile nsinstall without the wrapped system +# headers, so that we can use it to set up the wrapped system headers. +VISIBILITY_FLAGS = + +# autoconf.mk must be deleted last (from the top-level directory) +# because it is included by every makefile. +DIST_GARBAGE = nsprincl.mk nsprincl.sh nspr-config + +RELEASE_BINS = nspr-config + +include $(topsrcdir)/config/config.mk + +CSRCS = now.c + +# This version hasn't been ported for us; the one in mozilla/config has +ifneq ($(OS_ARCH),OS2) +CSRCS += nsinstall.c + +PLSRCS = nfspwd.pl +endif + +ifeq (,$(CROSS_COMPILE)$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +# Temporary workaround to disable the generation of +# library build time because now.c uses the 'long long' +# data type that's not available on some platforms. +ifeq (,$(filter-out NEC NEXTSTEP QNX SCOOS UNIXWARE,$(OS_ARCH))) +DEFINES += -DOMIT_LIB_BUILD_TIME +endif + +ifeq ($(OS_ARCH), IRIX) + ifeq ($(basename $(OS_RELEASE)),6) + ifndef NS_USE_GCC + ifeq ($(USE_N32),1) + XLDOPTS += -n32 -Wl,-woff,85 + else + ifeq ($(USE_64),1) + XLDOPTS += -64 + else + XLDOPTS += -32 + endif + endif + endif + endif +endif + +ifeq ($(OS_ARCH), HP-UX) + ifeq ($(USE_64),1) + XLDOPTS += +DD64 + endif +endif + +ifeq ($(MOZ_OS2_TOOLS),EMX) +XCFLAGS = $(OS_CFLAGS) +ifeq ($(MOZ_OS2_EMX_OBJECTFORMAT),OMF) +XLDOPTS = -Zlinker /PM:VIO +endif +endif + +ifeq ($(MOZ_OS2_TOOLS),PGCC) +XCFLAGS = $(OS_CFLAGS) +XLDOPTS = -Zlinker /PM:VIO +endif + +include $(topsrcdir)/config/rules.mk + +PROGS = $(OBJDIR)/now$(PROG_SUFFIX) + +ifeq (,$(CROSS_COMPILE)$(filter-out OS2 WINNT,$(OS_ARCH))) +TARGETS = $(PROGS) +else +PROGS += $(OBJDIR)/nsinstall$(PROG_SUFFIX) +TARGETS = $(PROGS) $(PLSRCS:.pl=) +endif + +OUTOPTION = -o # end of the line +ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET))) +ifndef NS_USE_GCC +OUTOPTION = -Fe +endif +endif + +# Redefine MAKE_OBJDIR for just this directory +define MAKE_OBJDIR +if test ! -d $(@D); then rm -rf $(@D); mkdir $(@D); else true; fi +endef + +export:: $(TARGETS) + rm -f $(dist_bindir)/nspr-config + +ifdef WRAP_SYSTEM_INCLUDES +export:: + if test ! -d system_wrappers; then mkdir system_wrappers; fi + $(PERL) $(srcdir)/make-system-wrappers.pl system_wrappers < $(srcdir)/system-headers + $(INSTALL) system_wrappers $(dist_includedir) +endif + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(LD) $(EXEFLAGS) $< +else + $(CC) $(XCFLAGS) $< $(LDFLAGS) $(XLDOPTS) $(OUTOPTION)$@ +endif + +install:: nspr.m4 + $(NSINSTALL) -D $(DESTDIR)$(datadir)/aclocal + $(NSINSTALL) -t -m 0644 $< $(DESTDIR)$(datadir)/aclocal diff --git a/nsprpub/config/autoconf.mk.in b/nsprpub/config/autoconf.mk.in new file mode 100644 index 00000000000..1c439c68a53 --- /dev/null +++ b/nsprpub/config/autoconf.mk.in @@ -0,0 +1,130 @@ +# -*- Mode: Makefile -*- + +INCLUDED_AUTOCONF_MK = 1 +USE_AUTOCONF = 1 +@SHELL_OVERRIDE@ +MOZILLA_CLIENT = @MOZILLA_CLIENT@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +includedir = @includedir@ +libdir = @libdir@ +datadir = @datadir@ + +dist_prefix = @dist_prefix@ +dist_bindir = @dist_bindir@ +dist_includedir = @dist_includedir@ +dist_libdir = @dist_libdir@ + +DIST = $(dist_prefix) + +RELEASE_OBJDIR_NAME = @RELEASE_OBJDIR_NAME@ +OBJDIR_NAME = @OBJDIR_NAME@ +OBJDIR = @OBJDIR@ +OBJ_SUFFIX = @OBJ_SUFFIX@ +LIB_SUFFIX = @LIB_SUFFIX@ +DLL_SUFFIX = @DLL_SUFFIX@ +ASM_SUFFIX = @ASM_SUFFIX@ +MOD_NAME = @NSPR_MODNAME@ + +MOD_MAJOR_VERSION = @MOD_MAJOR_VERSION@ +MOD_MINOR_VERSION = @MOD_MINOR_VERSION@ +MOD_PATCH_VERSION = @MOD_PATCH_VERSION@ + +LIBNSPR = @LIBNSPR@ +LIBPLC = @LIBPLC@ + +CROSS_COMPILE = @CROSS_COMPILE@ +BUILD_OPT = @MOZ_OPTIMIZE@ + +USE_CPLUS = @USE_CPLUS@ +USE_IPV6 = @USE_IPV6@ +USE_N32 = @USE_N32@ +USE_64 = @USE_64@ +GC_LEAK_DETECTOR = @GC_LEAK_DETECTOR@ +ENABLE_STRIP = @ENABLE_STRIP@ + +USE_PTHREADS = @USE_PTHREADS@ +USE_BTHREADS = @USE_BTHREADS@ +PTHREADS_USER = @USE_USER_PTHREADS@ +CLASSIC_NSPR = @USE_NSPR_THREADS@ + +AS = @AS@ +ASFLAGS = @ASFLAGS@ +CC = @CC@ +CCC = @CXX@ +NS_USE_GCC = @GNU_CC@ +GCC_USE_GNU_LD = @GCC_USE_GNU_LD@ +MSC_VER = @MSC_VER@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +LD = @LD@ +RANLIB = @RANLIB@ +PERL = @PERL@ +RC = @RC@ +RCFLAGS = @RCFLAGS@ +STRIP = @STRIP@ +NSINSTALL = @NSINSTALL@ +FILTER = @FILTER@ +IMPLIB = @IMPLIB@ +CYGWIN_WRAPPER = @CYGWIN_WRAPPER@ +MT = @MT@ + +OS_CPPFLAGS = @CPPFLAGS@ +OS_CFLAGS = $(OS_CPPFLAGS) @CFLAGS@ $(DSO_CFLAGS) +OS_CXXFLAGS = $(OS_CPPFLAGS) @CXXFLAGS@ $(DSO_CFLAGS) +OS_LIBS = @OS_LIBS@ +OS_LDFLAGS = @LDFLAGS@ +OS_DLLFLAGS = @OS_DLLFLAGS@ +DLLFLAGS = @DLLFLAGS@ +EXEFLAGS = @EXEFLAGS@ +OPTIMIZER = @OPTIMIZER@ + +MKSHLIB = @MKSHLIB@ +DSO_CFLAGS = @DSO_CFLAGS@ +DSO_LDOPTS = @DSO_LDOPTS@ + +RESOLVE_LINK_SYMBOLS = @RESOLVE_LINK_SYMBOLS@ + +HOST_CC = @HOST_CC@ +HOST_CFLAGS = @HOST_CFLAGS@ +HOST_LDFLAGS = @HOST_LDFLAGS@ + +DEFINES = @DEFINES@ @DEFS@ + +MDCPUCFG_H = @MDCPUCFG_H@ +PR_MD_CSRCS = @PR_MD_CSRCS@ +PR_MD_ASFILES = @PR_MD_ASFILES@ +PR_MD_ARCH_DIR = @PR_MD_ARCH_DIR@ +CPU_ARCH = @CPU_ARCH@ + +OS_TARGET = @OS_TARGET@ +OS_ARCH = @OS_ARCH@ +OS_RELEASE = @OS_RELEASE@ +OS_TEST = @OS_TEST@ + +NOSUCHFILE = @NOSUCHFILE@ +AIX_LINK_OPTS = @AIX_LINK_OPTS@ +MOZ_OBJFORMAT = @MOZ_OBJFORMAT@ +ULTRASPARC_LIBRARY = @ULTRASPARC_LIBRARY@ + +OBJECT_MODE = @OBJECT_MODE@ +ifdef OBJECT_MODE +export OBJECT_MODE +endif + +VISIBILITY_FLAGS = @VISIBILITY_FLAGS@ +WRAP_SYSTEM_INCLUDES = @WRAP_SYSTEM_INCLUDES@ + +MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLOYMENT_TARGET@ +ifdef MACOSX_DEPLOYMENT_TARGET +export MACOSX_DEPLOYMENT_TARGET +endif + +MACOS_SDK_DIR = @MACOS_SDK_DIR@ + +NEXT_ROOT = @NEXT_ROOT@ +ifdef NEXT_ROOT +export NEXT_ROOT +endif diff --git a/nsprpub/config/config.mk b/nsprpub/config/config.mk new file mode 100644 index 00000000000..10ebfdab139 --- /dev/null +++ b/nsprpub/config/config.mk @@ -0,0 +1,164 @@ +#! gmake +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# Configuration information for building in the NSPR source module + +# Define an include-at-most-once-flag +NSPR_CONFIG_MK = 1 + +# +# The variable definitions in this file are inputs to NSPR's +# build system. This file, if present, is included at the +# beginning of config.mk. +# +# For example: +# +# BUILD_OPT=1 +# USE_PTHREADS=1 +# NS_USE_GCC= +# +ifndef topsrcdir +topsrcdir=$(MOD_DEPTH) +endif + +ifndef srcdir +srcdir=. +endif + +NFSPWD = $(MOD_DEPTH)/config/nfspwd + +CFLAGS = $(VISIBILITY_FLAGS) $(CC_ONLY_FLAGS) $(OPTIMIZER)\ + $(OS_CFLAGS) $(XP_DEFINE) $(DEFINES) $(INCLUDES) $(XCFLAGS) +CCCFLAGS = $(VISIBILITY_FLAGS) $(CCC_ONLY_FLAGS) $(OPTIMIZER)\ + $(OS_CFLAGS) $(XP_DEFINE) $(DEFINES) $(INCLUDES) $(XCFLAGS) +# For purify +NOMD_CFLAGS = $(CC_ONLY_FLAGS) $(OPTIMIZER) $(NOMD_OS_CFLAGS)\ + $(XP_DEFINE) $(DEFINES) $(INCLUDES) $(XCFLAGS) +NOMD_CCFLAGS = $(CCC_ONLY_FLAGS) $(OPTIMIZER) $(NOMD_OS_CFLAGS)\ + $(XP_DEFINE) $(DEFINES) $(INCLUDES) $(XCFLAGS) + +LDFLAGS = $(OS_LDFLAGS) + +define MAKE_OBJDIR +if test ! -d $(@D); then rm -rf $(@D); $(NSINSTALL) -D $(@D); fi +endef + +LINK_DLL = $(LD) $(OS_DLLFLAGS) $(DLLFLAGS) + +ifeq ($(OS_ARCH),Darwin) +PWD := $(shell pwd) +endif + +ifeq (,$(CROSS_COMPILE)$(filter-out WINNT OS2, $(OS_ARCH))) +INSTALL = $(NSINSTALL) +else +ifeq ($(NSDISTMODE),copy) +# copy files, but preserve source mtime +INSTALL = $(NSINSTALL) -t +else +ifeq ($(NSDISTMODE),absolute_symlink) +# install using absolute symbolic links +ifeq ($(OS_ARCH),Darwin) +INSTALL = $(NSINSTALL) -L $(PWD) +else +INSTALL = $(NSINSTALL) -L `$(NFSPWD)` +endif +else +# install using relative symbolic links +INSTALL = $(NSINSTALL) -R +endif +endif +endif # (WINNT || OS2) && !CROSS_COMPILE + +DEPENDENCIES = $(OBJDIR)/.md + +ifdef BUILD_DEBUG_GC +DEFINES += -DDEBUG_GC +endif + +GARBAGE += $(DEPENDENCIES) core $(wildcard core.[0-9]*) + +DIST_GARBAGE += Makefile + +#################################################################### +# +# The NSPR-specific configuration +# +#################################################################### + +DEFINES += -DFORCE_PR_LOG + +ifeq ($(_PR_NO_CLOCK_TIMER),1) +DEFINES += -D_PR_NO_CLOCK_TIMER +endif + +ifeq ($(USE_PTHREADS), 1) +DEFINES += -D_PR_PTHREADS -UHAVE_CVAR_BUILT_ON_SEM +endif + +ifeq ($(PTHREADS_USER), 1) +DEFINES += -DPTHREADS_USER -UHAVE_CVAR_BUILT_ON_SEM +endif + +ifeq ($(USE_IPV6),1) +DEFINES += -D_PR_INET6 +endif + +ifeq ($(MOZ_UNICODE),1) +DEFINES += -DMOZ_UNICODE +endif + +#################################################################### +# +# Configuration for the release process +# +#################################################################### + +MDIST = /m/dist +ifeq ($(OS_ARCH),WINNT) +MDIST = //helium/dist +MDIST_DOS = $(subst /,\\,$(MDIST)) +endif + +# RELEASE_DIR is ns/dist/ + +RELEASE_DIR = $(MOD_DEPTH)/dist/release/$(MOD_NAME) + +RELEASE_INCLUDE_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/include +RELEASE_BIN_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/bin +RELEASE_LIB_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/lib diff --git a/nsprpub/config/gcc_hidden.h b/nsprpub/config/gcc_hidden.h new file mode 100644 index 00000000000..58140c15723 --- /dev/null +++ b/nsprpub/config/gcc_hidden.h @@ -0,0 +1,2 @@ +/* Begin all files as hidden visibility */ +#pragma GCC visibility push(hidden) diff --git a/nsprpub/config/libc_r.h b/nsprpub/config/libc_r.h new file mode 100644 index 00000000000..0f66d1270d9 --- /dev/null +++ b/nsprpub/config/libc_r.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* libc_r.h -- macros, defines, etc. to make using reentrant libc calls */ +/* a bit easier. This was initially done for AIX pthreads, */ +/* but should be usable for anyone... */ + +/* Most of these use locally defined space instead of static library space. */ +/* Because of this, we use the _INIT_R to declare/allocate space (stack), */ +/* and the plain routines to actually do it..._WARNING_: avoid allocating */ +/* memory wherever possible. Memory allocation is fairly expensive, at */ +/* least on AIX...use arrays instead (which allocate from the stack.) */ +/* I know the names are a bit strange, but I wanted to be fairly certain */ +/* that we didn't have any namespace corruption...in general, the inits are */ +/* R__INIT_R(), and the actual calls are R__R(). */ + +#ifndef _LIBC_R_H +#define _LIBC_R_H + +/************/ +/* strtok */ +/************/ +#define R_STRTOK_INIT_R() \ + char *r_strtok_r=NULL + +#define R_STRTOK_R(return,source,delim) \ + return=strtok_r(source,delim,&r_strtok_r) + +#define R_STRTOK_NORET_R(source,delim) \ + strtok_r(source,delim,&r_strtok_r) + +/**************/ +/* strerror */ +/**************/ +#define R_MAX_STRERROR_LEN_R 8192 /* Straight from limits.h */ + +#define R_STRERROR_INIT_R() \ + char r_strerror_r[R_MAX_STRERROR_LEN_R] + +#define R_STRERROR_R(val) \ + strerror_r(val,r_strerror_r,R_MAX_STRERROR_LEN_R) + +/*****************/ +/* time things */ +/*****************/ +#define R_ASCTIME_INIT_R() \ + char r_asctime_r[26] + +#define R_ASCTIME_R(val) \ + asctime_r(val,r_asctime_r) + +#define R_CTIME_INIT_R() \ + char r_ctime_r[26] + +#define R_CTIME_R(val) \ + ctime_r(val,r_ctime_r) + +#define R_GMTIME_INIT_R() \ + struct tm r_gmtime_r + +#define R_GMTIME_R(time) \ + gmtime_r(time,&r_gmtime_r) + +#define R_LOCALTIME_INIT_R() \ + struct tm r_localtime_r + +#define R_LOCALTIME_R(val) \ + localtime_r(val,&r_localtime_r) + +/***********/ +/* crypt */ +/***********/ +#include +#define R_CRYPT_INIT_R() \ + CRYPTD r_cryptd_r; \ + bzero(&r_cryptd_r,sizeof(CRYPTD)) + +#define R_CRYPT_R(pass,salt) \ + crypt_r(pass,salt,&r_cryptd_r) + +/**************/ +/* pw stuff */ +/**************/ +#define R_MAX_PW_LEN_R 1024 +/* The following must be after the last declaration, but */ +/* before the first bit of code... */ +#define R_GETPWNAM_INIT_R(pw_ptr) \ + struct passwd r_getpwnam_pw_r; \ + char r_getpwnam_line_r[R_MAX_PW_LEN_R]; \ + pw_ptr = &r_getpwnam_pw_r + +#define R_GETPWNAM_R(name) \ + getpwnam_r(name,&r_getpwnam_pw_r,r_getpwnam_line_r,R_MAX_PW_LEN_R) + +/*******************/ +/* gethost stuff */ +/*******************/ +#define R_GETHOSTBYADDR_INIT_R() \ + struct hostent r_gethostbyaddr_r; \ + struct hostent_data r_gethostbyaddr_data_r + +#define R_GETHOSTBYADDR_R(addr,len,type,xptr_ent) \ + bzero(&r_gethostbyaddr_r,sizeof(struct hostent)); \ + bzero(&r_gethostbyaddr_data_r,sizeof(struct hostent_data)); \ + xptr_ent = &r_gethostbyaddr_r; \ + if (gethostbyaddr_r(addr,len,type, \ + &r_gethostbyaddr_r,&r_gethostbyaddr_data_r) == -1) { \ + xptr_ent = NULL; \ + } + +#define R_GETHOSTBYNAME_INIT_R() \ + struct hostent r_gethostbyname_r; \ + struct hostent_data r_gethostbyname_data_r + +#define R_GETHOSTBYNAME_R(name,xptr_ent) \ + bzero(&r_gethostbyname_r,sizeof(struct hostent)); \ + bzero(&r_gethostbyname_data_r,sizeof(struct hostent_data)); \ + xptr_ent = &r_gethostbyname_r; \ + if (gethostbyname_r(name, \ + &r_gethostbyname_r,&r_gethostbyname_data_r) == -1) { \ + xptr_ent = NULL; \ + } + +#endif /* _LIBC_R_H */ diff --git a/nsprpub/config/make-system-wrappers.pl b/nsprpub/config/make-system-wrappers.pl new file mode 100644 index 00000000000..31c9af4a555 --- /dev/null +++ b/nsprpub/config/make-system-wrappers.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# IBM Corporation. +# Portions created by the Initial Developer are Copyright (C) 2004 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Brian Ryner +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +$output_dir = shift; + +while () { + chomp; + if (-e "$output_dir/$_") { + next; + } + + if (/(.*)\/[^\/*]/) { + mkdir "$output_dir/$1"; + } + + open OUT, ">$output_dir/$_"; + print OUT "#pragma GCC system_header\n"; # suppress include_next warning + print OUT "#pragma GCC visibility push(default)\n"; + print OUT "#include_next \<$_\>\n"; + print OUT "#pragma GCC visibility pop\n"; + close OUT; +} + diff --git a/nsprpub/config/nfspwd.pl b/nsprpub/config/nfspwd.pl new file mode 100644 index 00000000000..947b822ae56 --- /dev/null +++ b/nsprpub/config/nfspwd.pl @@ -0,0 +1,50 @@ +#! perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +require "fastcwd.pl"; + +$_ = &fastcwd; +if (m@^/[uh]/@o || s@^/tmp_mnt/@/@o) { + print("$_\n"); +} elsif ((($user, $rest) = m@^/usr/people/(\w+)/(.*)@o) + && readlink("/u/$user") eq "/usr/people/$user") { + print("/u/$user/$rest\n"); +} else { + chop($host = `hostname`); + print("/h/$host$_\n"); +} diff --git a/nsprpub/config/now.c b/nsprpub/config/now.c new file mode 100644 index 00000000000..f797ef84416 --- /dev/null +++ b/nsprpub/config/now.c @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include + +#if defined(VMS) +#include +#elif defined(XP_UNIX) || defined(XP_OS2_EMX) || defined(XP_BEOS) +#include +#elif defined(WIN32) +#include +#elif defined(XP_OS2_VACPP) +#include +#else +#error "Architecture not supported" +#endif + + +int main(int argc, char **argv) +{ +#if defined(OMIT_LIB_BUILD_TIME) + /* + * Some platforms don't have any 64-bit integer type + * such as 'long long'. Because we can't use NSPR's + * PR_snprintf in this program, it is difficult to + * print a static initializer for PRInt64 (a struct). + * So we print nothing. The makefiles that build the + * shared libraries will detect the empty output string + * of this program and omit the library build time + * in PRVersionDescription. + */ +#elif defined(VMS) + long long now; + struct timeb b; + ftime(&b); + now = b.time; + now *= 1000000; + now += (1000 * b.millitm); + fprintf(stdout, "%Ld", now); +#elif defined(XP_UNIX) || defined(XP_OS2_EMX) || defined(XP_BEOS) + long long now; + struct timeval tv; +#ifdef HAVE_SVID_GETTOD + gettimeofday(&tv); +#else + gettimeofday(&tv, NULL); +#endif + now = ((1000000LL) * tv.tv_sec) + (long long)tv.tv_usec; +#if defined(OSF1) + fprintf(stdout, "%ld", now); +#elif defined(BEOS) && defined(__POWERPC__) + fprintf(stdout, "%Ld", now); /* Metroworks on BeOS PPC */ +#else + fprintf(stdout, "%lld", now); +#endif + +#elif defined(WIN32) + __int64 now; + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + CopyMemory(&now, &ft, sizeof(now)); + /* + * 116444736000000000 is the number of 100-nanosecond intervals + * between Jan. 1, 1601 and Jan. 1, 1970. + */ +#ifdef __GNUC__ + now = (now - 116444736000000000LL) / 10LL; + fprintf(stdout, "%lld", now); +#else + now = (now - 116444736000000000i64) / 10i64; + fprintf(stdout, "%I64d", now); +#endif + +#elif defined(XP_OS2_VACPP) +/* no long long or i64 so we use a string */ +#include + char buf[24]; + char tbuf[7]; + time_t now; + long mtime; + int i; + + struct timeb b; + ftime(&b); + now = b.time; + _ltoa(now, buf, 10); + + mtime = b.millitm * 1000; + if (mtime == 0){ + ++now; + strcat(buf, "000000"); + } else { + _ltoa(mtime, tbuf, 10); + for (i = strlen(tbuf); i < 6; ++i) + strcat(buf, "0"); + strcat(buf, tbuf); + } + fprintf(stdout, "%s", buf); + +#else +#error "Architecture not supported" +#endif + + return 0; +} /* main */ + +/* now.c */ diff --git a/nsprpub/config/nsinstall.c b/nsprpub/config/nsinstall.c new file mode 100644 index 00000000000..80d907edf23 --- /dev/null +++ b/nsprpub/config/nsinstall.c @@ -0,0 +1,602 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Netscape portable install command. +** +** Brendan Eich, 7/20/95 +*/ +#include /* OSF/1 requires this before grp.h, so put it first */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_REENTRANT_LIBC +#include "libc_r.h" +#endif /* USE_REENTRANT_LIBC */ + +#include "pathsub.h" + +#define HAVE_FCHMOD + +#if defined(BEOS) +#undef HAVE_FCHMOD +#endif + +/* + * Does getcwd() take NULL as the first argument and malloc + * the result buffer? + */ +#if !defined(DARWIN) && !defined(NEXTSTEP) && !defined(VMS) +#define GETCWD_CAN_MALLOC +#endif + +#ifdef NEXTSTEP +#include + +/* +** balazs.pataki@sztaki.hu: The getcwd is broken in NEXTSTEP (returns 0), +** when called on a mounted fs. Did anyone notice this? Here's an ugly +** workaround ... +*/ +#define getcwd(b,s) my_getcwd(b,s) + +static char * +my_getcwd (char *buf, size_t size) +{ + FILE *pwd = popen("pwd", "r"); + char *result = fgets(buf, size, pwd); + + if (result) { + buf[strlen(buf)-1] = '\0'; + } + pclose (pwd); + return buf; +} +#endif /* NEXTSTEP */ + +#if defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) +#include +#endif + +#if defined(SCO) || defined(UNIXWARE) || defined(SNI) || defined(NCR) || defined(NEC) || defined(NEXTSTEP) +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) +#endif +#endif + +#if defined(SNI) +extern int fchmod(int fildes, mode_t mode); +#endif + +#ifdef QNX +#define d_ino d_stat.st_ino +#endif + +static void +usage(void) +{ + fprintf(stderr, + "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n" + " %*s [-DdltR] file [file ...] directory\n", + program, (int)strlen(program), ""); + exit(2); +} + +static int +mkdirs(char *path, mode_t mode) +{ + char *cp; + struct stat sb; + int res; + + while (*path == '/' && path[1] == '/') + path++; + for (cp = strrchr(path, '/'); cp && cp != path && cp[-1] == '/'; cp--) + ; + if (cp && cp != path) { + *cp = '\0'; + if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) && + mkdirs(path, mode) < 0) { + return -1; + } + *cp = '/'; + } + res = mkdir(path, mode); + if ((res != 0) && (errno == EEXIST)) + return 0; + else + return res; +} + +static uid_t +touid(char *owner) +{ + struct passwd *pw; + uid_t uid; + char *cp; + + pw = getpwnam(owner); + if (pw) + return pw->pw_uid; + uid = strtol(owner, &cp, 0); + if (uid == 0 && cp == owner) + fail("cannot find uid for %s", owner); + return uid; +} + +static gid_t +togid(char *group) +{ + struct group *gr; + gid_t gid; + char *cp; + + gr = getgrnam(group); + if (gr) + return gr->gr_gid; + gid = strtol(group, &cp, 0); + if (gid == 0 && cp == group) + fail("cannot find gid for %s", group); + return gid; +} + +int +main(int argc, char **argv) +{ + int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc; + mode_t mode = 0755; + char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ]; + uid_t uid; + gid_t gid; + struct stat sb, tosb; + struct utimbuf utb; + + program = argv[0]; + cwd = linkname = linkprefix = owner = group = 0; + onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0; + + while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { + switch (opt) { + case 'C': + cwd = optarg; + break; + case 'D': + onlydir = 1; + break; + case 'd': + dodir = 1; + break; + case 'l': + dolink = 1; + break; + case 'L': + linkprefix = optarg; + lplen = strlen(linkprefix); + dolink = 1; + break; + case 'R': + dolink = dorelsymlink = 1; + break; + case 'm': + mode = strtoul(optarg, &cp, 8); + if (mode == 0 && cp == optarg) + usage(); + break; + case 'o': + owner = optarg; + break; + case 'g': + group = optarg; + break; + case 't': + dotimes = 1; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 2 - onlydir) + usage(); + + todir = argv[argc-1]; + if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && + mkdirs(todir, 0777) < 0) { + fail("cannot make directory %s", todir); + } + if (onlydir) + return 0; + + if (!cwd) { +#ifdef GETCWD_CAN_MALLOC + cwd = getcwd(0, PATH_MAX); +#else + cwd = malloc(PATH_MAX + 1); + cwd = getcwd(cwd, PATH_MAX); +#endif + } + xchdir(todir); +#ifdef GETCWD_CAN_MALLOC + todir = getcwd(0, PATH_MAX); +#else + todir = malloc(PATH_MAX + 1); + todir = getcwd(todir, PATH_MAX); +#endif + tdlen = strlen(todir); + xchdir(cwd); + tdlen = strlen(todir); + + uid = owner ? touid(owner) : -1; + gid = group ? togid(group) : -1; + + while (--argc > 0) { + name = *argv++; + len = strlen(name); + base = xbasename(name); + bnlen = strlen(base); + toname = (char*)xmalloc(tdlen + 1 + bnlen + 1); + sprintf(toname, "%s/%s", todir, base); + exists = (lstat(toname, &tosb) == 0); + + if (dodir) { + /* -d means create a directory, always */ + if (exists && !S_ISDIR(tosb.st_mode)) { + (void) unlink(toname); + exists = 0; + } + if (!exists && mkdir(toname, mode) < 0) + fail("cannot make directory %s", toname); + if ((owner || group) && chown(toname, uid, gid) < 0) + fail("cannot change owner of %s", toname); + } else if (dolink) { + if (*name == '/') { + /* source is absolute pathname, link to it directly */ + linkname = 0; + } else { + if (linkprefix) { + /* -L implies -l and prefixes names with a $cwd arg. */ + len += lplen + 1; + linkname = (char*)xmalloc(len + 1); + sprintf(linkname, "%s/%s", linkprefix, name); + } else if (dorelsymlink) { + /* Symlink the relative path from todir to source name. */ + linkname = (char*)xmalloc(PATH_MAX); + + if (*todir == '/') { + /* todir is absolute: skip over common prefix. */ + lplen = relatepaths(todir, cwd, linkname); + strcpy(linkname + lplen, name); + } else { + /* todir is named by a relative path: reverse it. */ + reversepath(todir, name, len, linkname); + xchdir(cwd); + } + + len = strlen(linkname); + } + name = linkname; + } + + /* Check for a pre-existing symlink with identical content. */ + if (exists && + (!S_ISLNK(tosb.st_mode) || + readlink(toname, buf, sizeof buf) != len || + strncmp(buf, name, len) != 0)) { + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); + exists = 0; + } + if (!exists && symlink(name, toname) < 0) + fail("cannot make symbolic link %s", toname); +#ifdef HAVE_LCHOWN + if ((owner || group) && lchown(toname, uid, gid) < 0) + fail("cannot change owner of %s", toname); +#endif + + if (linkname) { + free(linkname); + linkname = 0; + } + } else { + /* Copy from name to toname, which might be the same file. */ + fromfd = open(name, O_RDONLY); + if (fromfd < 0 || fstat(fromfd, &sb) < 0) + fail("cannot access %s", name); + if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0)) + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); + tofd = open(toname, O_CREAT | O_WRONLY, 0666); + if (tofd < 0) + fail("cannot create %s", toname); + + bp = buf; + while ((cc = read(fromfd, bp, sizeof buf)) > 0) { + while ((wc = write(tofd, bp, cc)) > 0) { + if ((cc -= wc) == 0) + break; + bp += wc; + } + if (wc < 0) + fail("cannot write to %s", toname); + } + if (cc < 0) + fail("cannot read from %s", name); + + if (ftruncate(tofd, sb.st_size) < 0) + fail("cannot truncate %s", toname); + /* + ** On OpenVMS we can't chmod() until the file is closed, and we + ** have to utime() last since fchown/chmod alter the timestamps. + */ +#ifndef VMS + if (dotimes) { + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + if (utime(toname, &utb) < 0) + fail("cannot set times of %s", toname); + } +#ifdef HAVE_FCHMOD + if (fchmod(tofd, mode) < 0) +#else + if (chmod(toname, mode) < 0) +#endif + fail("cannot change mode of %s", toname); +#endif + if ((owner || group) && fchown(tofd, uid, gid) < 0) + fail("cannot change owner of %s", toname); + + /* Must check for delayed (NFS) write errors on close. */ + if (close(tofd) < 0) + fail("cannot write to %s", toname); + close(fromfd); +#ifdef VMS + if (chmod(toname, mode) < 0) + fail("cannot change mode of %s", toname); + if (dotimes) { + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + if (utime(toname, &utb) < 0) + fail("cannot set times of %s", toname); + } +#endif + } + + free(toname); + } + + free(cwd); + free(todir); + return 0; +} + +/* +** Pathname subroutines. +** +** Brendan Eich, 8/29/95 +*/ + +char *program; + +void +fail(char *format, ...) +{ + int error; + va_list ap; + +#ifdef USE_REENTRANT_LIBC + R_STRERROR_INIT_R(); +#endif + + error = errno; + fprintf(stderr, "%s: ", program); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (error) + +#ifdef USE_REENTRANT_LIBC + R_STRERROR_R(errno); + fprintf(stderr, ": %s", r_strerror_r); +#else + fprintf(stderr, ": %s", strerror(errno)); +#endif + + putc('\n', stderr); + exit(1); +} + +char * +getcomponent(char *path, char *name) +{ + if (*path == '\0') + return 0; + if (*path == '/') { + *name++ = '/'; + } else { + do { + *name++ = *path++; + } while (*path != '/' && *path != '\0'); + } + *name = '\0'; + while (*path == '/') + path++; + return path; +} + +#ifdef UNIXWARE_READDIR_BUFFER_TOO_SMALL +/* Sigh. The static buffer in Unixware's readdir is too small. */ +struct dirent * readdir(DIR *d) +{ + static struct dirent *buf = NULL; +#define MAX_PATH_LEN 1024 + + + if(buf == NULL) + buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN) +; + return(readdir_r(d, buf)); +} +#endif + +char * +ino2name(ino_t ino, char *dir) +{ + DIR *dp; + struct dirent *ep; + char *name; + + dp = opendir(".."); + if (!dp) + fail("cannot read parent directory"); + for (;;) { + if (!(ep = readdir(dp))) + fail("cannot find current directory"); + if (ep->d_ino == ino) + break; + } + name = xstrdup(ep->d_name); + closedir(dp); + return name; +} + +void * +xmalloc(size_t size) +{ + void *p = malloc(size); + if (!p) + fail("cannot allocate %u bytes", size); + return p; +} + +char * +xstrdup(char *s) +{ + return strcpy((char*)xmalloc(strlen(s) + 1), s); +} + +char * +xbasename(char *path) +{ + char *cp; + + while ((cp = strrchr(path, '/')) && cp[1] == '\0') + *cp = '\0'; + if (!cp) return path; + return cp + 1; +} + +void +xchdir(char *dir) +{ + if (chdir(dir) < 0) + fail("cannot change directory to %s", dir); +} + +int +relatepaths(char *from, char *to, char *outpath) +{ + char *cp, *cp2; + int len; + char buf[NAME_MAX]; + + assert(*from == '/' && *to == '/'); + for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) + if (*cp == '\0') + break; + while (cp[-1] != '/') + cp--, cp2--; + if (cp - 1 == to) { + /* closest common ancestor is /, so use full pathname */ + len = strlen(strcpy(outpath, to)); + if (outpath[len] != '/') { + outpath[len++] = '/'; + outpath[len] = '\0'; + } + } else { + len = 0; + while ((cp2 = getcomponent(cp2, buf)) != 0) { + strcpy(outpath + len, "../"); + len += 3; + } + while ((cp = getcomponent(cp, buf)) != 0) { + sprintf(outpath + len, "%s/", buf); + len += strlen(outpath + len); + } + } + return len; +} + +void +reversepath(char *inpath, char *name, int len, char *outpath) +{ + char *cp, *cp2; + char buf[NAME_MAX]; + struct stat sb; + + cp = strcpy(outpath + PATH_MAX - (len + 1), name); + cp2 = inpath; + while ((cp2 = getcomponent(cp2, buf)) != 0) { + if (strcmp(buf, ".") == 0) + continue; + if (strcmp(buf, "..") == 0) { + if (stat(".", &sb) < 0) + fail("cannot stat current directory"); + name = ino2name(sb.st_ino, ".."); + len = strlen(name); + cp -= len + 1; + strcpy(cp, name); + cp[len] = '/'; + free(name); + xchdir(".."); + } else { + cp -= 3; + strncpy(cp, "../", 3); + xchdir(buf); + } + } + strcpy(outpath, cp); +} diff --git a/nsprpub/config/nspr-config.in b/nsprpub/config/nspr-config.in new file mode 100755 index 00000000000..a7d2b4fc392 --- /dev/null +++ b/nsprpub/config/nspr-config.in @@ -0,0 +1,143 @@ +#!/bin/sh + +prefix=@prefix@ + +major_version=@MOD_MAJOR_VERSION@ +minor_version=@MOD_MINOR_VERSION@ +patch_version=@MOD_PATCH_VERSION@ + +usage() +{ + cat <&2 +fi + +lib_nspr=yes +lib_plc=yes +lib_plds=yes + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + ;; + --prefix) + echo_prefix=yes + ;; + --exec-prefix=*) + exec_prefix=$optarg + ;; + --exec-prefix) + echo_exec_prefix=yes + ;; + --includedir=*) + includedir=$optarg + ;; + --includedir) + echo_includedir=yes + ;; + --libdir=*) + libdir=$optarg + ;; + --libdir) + echo_libdir=yes + ;; + --version) + echo ${major_version}.${minor_version}.${patch_version} + ;; + --cflags) + echo_cflags=yes + ;; + --libs) + echo_libs=yes + ;; + nspr) + lib_nspr=yes + ;; + plc) + lib_plc=yes + ;; + plds) + lib_plds=yes + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + +# Set variables that may be dependent upon other variables +if test -z "$exec_prefix"; then + exec_prefix=@exec_prefix@ +fi +if test -z "$includedir"; then + includedir=@includedir@ +fi +if test -z "$libdir"; then + libdir=@libdir@ +fi + +if test "$echo_prefix" = "yes"; then + echo $prefix +fi + +if test "$echo_exec_prefix" = "yes"; then + echo $exec_prefix +fi + +if test "$echo_includedir" = "yes"; then + echo $includedir +fi + +if test "$echo_libdir" = "yes"; then + echo $libdir +fi + +if test "$echo_cflags" = "yes"; then + echo -I$includedir +fi + +if test "$echo_libs" = "yes"; then + libdirs=-L$libdir + if test -n "$lib_plds"; then + libdirs="$libdirs -lplds${major_version}" + fi + if test -n "$lib_plc"; then + libdirs="$libdirs -lplc${major_version}" + fi + if test -n "$lib_nspr"; then + libdirs="$libdirs -lnspr${major_version}" + fi + os_ldflags="@LDFLAGS@" + for i in $os_ldflags ; do + if echo $i | grep \^-L >/dev/null; then + libdirs="$libdirs $i" + fi + done + echo $libdirs @OS_LIBS@ +fi + diff --git a/nsprpub/config/nspr.m4 b/nsprpub/config/nspr.m4 new file mode 100644 index 00000000000..d21df69783e --- /dev/null +++ b/nsprpub/config/nspr.m4 @@ -0,0 +1,82 @@ +# -*- tab-width: 4; -*- +# Configure paths for NSPR +# Public domain - Chris Seawood 2001-04-05 +# Based upon gtk.m4 (also PD) by Owen Taylor + +dnl AM_PATH_NSPR([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for NSPR, and define NSPR_CFLAGS and NSPR_LIBS +AC_DEFUN([AM_PATH_NSPR], +[dnl + +AC_ARG_WITH(nspr-prefix, + [ --with-nspr-prefix=PFX Prefix where NSPR is installed], + nspr_config_prefix="$withval", + nspr_config_prefix="") + +AC_ARG_WITH(nspr-exec-prefix, + [ --with-nspr-exec-prefix=PFX + Exec prefix where NSPR is installed], + nspr_config_exec_prefix="$withval", + nspr_config_exec_prefix="") + + if test -n "$nspr_config_exec_prefix"; then + nspr_config_args="$nspr_config_args --exec-prefix=$nspr_config_exec_prefix" + if test -z "$NSPR_CONFIG"; then + NSPR_CONFIG=$nspr_config_exec_prefix/bin/nspr-config + fi + fi + if test -n "$nspr_config_prefix"; then + nspr_config_args="$nspr_config_args --prefix=$nspr_config_prefix" + if test -z "$NSPR_CONFIG"; then + NSPR_CONFIG=$nspr_config_prefix/bin/nspr-config + fi + fi + + unset ac_cv_path_NSPR_CONFIG + AC_PATH_PROG(NSPR_CONFIG, nspr-config, no) + min_nspr_version=ifelse([$1], ,4.0.0,$1) + AC_MSG_CHECKING(for NSPR - version >= $min_nspr_version) + + no_nspr="" + if test "$NSPR_CONFIG" = "no"; then + no_nspr="yes" + else + NSPR_CFLAGS=`$NSPR_CONFIG $nspr_config_args --cflags` + NSPR_LIBS=`$NSPR_CONFIG $nspr_config_args --libs` + + nspr_config_major_version=`$NSPR_CONFIG $nspr_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + nspr_config_minor_version=`$NSPR_CONFIG $nspr_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + nspr_config_micro_version=`$NSPR_CONFIG $nspr_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + min_nspr_major_version=`echo $min_nspr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + min_nspr_minor_version=`echo $min_nspr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + min_nspr_micro_version=`echo $min_nspr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "$nspr_config_major_version" -ne "$min_nspr_major_version"; then + no_nspr="yes" + elif test "$nspr_config_major_version" -eq "$min_nspr_major_version" && + test "$nspr_config_minor_version" -lt "$min_nspr_minor_version"; then + no_nspr="yes" + elif test "$nspr_config_major_version" -eq "$min_nspr_major_version" && + test "$nspr_config_minor_version" -eq "$min_nspr_minor_version" && + test "$nspr_config_micro_version" -lt "$min_nspr_micro_version"; then + no_nspr="yes" + fi + fi + + if test -z "$no_nspr"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + fi + + + AC_SUBST(NSPR_CFLAGS) + AC_SUBST(NSPR_LIBS) + +]) diff --git a/nsprpub/config/nsprincl.mk.in b/nsprpub/config/nsprincl.mk.in new file mode 100644 index 00000000000..d56cc0248b2 --- /dev/null +++ b/nsprpub/config/nsprincl.mk.in @@ -0,0 +1,5 @@ +# Include in Makefiles to define NSPR variables + +NSPR_VERSION = @NSPR_VERSION@ +NSPR_LIB = -lnspr@NSPR_VERSION@ +NSPR_EXTRA_LIBS = @EXTRA_LIBS@ diff --git a/nsprpub/config/nsprincl.sh.in b/nsprpub/config/nsprincl.sh.in new file mode 100644 index 00000000000..be4e1450ca4 --- /dev/null +++ b/nsprpub/config/nsprincl.sh.in @@ -0,0 +1,5 @@ +# Include in shell scripts to define NSPR variables + +NSPR_VERSION=@NSPR_VERSION@ +NSPR_LIB=-lnspr$NSPR_VERSION +NSPR_EXTRA_LIBS="@EXTRA_LIBS@" diff --git a/nsprpub/config/pathsub.h b/nsprpub/config/pathsub.h new file mode 100644 index 00000000000..bf3fca31319 --- /dev/null +++ b/nsprpub/config/pathsub.h @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef pathsub_h___ +#define pathsub_h___ +/* +** Pathname subroutines. +** +** Brendan Eich, 8/29/95 +*/ +#include +#include + +#if SUNOS4 +#include "../pr/include/md/sunos4.h" +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +/* + * Just prevent stupidity + */ +#undef NAME_MAX +#define NAME_MAX 256 + +extern char *program; + +extern void fail(char *format, ...); +extern char *getcomponent(char *path, char *name); +extern char *ino2name(ino_t ino, char *dir); +extern void *xmalloc(size_t size); +extern char *xstrdup(char *s); +extern char *xbasename(char *path); +extern void xchdir(char *dir); + +/* Relate absolute pathnames from and to returning the result in outpath. */ +extern int relatepaths(char *from, char *to, char *outpath); + +/* XXX changes current working directory -- caveat emptor */ +extern void reversepath(char *inpath, char *name, int len, char *outpath); + +#endif /* pathsub_h___ */ diff --git a/nsprpub/config/prdepend.h b/nsprpub/config/prdepend.h new file mode 100644 index 00000000000..df72c56882d --- /dev/null +++ b/nsprpub/config/prdepend.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * A dummy header file that is a dependency for all the object files. + * Used to force a full recompilation of NSPR in Mozilla's Tinderbox + * depend builds. See comments in rules.mk. + */ + +#error "Do not include this header file." diff --git a/nsprpub/config/rules.mk b/nsprpub/config/rules.mk new file mode 100644 index 00000000000..d944a0cff76 --- /dev/null +++ b/nsprpub/config/rules.mk @@ -0,0 +1,527 @@ +#! gmake +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +################################################################################ +# We used to have a 4 pass build process. Now we do everything in one pass. +# +# export - Create generated headers and stubs. Publish public headers to +# dist//include. +# Create libraries. Publish libraries to dist//lib. +# Create programs. +# +# libs - obsolete. Now a synonym of "export". +# +# all - the default makefile target. Now a synonym of "export". +# +# install - Install headers, libraries, and programs on the system. +# +# Parameters to this makefile (set these before including): +# +# a) +# TARGETS -- the target to create +# (defaults to $LIBRARY $PROGRAM) +# b) +# DIRS -- subdirectories for make to recurse on +# (the 'all' rule builds $TARGETS $DIRS) +# c) +# CSRCS -- .c files to compile +# (used to define $OBJS) +# d) +# PROGRAM -- the target program name to create from $OBJS +# ($OBJDIR automatically prepended to it) +# e) +# LIBRARY -- the target library name to create from $OBJS +# ($OBJDIR automatically prepended to it) +# +################################################################################ + +ifndef topsrcdir +topsrcdir=$(MOD_DEPTH) +endif + +ifndef srcdir +srcdir=. +endif + +ifndef NSPR_CONFIG_MK +include $(topsrcdir)/config/config.mk +endif + +ifdef USE_AUTOCONF +ifdef CROSS_COMPILE +ifdef INTERNAL_TOOLS +CC=$(HOST_CC) +CCC=$(HOST_CXX) +CFLAGS=$(HOST_CFLAGS) +CXXFLAGS=$(HOST_CXXFLAGS) +LDFLAGS=$(HOST_LDFLAGS) +endif +endif +endif + +# +# This makefile contains rules for building the following kinds of +# libraries: +# - LIBRARY: a static (archival) library +# - SHARED_LIBRARY: a shared (dynamic link) library +# - IMPORT_LIBRARY: an import library, used only on Windows and OS/2 +# +# The names of these libraries can be generated by simply specifying +# LIBRARY_NAME and LIBRARY_VERSION. +# + +ifdef LIBRARY_NAME +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) + +# +# Win95, Win16, and OS/2 require library names conforming to the 8.3 rule. +# other platforms do not. +# +ifeq (,$(filter-out WIN95 OS2,$(OS_TARGET))) +LIBRARY = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION)_s.$(LIB_SUFFIX) +SHARED_LIBRARY = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) +IMPORT_LIBRARY = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX) +SHARED_LIB_PDB = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).pdb +else +LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_s.$(LIB_SUFFIX) +SHARED_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) +IMPORT_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX) +SHARED_LIB_PDB = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).pdb +endif + +else + +LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX) +ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1) +SHARED_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_shr.a +else +ifdef MKSHLIB +SHARED_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) +endif +endif + +endif +endif + +ifndef TARGETS +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY) +ifndef BUILD_OPT +ifdef MSC_VER +ifneq (,$(filter-out 1100 1200,$(MSC_VER))) +TARGETS += $(SHARED_LIB_PDB) +endif +endif +endif +else +TARGETS = $(LIBRARY) $(SHARED_LIBRARY) +endif +endif + +# +# OBJS is the list of object files. It can be constructed by +# specifying CSRCS (list of C source files) and ASFILES (list +# of assembly language source files). +# + +ifndef OBJS +OBJS = $(addprefix $(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix $(OBJDIR)/,$(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))) +endif + +ifeq ($(MOZ_OS2_TOOLS),VACPP) +EXTRA_LIBS := $(patsubst -l%,$(DIST)/lib/%.$(LIB_SUFFIX),$(EXTRA_LIBS)) +endif + +ALL_TRASH = $(TARGETS) $(OBJS) $(RES) $(filter-out . .., $(OBJDIR)) LOGS TAGS $(GARBAGE) \ + $(NOSUCHFILE) \ + so_locations + +ifeq ($(OS_ARCH),OpenVMS) +ALL_TRASH += $(wildcard *.c*_defines) +ifdef SHARED_LIBRARY +VMS_SYMVEC_FILE = $(SHARED_LIBRARY:.$(DLL_SUFFIX)=_symvec.opt) +VMS_SYMVEC_FILE_MODULE = $(srcdir)/$(LIBRARY_NAME)_symvec.opt +ALL_TRASH += $(VMS_SYMVEC_FILE) +endif +endif + +ifndef RELEASE_LIBS_DEST +RELEASE_LIBS_DEST = $(RELEASE_LIB_DIR) +endif + +ifdef DIRS +LOOP_OVER_DIRS = \ + @for d in $(DIRS); do \ + if test -d $$d; then \ + set -e; \ + echo "cd $$d; $(MAKE) $@"; \ + $(MAKE) -C $$d $@; \ + set +e; \ + else \ + echo "Skipping non-directory $$d..."; \ + fi; \ + done +endif + +################################################################################ + +all:: export + +export:: + +$(LOOP_OVER_DIRS) + +libs:: export + +clean:: + rm -rf $(OBJS) $(RES) so_locations $(NOSUCHFILE) $(GARBAGE) + +$(LOOP_OVER_DIRS) + +clobber:: + rm -rf $(OBJS) $(RES) $(TARGETS) $(filter-out . ..,$(OBJDIR)) $(GARBAGE) so_locations $(NOSUCHFILE) + +$(LOOP_OVER_DIRS) + +realclean clobber_all:: + rm -rf $(wildcard *.OBJ *.OBJD) dist $(ALL_TRASH) + +$(LOOP_OVER_DIRS) + +distclean:: + rm -rf $(wildcard *.OBJ *.OBJD) dist $(ALL_TRASH) $(DIST_GARBAGE) + +$(LOOP_OVER_DIRS) + +install:: $(RELEASE_BINS) $(RELEASE_HEADERS) $(RELEASE_LIBS) +ifdef RELEASE_BINS + $(NSINSTALL) -t -m 0755 $(RELEASE_BINS) $(DESTDIR)$(bindir) +endif +ifdef RELEASE_HEADERS + $(NSINSTALL) -t -m 0644 $(RELEASE_HEADERS) $(DESTDIR)$(includedir)/$(include_subdir) +endif +ifdef RELEASE_LIBS + $(NSINSTALL) -t -m 0755 $(RELEASE_LIBS) $(DESTDIR)$(libdir)/$(lib_subdir) +endif + +$(LOOP_OVER_DIRS) + +release:: export +ifdef RELEASE_BINS + @echo "Copying executable programs and scripts to release directory" + @if test -z "$(BUILD_NUMBER)"; then \ + echo "BUILD_NUMBER must be defined"; \ + false; \ + else \ + true; \ + fi + @if test ! -d $(RELEASE_BIN_DIR); then \ + rm -rf $(RELEASE_BIN_DIR); \ + $(NSINSTALL) -D $(RELEASE_BIN_DIR);\ + else \ + true; \ + fi + cp $(RELEASE_BINS) $(RELEASE_BIN_DIR) +endif +ifdef RELEASE_LIBS + @echo "Copying libraries to release directory" + @if test -z "$(BUILD_NUMBER)"; then \ + echo "BUILD_NUMBER must be defined"; \ + false; \ + else \ + true; \ + fi + @if test ! -d $(RELEASE_LIBS_DEST); then \ + rm -rf $(RELEASE_LIBS_DEST); \ + $(NSINSTALL) -D $(RELEASE_LIBS_DEST);\ + else \ + true; \ + fi + cp $(RELEASE_LIBS) $(RELEASE_LIBS_DEST) +endif +ifdef RELEASE_HEADERS + @echo "Copying header files to release directory" + @if test -z "$(BUILD_NUMBER)"; then \ + echo "BUILD_NUMBER must be defined"; \ + false; \ + else \ + true; \ + fi + @if test ! -d $(RELEASE_HEADERS_DEST); then \ + rm -rf $(RELEASE_HEADERS_DEST); \ + $(NSINSTALL) -D $(RELEASE_HEADERS_DEST);\ + else \ + true; \ + fi + cp $(RELEASE_HEADERS) $(RELEASE_HEADERS_DEST) +endif + +$(LOOP_OVER_DIRS) + +alltags: + rm -f TAGS tags + find . -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' \) -print | xargs etags -a + find . -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' \) -print | xargs ctags -a + +$(NFSPWD): + cd $(@D); $(MAKE) $(@F) + +$(PROGRAM): $(OBJS) + @$(MAKE_OBJDIR) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) $(OBJS) -Fe$@ -link $(LDFLAGS) $(OS_LIBS) $(EXTRA_LIBS) +ifdef MT + @if test -f $@.manifest; then \ + $(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ + rm -f $@.manifest; \ + fi +endif # MSVC with manifest tool +else # WINNT && !GCC +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(CC) $(OBJS) -Fe$@ $(LDFLAGS) $(OS_LIBS) $(EXTRA_LIBS) +else + $(CC) -o $@ $(CFLAGS) $(OBJS) $(LDFLAGS) +endif +endif # WINNT && !GCC +ifdef ENABLE_STRIP + $(STRIP) $@ +endif + +$(LIBRARY): $(OBJS) + @$(MAKE_OBJDIR) + rm -f $@ +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(AR) $(subst /,\\,$(OBJS)) $(AR_FLAGS) +else + $(AR) $(AR_FLAGS) $(OBJS) $(AR_EXTRA_ARGS) +endif + $(RANLIB) $@ + +ifeq ($(OS_TARGET), OS2) +$(IMPORT_LIBRARY): $(MAPFILE) + rm -f $@ + $(IMPLIB) $@ $(MAPFILE) +endif + +$(SHARED_LIBRARY): $(OBJS) $(RES) $(MAPFILE) + @$(MAKE_OBJDIR) + rm -f $@ +ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1) + echo "#!" > $(OBJDIR)/lib$(LIBRARY_NAME)_syms + nm -B -C -g $(OBJS) \ + | awk '/ [T,D] / {print $$3}' \ + | sed -e 's/^\.//' \ + | sort -u >> $(OBJDIR)/lib$(LIBRARY_NAME)_syms + $(LD) $(XCFLAGS) -o $@ $(OBJS) -bE:$(OBJDIR)/lib$(LIBRARY_NAME)_syms \ + -bM:SRE -bnoentry $(OS_LIBS) $(EXTRA_LIBS) +else # AIX 4.1 +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(LINK_DLL) -MAP $(DLLBASE) $(DLL_LIBS) $(EXTRA_LIBS) $(OBJS) $(RES) +ifdef MT + @if test -f $@.manifest; then \ + $(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;2; \ + rm -f $@.manifest; \ + fi +endif # MSVC with manifest tool +else # WINNT && !GCC +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(LINK_DLL) $(DLLBASE) $(OBJS) $(OS_LIBS) $(EXTRA_LIBS) $(MAPFILE) +else # !os2 vacpp +ifeq ($(OS_TARGET), OpenVMS) + @if test ! -f $(VMS_SYMVEC_FILE); then \ + if test -f $(VMS_SYMVEC_FILE_MODULE); then \ + echo Creating component options file $(VMS_SYMVEC_FILE); \ + cp $(VMS_SYMVEC_FILE_MODULE) $(VMS_SYMVEC_FILE); \ + fi; \ + fi +endif # OpenVMS + $(MKSHLIB) $(OBJS) $(RES) $(EXTRA_LIBS) +endif # OS2 vacpp +endif # WINNT && !GCC +endif # AIX 4.1 +ifdef ENABLE_STRIP + $(STRIP) $@ +endif + +ifeq ($(OS_ARCH),WINNT) +$(RES): $(RESNAME) + @$(MAKE_OBJDIR) +# The resource compiler does not understand the -U option. +ifdef NS_USE_GCC + $(RC) $(RCFLAGS) $(filter-out -U%,$(DEFINES)) $(INCLUDES:-I%=--include-dir %) -o $@ $< +else + $(RC) $(RCFLAGS) $(filter-out -U%,$(DEFINES)) $(INCLUDES) -Fo$@ $< +endif # GCC + @echo $(RES) finished +endif + +$(MAPFILE): $(LIBRARY_NAME).def + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH),SunOS) + grep -v ';-' $< | \ + sed -e 's,;+,,' -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,;,' > $@ +endif +ifeq ($(OS_ARCH),OS2) + echo LIBRARY $(LIBRARY_NAME)$(LIBRARY_VERSION) INITINSTANCE TERMINSTANCE > $@ + echo PROTMODE >> $@ + echo CODE LOADONCALL MOVEABLE DISCARDABLE >> $@ + echo DATA PRELOAD MOVEABLE MULTIPLE NONSHARED >> $@ + echo EXPORTS >> $@ +ifeq ($(MOZ_OS2_TOOLS),VACPP) + grep -v ';+' $< | grep -v ';-' | \ + sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' >> $@ +else + grep -v ';+' $< | grep -v ';-' | \ + sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' -e 's,\([\t ]*\),\1_,' | \ + awk 'BEGIN {ord=1;} { print($$0 " @" ord " RESIDENTNAME"); ord++;}' >> $@ + $(ADD_TO_DEF_FILE) +endif +endif + +# +# Translate source filenames to absolute paths. This is required for +# debuggers under Windows and OS/2 to find source files automatically. +# + +ifeq (,$(filter-out AIX OS2,$(OS_ARCH))) +NEED_ABSOLUTE_PATH = 1 +endif + +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) +NEED_ABSOLUTE_PATH = 1 +endif + +ifdef NEED_ABSOLUTE_PATH +PWD := $(shell pwd) +abspath = $(if $(findstring :,$(1)),$(1),$(if $(filter /%,$(1)),$(1),$(PWD)/$(1))) +endif + +$(OBJDIR)/%.$(OBJ_SUFFIX): %.cpp + @$(MAKE_OBJDIR) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CCC) -Fo$@ -c $(CCCFLAGS) $(call abspath,$<) +else +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(CCC) -Fo$@ -c $(CCCFLAGS) $(call abspath,$<) +else +ifdef NEED_ABSOLUTE_PATH + $(CCC) -o $@ -c $(CCCFLAGS) $(call abspath,$<) +else + $(CCC) -o $@ -c $(CCCFLAGS) $< +endif +endif +endif + +WCCFLAGS1 = $(subst /,\\,$(CFLAGS)) +WCCFLAGS2 = $(subst -I,-i=,$(WCCFLAGS1)) +WCCFLAGS3 = $(subst -D,-d,$(WCCFLAGS2)) +$(OBJDIR)/%.$(OBJ_SUFFIX): %.c + @$(MAKE_OBJDIR) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) -Fo$@ -c $(CFLAGS) $(call abspath,$<) +else +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(CC) -Fo$@ -c $(CFLAGS) $(call abspath,$<) +else +ifdef NEED_ABSOLUTE_PATH + $(CC) -o $@ -c $(CFLAGS) $(call abspath,$<) +else + $(CC) -o $@ -c $(CFLAGS) $< +endif +endif +endif + + +$(OBJDIR)/%.$(OBJ_SUFFIX): %.s + @$(MAKE_OBJDIR) + $(AS) -o $@ $(ASFLAGS) -c $< + +ifeq ($(MOZ_OS2_TOOLS),VACPP) +$(OBJDIR)/%.$(OBJ_SUFFIX): %.asm + @$(MAKE_OBJDIR) + $(AS) -Fdo:./$(OBJDIR) $(ASFLAGS) $< +endif + +%.i: %.c + $(CC) -C -E $(CFLAGS) $< > $*.i + +%: %.pl + rm -f $@; cp $< $@; chmod +x $@ + +# +# HACK ALERT +# +# The only purpose of this rule is to pass Mozilla's Tinderbox depend +# builds (http://tinderbox.mozilla.org/showbuilds.cgi). Mozilla's +# Tinderbox builds NSPR continuously as part of the Mozilla client. +# Because NSPR's make depend is not implemented, whenever we change +# an NSPR header file, the depend build does not recompile the NSPR +# files that depend on the header. +# +# This rule makes all the objects depend on a dummy header file. +# Touch this dummy header file to force the depend build to recompile +# everything. +# +# This rule should be removed when make depend is implemented. +# + +DUMMY_DEPEND_H = $(topsrcdir)/config/prdepend.h + +$(filter $(OBJDIR)/%.$(OBJ_SUFFIX),$(OBJS)): $(OBJDIR)/%.$(OBJ_SUFFIX): $(DUMMY_DEPEND_H) + +# END OF HACK + +################################################################################ +# Special gmake rules. +################################################################################ + +# +# Re-define the list of default suffixes, so gmake won't have to churn through +# hundreds of built-in suffix rules for stuff we don't need. +# +.SUFFIXES: +.SUFFIXES: .a .$(OBJ_SUFFIX) .c .cpp .s .h .i .pl + +# +# Fake targets. Always run these rules, even if a file/directory with that +# name already exists. +# +.PHONY: all alltags clean export install libs realclean release + +# +# List the target pattern of an implicit rule as a dependency of the +# special target .PRECIOUS to preserve intermediate files made by +# implicit rules whose target patterns match that file's name. +# (See GNU Make documentation, Edition 0.51, May 1996, Sec. 10.4, +# p. 107.) +# +.PRECIOUS: $(OBJDIR)/%.$(OBJ_SUFFIX) diff --git a/nsprpub/config/system-headers b/nsprpub/config/system-headers new file mode 100644 index 00000000000..cf0f11498f5 --- /dev/null +++ b/nsprpub/config/system-headers @@ -0,0 +1,172 @@ +Aliases.h +arpa/inet.h +assert.h +bsd/libc.h +bsd/syscall.h +bstring.h +builtin.h +c_asm.h +cf.h +CFBundle.h +CFData.h +CFDictionary.h +CFString.h +CFURL.h +CodeFragments.h +commdlg.h +crt_externs.h +crypt.h +ctype.h +descrip.h +Devices.h +direct.h +dirent.h +dlfcn.h +dl.h +DriverServices.h +dvidef.h +errno.h +Errors.h +Events.h +fcntl.h +fibdef.h +files.h +Files.h +float.h +Folders.h +Gestalt.h +getopt.h +grp.h +ia64/sys/inline.h +ifaddrs.h +image.h +ints.h +iodef.h +io.h +iostream.h +kernel/OS.h +lib$routines.h +limits.h +loader.h +locale.h +LowMem.h +MacErrors.h +machine/builtins.h +machine/clock.h +machine/endian.h +machine/inline.h +mach/mach_init.h +mach/mach_host.h +mach-o/dyld.h +MacTypes.h +Math64.h +math.h +mbstring.h +memory.h +MixedMode.h +model.h +mswsock.h +Multiprocessing.h +mutex.h +netdb.h +net/if.h +netinet/in.h +netinet/in_systm.h +netinet/tcp.h +OpenTptInternet.h +OpenTransport.h +os2.h +OS.h +osreldate.h +OSUtils.h +poll.h +PPCToolbox.h +Processes.h +process.h +pthread.h +pwd.h +QDOffscreen.h +Resources.h +rld_interface.h +rpc/types.h +semaphore.h +setjmp.h +share.h +signal.h +ssdef.h +starlet.h +stat.h +stdarg.h +stddef.h +stdio.h +stdlib.h +string.h +stropts.h +stsdef.h +support/SupportDefs.h +support/TLS.h +synch.h +sys/atomic_op.h +syscall.h +sys/cfgodm.h +sys/file.h +sys/filio.h +sys/immu.h +sys/ioctl.h +sys/ipc.h +sys/ldr.h +sys/locking.h +sys/lwp.h +sys/mman.h +sys/mpctl.h +sys/param.h +sys/pda.h +sys/poll.h +sys/prctl.h +sys/priv.h +sys/procfs.h +sys/pstat.h +sys/regset.h +sys/resource.h +sys/sched.h +sys/select.h +sys/sem.h +sys/sendfile.h +sys/shm.h +sys/socket.h +sys/stack.h +sys/stat.h +sys/statvfs.h +sys/syscall.h +sys/sysctl.h +sys/sysmp.h +sys/syssgi.h +sys/systeminfo.h +sys/timeb.h +sys/time.h +sys/times.h +sys/types.h +sys/ucontext.h +sys/uio.h +sys/utsname.h +sys/wait.h +task.h +TextUtils.h +thread.h +time.h +Timer.h +types.h +Types.h +ucontext.h +ucx$inetdef.h +ulocks.h +unistd.h +unix.h +unixlib.h +utime.h +wchar.h +winbase.h +win/compobj.h +windef.h +windows.h +winsock.h diff --git a/nsprpub/configure b/nsprpub/configure new file mode 100755 index 00000000000..9e23bb710e4 --- /dev/null +++ b/nsprpub/configure @@ -0,0 +1,6379 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-dist-prefix=DIST_PREFIX + place build files in DIST_PREFIX [dist]" +ac_help="$ac_help + --with-dist-bindir=DIR build execuatables in DIR [DIST_PREFIX/bin]" +ac_help="$ac_help + --with-dist-includedir=DIR + build include files in DIR [DIST_PREFIX/include/nspr]" +ac_help="$ac_help + --with-dist-libdir=DIR build library files in DIR [DIST_PREFIX/lib]" +ac_help="$ac_help + --with-mozilla Compile NSPR with Mozilla support" +ac_help="$ac_help + --enable-optimize(=val) Enable code optimizations (val, ie. -O2) " +ac_help="$ac_help + --disable-debug Do not compile in debugging symbols + --enable-debug(=val) Enable debugging (debug flags val)" +ac_help="$ac_help + --enable-win32-target=\$t + Specify win32 flavor. (WIN95 or WINNT)" +ac_help="$ac_help + --enable-debug-rtl Use the MSVC debug runtime library" +ac_help="$ac_help + --enable-n32 Enable n32 ABI support (IRIX only)" +ac_help="$ac_help + --enable-64bit Enable 64-bit support (on certain platforms)" +ac_help="$ac_help + --enable-mdupdate Enable use of certain compilers' mdupdate feature" +ac_help="$ac_help + --enable-cplus Enable some c++ api routines" +ac_help="$ac_help + --with-arm-kuser Use kuser helpers (Linux/ARM only) + (Requires kernel 2.6.13 or later)" +ac_help="$ac_help + --with-macos-sdk=dir Location of platform SDK to use (Mac OS X only)" +ac_help="$ac_help + --enable-macos-target=VER + Set the minimum MacOS version needed at runtime + [10.2 for ppc, 10.4 for x86]" +ac_help="$ac_help + --disable-os2-high-mem Disable high-memory support on OS/2" +ac_help="$ac_help + --enable-strip Enable stripping of shared libs and programs" +ac_help="$ac_help + --with-pthreads Use system pthreads library as thread subsystem" +ac_help="$ac_help + --enable-user-pthreads Build using userland pthreads" +ac_help="$ac_help + --enable-nspr-threads Build using classic nspr threads" +ac_help="$ac_help + --with-bthreads Use system bthreads library as thread subsystem + (BeOS only)" +ac_help="$ac_help + --with-native-threads Use native system threads as thread subsystem + (Solaris only)" +ac_help="$ac_help + --enable-ipv6 Compile ipv6 support" +ac_help="$ac_help + --enable-boehm Enable the Boehm Garbage Collector" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=config/libc_r.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in ${srcdir}/build/autoconf $srcdir/${srcdir}/build/autoconf; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in ${srcdir}/build/autoconf $srcdir/${srcdir}/build/autoconf" 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:632: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:653: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:671: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +MOD_MAJOR_VERSION=4 +MOD_MINOR_VERSION=7 +MOD_PATCH_VERSION=1 +NSPR_MODNAME=nspr20 +_HAVE_PTHREADS= +USE_PTHREADS= +USE_USER_PTHREADS= +USE_NSPR_THREADS= +USE_N32= +USE_64= +USE_CPLUS= +USE_IPV6= +USE_MDUPDATE= +_MACOSX_DEPLOYMENT_TARGET= +_OPTIMIZE_FLAGS=-O +_DEBUG_FLAGS=-g +MOZ_DEBUG=1 +MOZ_OPTIMIZE= +OBJDIR='$(OBJDIR_NAME)' +OBJDIR_NAME=. +OBJDIR_SUFFIX=OBJ +NSINSTALL='$(MOD_DEPTH)/config/$(OBJDIR_NAME)/nsinstall' +NOSUCHFILE=/no-such-file +LIBNSPR='-L$(dist_libdir) -lnspr$(MOD_MAJOR_VERSION)' +LIBPLC='-L$(dist_libdir) -lplc$(MOD_MAJOR_VERSION)' +CYGWIN_WRAPPER= +MACOS_SDK_DIR= +NEXT_ROOT= +MT= +MOZ_OS2_HIGH_MEMORY=1 + +RESOLVE_LINK_SYMBOLS= + +CFLAGS="${CFLAGS=}" +CXXFLAGS="${CXXFLAGS=}" +LDFLAGS="${LDFLAGS=}" +DLLFLAGS="${DLLFLAGS=}" +HOST_CFLAGS="${HOST_CFLAGS=}" +HOST_LDFLAGS="${HOST_LDFLAGS=}" + +case "$target" in +*-cygwin*|*-mingw*) + # Check to see if we are really running in a msvc environemnt + _WIN32_MSVC= + for ac_prog in cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:743: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CC" && break +done + + if test "$CC" = "cl"; then + echo 'main() { return 0; }' > dummy.c + ${CC} -o dummy dummy.c >/dev/null 2>&1 + if test $? = 0; then + _WIN32_MSVC=1 + CXX=$CC + else + echo "configure: warning: $(CC) test failed. Using normal feature tests" 1>&2 + fi + rm -f dummy dummy.o dummy.obj dummy.exe dummy.c + fi + ;; +*-msvc*) + _WIN32_MSVC=1 + ;; +*-mks*) + _WIN32_MSVC=1 + ;; +esac + +if test -n "$_WIN32_MSVC"; then + SKIP_PATH_CHECKS=1 + SKIP_COMPILER_CHECKS=1 + SKIP_LIBRARY_CHECKS=1 +fi + +dist_prefix='${MOD_DEPTH}/dist' +dist_bindir='${dist_prefix}/bin' +dist_includedir='${dist_prefix}/include/nspr' +dist_libdir='${dist_prefix}/lib' +if test "${includedir}" = '${prefix}/include'; then + includedir='${prefix}/include/nspr' +fi + +# Check whether --with-dist-prefix or --without-dist-prefix was given. +if test "${with_dist_prefix+set}" = set; then + withval="$with_dist_prefix" + dist_prefix=$withval +fi + + +# Check whether --with-dist-bindir or --without-dist-bindir was given. +if test "${with_dist_bindir+set}" = set; then + withval="$with_dist_bindir" + dist_bindir=$withval +fi + + +# Check whether --with-dist-includedir or --without-dist-includedir was given. +if test "${with_dist_includedir+set}" = set; then + withval="$with_dist_includedir" + dist_includedir=$withval +fi + + +# Check whether --with-dist-libdir or --without-dist-libdir was given. +if test "${with_dist_libdir+set}" = set; then + withval="$with_dist_libdir" + dist_libdir=$withval +fi + + + + + + + +# Check whether --with-mozilla or --without-mozilla was given. +if test "${with_mozilla+set}" = set; then + withval="$with_mozilla" + if test "$withval" = "yes"; then + cat >> confdefs.h <<\EOF +#define MOZILLA_CLIENT 1 +EOF + + MOZILLA_CLIENT=1 + else + MOZILLA_CLIENT= + fi +else + if test -n "$MOZILLA_CLIENT"; then + cat >> confdefs.h <<\EOF +#define MOZILLA_CLIENT 1 +EOF + + fi +fi + + +# Check whether --enable-optimize or --disable-optimize was given. +if test "${enable_optimize+set}" = set; then + enableval="$enable_optimize" + if test "$enableval" != "no"; then + MOZ_OPTIMIZE=1 + if test -n "$enableval" && test "$enableval" != "yes"; then + _OPTIMIZE_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + _SAVE_OPTIMIZE_FLAGS=$_OPTIMIZE_FLAGS + fi + else + MOZ_OPTIMIZE= + fi +fi + + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + if test "$enableval" = "no"; then + MOZ_DEBUG= + else + MOZ_DEBUG=1 + if test -n "$enableval" && test "$enableval" != "yes"; then + _DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + _SAVE_DEBUG_FLAGS=$_DEBUG_FLAGS + fi + fi +fi + + +# Check whether --enable-win32-target or --disable-win32-target was given. +if test "${enable_win32_target+set}" = set; then + enableval="$enable_win32_target" + OS_TARGET=`echo $enableval | tr a-z A-Z` +else + OS_TARGET= +fi + + +# Check whether --enable-debug-rtl or --disable-debug-rtl was given. +if test "${enable_debug_rtl+set}" = set; then + enableval="$enable_debug_rtl" + if test "$enableval" = "yes"; then + USE_DEBUG_RTL=1 + fi +fi + + +# Check whether --enable-n32 or --disable-n32 was given. +if test "${enable_n32+set}" = set; then + enableval="$enable_n32" + if test "$enableval" = "yes"; then + USE_N32=1 + else if test "$enableval" = "no"; then + USE_N32= + fi + fi +fi + + +# Check whether --enable-64bit or --disable-64bit was given. +if test "${enable_64bit+set}" = set; then + enableval="$enable_64bit" + if test "$enableval" = "yes"; then + USE_64=1 + fi +fi + + +# Check whether --enable-mdupdate or --disable-mdupdate was given. +if test "${enable_mdupdate+set}" = set; then + enableval="$enable_mdupdate" + if test "$enableval" = "yes"; then + USE_MDUPDATE=1 + fi +fi + + +# Check whether --enable-cplus or --disable-cplus was given. +if test "${enable_cplus+set}" = set; then + enableval="$enable_cplus" + if test "$enableval" = "yes"; then + USE_CPLUS=1 + fi +fi + + +# Check whether --with-arm-kuser or --without-arm-kuser was given. +if test "${with_arm_kuser+set}" = set; then + withval="$with_arm_kuser" + if test "$withval" = "yes"; then + cat >> confdefs.h <<\EOF +#define _PR_ARM_KUSER 1 +EOF + + fi +fi + + +# Check whether --with-macos-sdk or --without-macos-sdk was given. +if test "${with_macos_sdk+set}" = set; then + withval="$with_macos_sdk" + MACOS_SDK_DIR=$withval +fi + + +# Check whether --enable-macos-target or --disable-macos-target was given. +if test "${enable_macos_target+set}" = set; then + enableval="$enable_macos_target" + _MACOSX_DEPLOYMENT_TARGET=$enableval +fi + + +case "$target" in + +*-aix*) + case "${target_os}" in + aix3.2*) + USE_NSPR_THREADS=1 + ;; + *) + USE_PTHREADS=1 + ;; + esac + ;; + +esac + +if test -z "$CC"; then + case "$target" in + + *-aix*) + if test -z "$USE_NSPR_THREADS"; then + CC=xlc_r + else + CC=xlc + fi + ;; + + *-hpux*) + CC=cc + ;; + + *-irix*) + CC=cc + ;; + + *-openvms*) + CC=cc + ;; + + *-osf*) + CC=cc + ;; + + *-solaris*) + CC=cc + ;; + + esac +fi + +if test -z "$CXX"; then + case "$target" in + + *-aix*) + if test -z "$USE_NSPR_THREADS"; then + CXX=xlC_r + else + CXX=xlC + fi + ;; + + *-hpux*) + case "${target_os}" in + hpux10.30) + CXX=aCC + ;; + hpux11.*) + CXX=aCC + ;; + *) + CXX=CC + ;; + esac + ;; + + *-irix*) + CXX=CC + ;; + + *-openvms*) + CXX=cxx + ;; + + *-osf*) + CXX=cxx + ;; + + *-solaris*) + CXX=CC + ;; + + esac +fi + +if test -z "$SKIP_PATH_CHECKS"; then + # Extract the first word of "$WHOAMI whoami", so it can be a program name with args. +set dummy $WHOAMI whoami; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1071: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_WHOAMI'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$WHOAMI" in + /*) + ac_cv_path_WHOAMI="$WHOAMI" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_WHOAMI="$WHOAMI" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_WHOAMI="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_WHOAMI" && ac_cv_path_WHOAMI="echo not_whoami" + ;; +esac +fi +WHOAMI="$ac_cv_path_WHOAMI" +if test -n "$WHOAMI"; then + echo "$ac_t""$WHOAMI" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +fi + +if test -n "$MOZ_DEBUG"; then + cat >> confdefs.h <<\EOF +#define DEBUG 1 +EOF + + DEFINES="$DEFINES -UNDEBUG" + + case "${target_os}" in + beos*) + DEFINES="$DEFINES -DDEBUG_${USER}" + ;; + msvc*|mks*|cygwin*|mingw*|os2*) + DEFINES="$DEFINES -DDEBUG_`echo ${USERNAME} | sed -e 's| |_|g'`" + ;; + *) + DEFINES="$DEFINES -DDEBUG_`$WHOAMI`" + ;; + esac +else + cat >> confdefs.h <<\EOF +#define NDEBUG 1 +EOF + + DEFINES="$DEFINES -UDEBUG" +fi + +if test -z "$SKIP_COMPILER_CHECKS"; then +if test "$target" != "$host"; then + echo "cross compiling from $host to $target" + cross_compiling=yes + + _SAVE_CC="$CC" + _SAVE_CFLAGS="$CFLAGS" + _SAVE_LDFLAGS="$LDFLAGS" + + echo $ac_n "checking for $host compiler""... $ac_c" 1>&6 +echo "configure:1142: checking for $host compiler" >&5 + for ac_prog in $HOST_CC gcc cc /usr/ucb/cc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1148: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HOST_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HOST_CC"; then + ac_cv_prog_HOST_CC="$HOST_CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HOST_CC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +HOST_CC="$ac_cv_prog_HOST_CC" +if test -n "$HOST_CC"; then + echo "$ac_t""$HOST_CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$HOST_CC" && break +done +test -n "$HOST_CC" || HOST_CC="""" + + if test -z "$HOST_CC"; then + { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } + fi + echo "$ac_t""$HOST_CC" 1>&6 + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi + if test -z "$HOST_LDFLAGS"; then + HOST_LDFLAGS="$LDFLAGS" + fi + + CC="$HOST_CC" + CFLAGS="$HOST_CFLAGS" + LDFLAGS="$HOST_LDFLAGS" + + echo $ac_n "checking whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1194: checking whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works" >&5 + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_prog_host_cc_works=1 echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: installation or configuration problem: $host compiler $HOST_CC cannot create executables." 1>&2; exit 1; } +fi +rm -f conftest* + + CC=$_SAVE_CC + CFLAGS=$_SAVE_CFLAGS + LDFLAGS=$_SAVE_LDFLAGS + + case "$build:$target" in + powerpc-apple-darwin8*:i?86-apple-darwin*) + _SAVE_CFLAGS=$CFLAGS + _SAVE_CXXFLAGS=$CXXLAGS + CFLAGS="-isysroot /Developer/SDKs/MacOSX10.4u.sdk $CFLAGS" + CXXFLAGS="-isysroot /Developer/SDKs/MacOSX10.4u.sdk $CXXFLAGS" + ;; + esac + + for ac_prog in $CC "${target_alias}-gcc" "${target}-gcc" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1232: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CC" && break +done +test -n "$CC" || CC="echo" + + unset ac_cv_prog_CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1266: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1296: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1347: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1379: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1390 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:1395: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1421: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1426: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1454: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + if test -n "$USE_CPLUS"; then + for ac_prog in $CXX "${target_alias}-g++" "${target}-g++" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1491: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="echo" + + unset ac_cv_prog_CXX + for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1527: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="gcc" + + +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1559: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext << EOF + +#line 1570 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:1575: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cxx_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cxx_cross=no + else + ac_cv_prog_cxx_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cxx_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 +if test $ac_cv_prog_cxx_works = no; then + { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1601: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 +echo "configure:1606: checking whether we are using GNU C++" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gxx" 1>&6 + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:1634: checking whether ${CXX-g++} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi + + fi + + case "$build:$target" in + powerpc-apple-darwin8*:i?86-apple-darwin*) + CFLAGS=$_SAVE_CFLAGS + CXXFLAGS=$_SAVE_CXXFLAGS + ;; + esac + + for ac_prog in $RANLIB "${target_alias}-ranlib" "${target}-ranlib" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1679: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$RANLIB" && break +done +test -n "$RANLIB" || RANLIB="echo" + + for ac_prog in $AR "${target_alias}-ar" "${target}-ar" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1714: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AR" && break +done +test -n "$AR" || AR="echo" + + for ac_prog in $AS "${target_alias}-as" "${target}-as" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1749: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AS="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AS="$ac_cv_prog_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AS" && break +done +test -n "$AS" || AS="echo" + + for ac_prog in $LD "${target_alias}-ld" "${target}-ld" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1784: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LD"; then + ac_cv_prog_LD="$LD" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LD="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LD="$ac_cv_prog_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LD" && break +done +test -n "$LD" || LD="echo" + + for ac_prog in $STRIP "${target_alias}-strip" "${target}-strip" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1819: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_STRIP="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +STRIP="$ac_cv_prog_STRIP" +if test -n "$STRIP"; then + echo "$ac_t""$STRIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$STRIP" && break +done +test -n "$STRIP" || STRIP="echo" + + for ac_prog in $WINDRES "${target_alias}-windres" "${target}-windres" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1854: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$WINDRES"; then + ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_WINDRES="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +WINDRES="$ac_cv_prog_WINDRES" +if test -n "$WINDRES"; then + echo "$ac_t""$WINDRES" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$WINDRES" && break +done +test -n "$WINDRES" || WINDRES="echo" + + +else + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1889: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1919: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1970: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:2002: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 2013 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:2018: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:2044: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:2049: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:2077: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + if test -n "$USE_CPLUS"; then + if test "$CC" = "cl" -a -z "$CXX"; then + CXX=$CC + else + for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2117: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="gcc" + + +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:2149: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext << EOF + +#line 2160 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:2165: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cxx_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cxx_cross=no + else + ac_cv_prog_cxx_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cxx_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 +if test $ac_cv_prog_cxx_works = no; then + { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:2191: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 +echo "configure:2196: checking whether we are using GNU C++" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gxx" 1>&6 + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:2224: checking whether ${CXX-g++} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi + + fi + fi + echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:2258: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2279: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2296: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2313: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2340: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + for ac_prog in as +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2372: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$AS" in + /*) + ac_cv_path_AS="$AS" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_AS="$AS" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_AS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +AS="$ac_cv_path_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AS" && break +done +test -n "$AS" || AS="$CC" + + for ac_prog in ar +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2413: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$AR" in + /*) + ac_cv_path_AR="$AR" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_AR="$AR" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_AR="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +AR="$ac_cv_path_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AR" && break +done +test -n "$AR" || AR="echo not_ar" + + for ac_prog in ld link +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2454: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$LD" in + /*) + ac_cv_path_LD="$LD" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_LD="$LD" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_LD="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +LD="$ac_cv_path_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LD" && break +done +test -n "$LD" || LD="echo not_ld" + + for ac_prog in strip +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2495: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_STRIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$STRIP" in + /*) + ac_cv_path_STRIP="$STRIP" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_STRIP="$STRIP" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_STRIP="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +STRIP="$ac_cv_path_STRIP" +if test -n "$STRIP"; then + echo "$ac_t""$STRIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$STRIP" && break +done +test -n "$STRIP" || STRIP="echo not_strip" + + for ac_prog in windres +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2536: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_WINDRES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$WINDRES" in + /*) + ac_cv_path_WINDRES="$WINDRES" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_WINDRES="$WINDRES" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_WINDRES="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +WINDRES="$ac_cv_path_WINDRES" +if test -n "$WINDRES"; then + echo "$ac_t""$WINDRES" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$WINDRES" && break +done +test -n "$WINDRES" || WINDRES="echo not_windres" + + if test -z "$HOST_CC"; then + HOST_CC="$CC" + fi + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi +fi + +if test "$GCC" = "yes"; then + GNU_CC=1 +fi +if test "$GXX" = "yes"; then + GNU_CXX=1 +fi +if test "`echo | $AS -v 2>&1 | grep -c GNU`" != "0"; then + GNU_AS=1 +fi +rm -f a.out + +case "$build:$target" in + i?86-apple-darwin*:powerpc-apple-darwin*) + cross_compiling=yes + ;; +esac + +if test "$cross_compiling" = "yes"; then + CROSS_COMPILE=1 +else + CROSS_COMPILE= +fi + +echo $ac_n "checking for gcc -pipe support""... $ac_c" 1>&6 +echo "configure:2604: checking for gcc -pipe support" >&5 +if test -n "$GNU_CC" && test -n "$GNU_CXX" && test -n "$GNU_AS"; then + echo '#include ' > dummy-hello.c + echo 'int main() { printf("Hello World\n"); return 0; }' >> dummy-hello.c + ${CC} -S dummy-hello.c -o dummy-hello.s 2>&5 + cat dummy-hello.s | ${AS} -o dummy-hello.S - 2>&5 + if test $? = 0; then + _res_as_stdin="yes" + else + _res_as_stdin="no" + fi + if test "$_res_as_stdin" = "yes"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -pipe" + cat > conftest.$ac_ext < +int main() { +printf("Hello World\n"); +; return 0; } +EOF +if { (eval echo configure:2626: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + _res_gcc_pipe="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _res_gcc_pipe="no" +fi +rm -f conftest* + CFLAGS=$_SAVE_CFLAGS + fi + if test "$_res_as_stdin" = "yes" && test "$_res_gcc_pipe" = "yes"; then + _res="yes"; + CFLAGS="$CFLAGS -pipe" + CXXFLAGS="$CXXFLAGS -pipe" + else + _res="no" + fi + rm -f dummy-hello.c dummy-hello.s dummy-hello.S dummy-hello a.out + echo "$ac_t""$_res" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$GNU_CC"; then + echo $ac_n "checking for visibility(hidden) attribute""... $ac_c" 1>&6 +echo "configure:2653: checking for visibility(hidden) attribute" >&5 +if eval "test \"`echo '$''{'ac_cv_visibility_hidden'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c </dev/null 2>&1; then + if grep '\.hidden.*foo' conftest.s >/dev/null; then + ac_cv_visibility_hidden=yes + fi + fi + rm -f conftest.cs + +fi + +echo "$ac_t""$ac_cv_visibility_hidden" 1>&6 + if test "$ac_cv_visibility_hidden" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_VISIBILITY_HIDDEN_ATTRIBUTE 1 +EOF + + echo $ac_n "checking for visibility pragma support""... $ac_c" 1>&6 +echo "configure:2677: checking for visibility pragma support" >&5 +if eval "test \"`echo '$''{'ac_cv_visibility_pragma'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c </dev/null 2>&1; then + if grep '\.hidden.*foo_hidden' conftest.s >/dev/null; then + if ! grep '\.hidden.*foo_default' conftest.s > /dev/null; then + ac_cv_visibility_pragma=yes + fi + fi + fi + rm -f conftest.cs + +fi + +echo "$ac_t""$ac_cv_visibility_pragma" 1>&6 + if test "$ac_cv_visibility_pragma" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_VISIBILITY_PRAGMA 1 +EOF + + # To work around a build problem on Linux x86-64 (Bugzilla bug + # 293438), we use the -fvisibility=hidden flag. This flag is less + # optimal than #pragma GCC visibility push(hidden) because the flag + # assumes that symbols defined outside the current source file have + # the default visibility. This has the advantage that we don't need + # to wrap system header files, but has the disadvantage that calls + # to hidden symbols defined in other source files cannot be + # optimized by the compiler. The -fvisibility=hidden flag does + # hide and export symbols correctly. + #VISIBILITY_FLAGS='-I$(dist_includedir)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h' + #WRAP_SYSTEM_INCLUDES=1 + VISIBILITY_FLAGS="-fvisibility=hidden" + WRAP_SYSTEM_INCLUDES= + fi + fi +fi # GNU_CC + +fi # SKIP_COMPILER_CHECKS + +if test -z "$SKIP_PATH_CHECKS"; then + for ac_prog in perl5 perl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2730: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$PERL" in + /*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_PERL="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +PERL="$ac_cv_path_PERL" +if test -n "$PERL"; then + echo "$ac_t""$PERL" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$PERL" && break +done +test -n "$PERL" || PERL="echo not_perl" + +elif test -z "$PERL"; then + PERL=perl +fi + +OBJ_SUFFIX=o +LIB_SUFFIX=a +DLL_SUFFIX=so +ASM_SUFFIX=s +MKSHLIB='$(LD) $(DSO_LDOPTS) -o $@' +PR_MD_ASFILES= +PR_MD_CSRCS= +PR_MD_ARCH_DIR=unix +AR_FLAGS='cr $@' +AS='$(CC)' +ASFLAGS='$(CFLAGS)' + +if test -n "$CROSS_COMPILE"; then + OS_ARCH=`echo $target_os | sed -e 's|/|_|g'` + OS_RELEASE= + OS_TEST="${target_cpu}" + case "${target_os}" in + linux*) OS_ARCH=Linux ;; + solaris*) OS_ARCH=SunOS OS_RELEASE=5 ;; + mingw*) OS_ARCH=WINNT ;; + darwin*) OS_ARCH=Darwin ;; + esac +else + OS_ARCH=`uname -s | sed -e 's|/|_|g'` + OS_RELEASE=`uname -r` + OS_TEST=`uname -m` +fi + +if test "$OS_ARCH" = "IRIX64"; then + OS_ARCH=IRIX +fi + +if test "$OS_ARCH" = "AIX"; then + OS_RELEASE=`uname -v`.`uname -r` +fi + +if test "$OS_ARCH" = "FreeBSD"; then + OS_RELEASE=`echo $OS_RELEASE | sed 's/-.*//'` +fi + +if test "$OS_ARCH" = "Linux"; then + OS_RELEASE=`echo $OS_RELEASE | sed 's/-.*//'` + OS_RELEASE=`echo $OS_RELEASE | awk -F\. '{ print $1 "." $2 }'` +fi + +if test "$OS_ARCH" = "OpenVMS"; then + OS_RELEASE=`uname -v` +fi + +####################################################################### +# Master "Core Components" macros for getting the OS target # +####################################################################### + +# +# Note: OS_TARGET should be specified on the command line for gmake. +# When OS_TARGET=WIN95 is specified, then a Windows 95 target is built. +# The difference between the Win95 target and the WinNT target is that +# the WinNT target uses Windows NT specific features not available +# in Windows 95. The Win95 target will run on Windows NT, but (supposedly) +# at lesser performance (the Win95 target uses threads; the WinNT target +# uses fibers). +# +# When OS_TARGET=WIN16 is specified, then a Windows 3.11 (16bit) target +# is built. See: win16_3.11.mk for lots more about the Win16 target. +# +# If OS_TARGET is not specified, it defaults to $(OS_ARCH), i.e., no +# cross-compilation. +# + +# +# The following hack allows one to build on a WIN95 machine (as if +# s/he were cross-compiling on a WINNT host for a WIN95 target). +# It also accomodates for MKS's uname.exe. If you never intend +# to do development on a WIN95 machine, you don't need this hack. +# +case "$OS_ARCH" in +WIN95) + OS_ARCH=WINNT + OS_TARGET=WIN95 + ;; +Windows_95) + OS_ARCH=Windows_NT + OS_TARGET=WIN95 + ;; +Windows_98) + OS_ARCH=Windows_NT + OS_TARGET=WIN95 + ;; +CYGWIN_9*|CYGWIN_ME*) + OS_ARCH='CYGWIN_NT-4.0' + OS_TARGET=WIN95 + ;; +OS_2) + OS_ARCH=OS2 + OS_TARGET=OS2 + ;; +esac + +# +# On WIN32, we also define the variable CPU_ARCH. +# + +case "$OS_ARCH" in +WINNT) + CPU_ARCH=`uname -p` + if test "$CPU_ARCH" = "I386"; then + CPU_ARCH=x86 + fi + ;; +Windows_NT) +# +# If uname -s returns "Windows_NT", we assume that we are using +# the uname.exe in MKS toolkit. +# +# The -r option of MKS uname only returns the major version number. +# So we need to use its -v option to get the minor version number. +# Moreover, it doesn't have the -p option, so we need to use uname -m. +# + OS_ARCH=WINNT + OS_MINOR_RELEASE=`uname -v` + if test "$OS_MINOR_RELEASE" = "00"; then + OS_MINOR_RELEASE=0 + fi + OS_RELEASE="${OS_RELEASE}.${OS_MINOR_RELEASE}" + CPU_ARCH=`uname -m` + # + # MKS's uname -m returns "586" on a Pentium machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi + ;; +CYGWIN_NT*|MINGW*_NT*) +# +# If uname -s returns "CYGWIN_NT-4.0", we assume that we are using +# the uname.exe in the Cygwin tools. +# If uname -s returns MINGW32_NT-5.1, we assume that we are using +# the uname.exe in the MSYS tools. +# + OS_RELEASE=`expr $OS_ARCH : '.*NT-\(.*\)'` + OS_ARCH=WINNT + CPU_ARCH=`uname -m` + # + # Cygwin's uname -m returns "i686" on a Pentium Pro machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi + ;; +esac + +if test -n "$MOZILLA_CLIENT" && test "$OS_ARCH" = "WINNT"; then + OS_TARGET=WIN95 + if test -n "$MOZ_DEBUG"; then + USE_DEBUG_RTL=1 + fi +fi +if test -z "$OS_TARGET"; then + OS_TARGET=$OS_ARCH +fi +if test "$OS_TARGET" = "WIN95"; then + OS_RELEASE="4.0" +fi +if test "$OS_TARGET" = "WIN16"; then + OS_RELEASE= +fi +OS_CONFIG="${OS_TARGET}${OS_RELEASE}" + +# Check whether --enable-os2-high-mem or --disable-os2-high-mem was given. +if test "${enable_os2_high_mem+set}" = set; then + enableval="$enable_os2_high_mem" + if test "$enableval" = "no"; then + MOZ_OS2_HIGH_MEMORY= + else + MOZ_OS2_HIGH_MEMORY=1 + fi +fi + + +case "$host" in +*-mingw*) + NSINSTALL=nsinstall + ;; +*-cygwin*|*-msvc*|*-mks*) + NSINSTALL='$(CYGWIN_WRAPPER) nsinstall' + if test `echo "${PATH}" | grep -c \;` = 0; then + CYGWIN_WRAPPER='sh $(topsrcdir)/build/cygwin-wrapper' + fi + ;; +*-beos*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_BEOS -DBeOS -DBEOS -D_POSIX_SOURCE" + ;; +*os2*) + ;; +*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + ;; +esac + +case "$target" in + +*-aix*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define AIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + DSO_LDOPTS='-brtl -bnortllib -bM:SRE -bnoentry -bexpall -blibpath:/usr/lib:/lib' + ac_safe=`echo "sys/atomic_op.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for sys/atomic_op.h""... $ac_c" 1>&6 +echo "configure:2987: checking for sys/atomic_op.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2997: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define AIX_HAVE_ATOMIC_OP_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + + case "${target_os}" in + aix3.2*) + cat >> confdefs.h <<\EOF +#define AIX_RENAME_SELECT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + AIX_LINK_OPTS='-bnso -berok' + PR_MD_ASFILES=os_AIX.s + ;; + aix4.1*) + cat >> confdefs.h <<\EOF +#define AIX_TIMERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + cat >> confdefs.h <<\EOF +#define AIX4_1 1 +EOF + + MKSHLIB= + DSO_LDOPTS= + AIX_LINK_OPTS='-bnso -berok' + LIBNSPR='-L$(dist_libdir) -lnspr$(MOD_MAJOR_VERSION)_shr' + LIBPLC='-L$(dist_libdir) -lplc$(MOD_MAJOR_VERSION)_shr' + ;; + aix4.2*) + cat >> confdefs.h <<\EOF +#define AIX_TIMERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + aix4.3*) + cat >> confdefs.h <<\EOF +#define AIX_TIMERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define AIX4_3_PLUS 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + USE_IPV6=1 + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + *) + cat >> confdefs.h <<\EOF +#define AIX_TIMERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define AIX4_3_PLUS 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + USE_IPV6=1 + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + esac + CFLAGS="$CFLAGS -qro -qroconst" + AIX_WRAP='$(DIST)/lib/aixwrap.o' + AIX_TMP='./_aix_tmp.o' + if test -n "$USE_64"; then + MDCPUCFG_H=_aix64.cfg + OBJECT_MODE=64 + else + MDCPUCFG_H=_aix32.cfg + fi + PR_MD_CSRCS=aix.c + RESOLVE_LINK_SYMBOLS=1 + ;; + +*-beos*) + cat >> confdefs.h <<\EOF +#define XP_BEOS 1 +EOF + + cat >> confdefs.h <<\EOF +#define BeOS 1 +EOF + + cat >> confdefs.h <<\EOF +#define BEOS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + DSO_LDOPTS=-nostart + MDCPUCFG_H=_beos.cfg + USE_BTHREADS=1 + PR_MD_ARCH_DIR=beos + RESOLVE_LINK_SYMBOLS=1 + case "${target_cpu}" in + i*86) + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS='-gdwarf-2 -O0' + MKSHLIB='$(CCC) $(DSO_LDOPTS) -o $@' + echo $ac_n "checking for gethostbyaddr in -lbind""... $ac_c" 1>&6 +echo "configure:3154: checking for gethostbyaddr in -lbind" >&5 +ac_lib_var=`echo bind'_'gethostbyaddr | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lbind $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + OS_LIBS="$OS_LIBS -lbind -lsocket" +else + echo "$ac_t""no" 1>&6 +fi + + ;; + powerpc) + CC=mwcc + CCC=mwcc + LD=mwld + DSO_LDOPTS='-xms -export pragma -init _init_routine_ -term _term_routine_ -lroot -lnet /boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o /boot/develop/lib/ppc/start_dyn.o' + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS='-g -O0' + ;; + esac + ;; + +*-bsdi*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define BSDI 1 +EOF + + cat >> confdefs.h <<\EOF +#define NEED_BSDREGEX 1 +EOF + + + CFLAGS="$CFLAGS -Wall -Wno-format" + CXXFLAGS="$CXXFLAGS -Wall -Wno-format" + + if echo "$OS_TEST" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + elif echo "$OS_TEST" | grep -c sparc >/dev/null; then + CPU_ARCH=sparc + fi + + MDCPUCFG_H=_bsdi.cfg + PR_MD_CSRCS=bsdi.c + + DSO_LDOPTS=-r + + case "$target_os" in + bsdi1.1*) + cat >> confdefs.h <<\EOF +#define _PR_BSDI_JMPBUF_IS_ARRAY 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ONLY_ST_ATIME 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + MKSHLIB= + DSO_CFLAGS= + DSO_LDOPTS= + ;; + + bsdi2.1*) + cat >> confdefs.h <<\EOF +#define _PR_TIMESPEC_HAS_TS_SEC 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_BSDI_JMPBUF_IS_ARRAY 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_DLL 1 +EOF + + cat >> confdefs.h <<\EOF +#define USE_DLFCN 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIMESPEC 1 +EOF + + PR_MD_ASFILES=os_BSD_OS_386_2.s + ;; + + bsdi4.* | bsdi5.*) + cat >> confdefs.h <<\EOF +#define _PR_SELECT_CONST_TIMEVAL 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_BSDI_JMPBUF_IS_STRUCT 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_DLL 1 +EOF + + cat >> confdefs.h <<\EOF +#define USE_DLFCN 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIMESPEC 1 +EOF + + MKSHLIB='$(CC) -o $@ $(DSO_LDOPTS)' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname,$(@:$(OBJDIR)/%.so=%.so)' + STRIP="$STRIP -d" + case "$target_os" in + bsdi4.2* | bsdi4.3* | bsdi5.*) + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETPROTO_R 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETPROTO_R_POINTER 1 +EOF + + ;; + esac + ;; + *) + cat >> confdefs.h <<\EOF +#define _PR_SELECT_CONST_TIMEVAL 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_BSDI_JMPBUF_IS_STRUCT 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_DLL 1 +EOF + + cat >> confdefs.h <<\EOF +#define USE_DLFCN 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIMESPEC 1 +EOF + + ;; + esac + + ;; + +*-darwin*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define DARWIN 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + CFLAGS="$CFLAGS -Wmost -fno-common" + case "${target_cpu}" in + i*86*) + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + CPU_ARCH=i386 + PR_MD_ASFILES=os_Darwin_x86.s + ;; + *) + cat >> confdefs.h <<\EOF +#define ppc 1 +EOF + + CPU_ARCH=ppc + PR_MD_ASFILES=os_Darwin_ppc.s + ;; + esac + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-dynamiclib -compatibility_version 1 -current_version 1 -all_load -install_name @executable_path/$@ -headerpad_max_install_names' + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + STRIP="$STRIP -x -S" + DLL_SUFFIX=dylib + USE_PTHREADS=1 + MDCPUCFG_H=_darwin.cfg + PR_MD_CSRCS=darwin.c + + # Add Mac OS X support for loading CFM & CFBundle plugins + if test -f /System/Library/Frameworks/Carbon.framework/Carbon; then + cat >> confdefs.h <<\EOF +#define XP_MACOSX 1 +EOF + + OS_TARGET=MacOSX + + if test -n "$_MACOSX_DEPLOYMENT_TARGET" ; then + export MACOSX_DEPLOYMENT_TARGET=$_MACOSX_DEPLOYMENT_TARGET + elif test -z "$MACOSX_DEPLOYMENT_TARGET" ; then + case "${target_cpu}" in + powerpc*) + export MACOSX_DEPLOYMENT_TARGET=10.2 + ;; + i*86*) + export MACOSX_DEPLOYMENT_TARGET=10.4 + ;; + esac + fi + + + if test "$MACOS_SDK_DIR"; then + + if test ! -d "$MACOS_SDK_DIR"; then + { echo "configure: error: SDK not found. When using --with-macos-sdk, you must +specify a valid SDK. SDKs are installed when the optional cross-development +tools are selected during the Xcode/Developer Tools installation." 1>&2; exit 1; } + fi + + + CC_VERSION=`$CC -v 2>&1 | grep 'gcc version'` + GCC_VERSION_FULL=`echo $CC_VERSION | $PERL -pe 's/^.*gcc version ([^ ]*).*/$1/'` + GCC_VERSION=`echo $GCC_VERSION_FULL | $PERL -pe '(split(/\./))[0]>=4&&s/(^\d*\.\d*).*/$1/;'` + + GCC_VERSION_MAJOR=`echo $GCC_VERSION_FULL | $PERL -pe 's/(^\d*).*/$1/;'` + if test "$GCC_VERSION_MAJOR" -lt "4" ; then + SDK_C_FRAMEWORK="-F${MACOS_SDK_DIR}/System/Library/Frameworks" + if test -d "${MACOS_SDK_DIR}/Library/Frameworks" ; then + SDK_C_FRAMEWORK="$SDK_C_FRAMEWORK -F${MACOS_SDK_DIR}/Library/Frameworks" + fi + + SDK_C_INCLUDE="-isystem ${MACOS_SDK_DIR}/usr/include/gcc/darwin/${GCC_VERSION} -isystem ${MACOS_SDK_DIR}/usr/include ${SDK_C_FRAMEWORK}" + + CFLAGS="$CFLAGS -nostdinc ${SDK_C_INCLUDE}" + + CPP="$CPP -nostdinc ${SDK_C_INCLUDE}" + + + HOST_DARWIN_MAJOR=`echo "$build_os" | sed -E -e 's/^darwin([0-9]+).*$/\1/'` + + if test "$HOST_DARWIN_MAJOR" -lt 9 ; then + MACOS_SDK_LIBS="-L${MACOS_SDK_DIR}/usr/lib/gcc/darwin -L${MACOS_SDK_DIR}/usr/lib/gcc/darwin/${GCC_VERSION_FULL} -L${MACOS_SDK_DIR}/usr/lib ${SDK_C_FRAMEWORK}" + else + MACOS_SDK_LIBS="-Wl,-syslibroot,${MACOS_SDK_DIR}" + fi + + LDFLAGS="${MACOS_SDK_LIBS} $LDFLAGS" + DSO_LDOPTS="${MACOS_SDK_LIBS} $DSO_LDOPTS" + export NEXT_ROOT=$MACOS_SDK_DIR + + if test -n "$CROSS_COMPILE" ; then + HOST_CC="NEXT_ROOT= $HOST_CC" + HOST_CXX="NEXT_ROOT= $HOST_CXX" + fi + else + CFLAGS="$CFLAGS -isysroot ${MACOS_SDK_DIR}" + + CPP="$CPP -isysroot ${MACOS_SDK_DIR}" + + if test "$GCC_VERSION_FULL" != "4.0.0" ; then + LDFLAGS="$LDFLAGS -isysroot ${MACOS_SDK_DIR}" + DSO_LDOPTS="$DSO_LDOPTS -isysroot ${MACOS_SDK_DIR}" + else + LDFLAGS="$LDFLAGS -Wl,-syslibroot,${MACOS_SDK_DIR}" + DSO_LDOPTS="$DSO_LDOPTS -Wl,-syslibroot,${MACOS_SDK_DIR}" + fi + fi + fi + fi + ;; + +*-dgux*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define DGUX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _DGUX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX4A_DRAFT6_SOURCE 1 +EOF + + DSO_LDOPTS=-G + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS= + MDCPUCFG_H=_dgux.cfg + PR_MD_CSRCS=dgux.c + ;; + +*-freebsd*) + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + fi + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define FREEBSD 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + CFLAGS="$CFLAGS $(DSO_CFLAGS) -ansi -Wall" + MOZ_OBJFORMAT=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + if test "$MOZ_OBJFORMAT" = "elf"; then + DLL_SUFFIX=so + else + DLL_SUFFIX=so.1.0 + fi + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' + MDCPUCFG_H=_freebsd.cfg + PR_MD_CSRCS=freebsd.c + ;; + +*-hpux*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _HPUX_SOURCE 1 +EOF + + # OSF1 and HPUX report the POLLHUP event for a socket when the + # shutdown(SHUT_WR) operation is called for the remote end, even though + # the socket is still writeable. Use select(), instead of poll(), to + # workaround this problem. + cat >> confdefs.h <<\EOF +#define _PR_POLL_WITH_SELECT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _USE_BIG_FDS 1 +EOF + + DSO_LDOPTS='-b +h $(notdir $@)' + PR_MD_CSRCS=hpux.c + if test "$OS_TEST" = "ia64"; then + DLL_SUFFIX=so + DSO_LDOPTS="$DSO_LDOPTS +b '\$\$ORIGIN'" + CPU_ARCH_TAG=_$OS_TEST + if test -z "$USE_64"; then + COMPILER_TAG=_32 + fi + PR_MD_ASFILES=os_HPUX_ia64.s + else + cat >> confdefs.h <<\EOF +#define hppa 1 +EOF + + DLL_SUFFIX=sl + PR_MD_ASFILES=os_HPUX.s + fi + if test -n "$USE_64"; then + MDCPUCFG_H=_hpux64.cfg + else + MDCPUCFG_H=_hpux32.cfg + fi + if test -z "$GNU_CC"; then + CC="$CC -Ae" + CXX="$CXX -ext" + DSO_CFLAGS=+Z + else + DSO_CFLAGS=-fPIC + fi + + if test -n "$MOZILLA_CLIENT"; then + DEFAULT_IMPL_STRATEGY=_EMU + fi + + if echo "$OS_RELEASE" | grep ^A.09 >/dev/null; then + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX9 1 +EOF + + DEFAULT_IMPL_STRATEGY=_EMU + USE_NSPR_THREADS=1 + fi + + if echo "$OS_RELEASE" | egrep '^(A.09|B.10)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define HAVE_INT_LOCALTIME_R 1 +EOF + + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.30|B.11)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + + # HP-UX 11i v2 (B.11.23) or higher + + case "$OS_RELEASE" in + [C-Z]*|B.[2-9]*|B.1[2-9]*|B.11.[3-9]*|B.11.2[3-9]*) + USE_IPV6=1 + ;; + esac + + + if test "$OS_RELEASE" = "B.10.01"; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + DEFAULT_IMPL_STRATEGY=_EMU + fi + + if test "$OS_RELEASE" = "B.10.10"; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX10_10 1 +EOF + + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$OS_RELEASE" = "B.10.20"; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX10_20 1 +EOF + + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS +DAportable +DS1.1" + CXXFLAGS="$CXXFLAGS +DAportable +DS1.1" + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$OS_RELEASE" = "B.10.30"; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX10_30 1 +EOF + + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS +DAportable +DS1.1" + CXXFLAGS="$CXXFLAGS +DAportable +DS1.1" + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if echo "$OS_RELEASE" | grep ^B.11 >/dev/null; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX11 1 +EOF + + cat >> confdefs.h <<\EOF +#define _LARGEFILE64_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + if test -z "$GNU_CC"; then + if test -z "$USE_64"; then + if test "$OS_TEST" = "ia64"; then + CFLAGS="$CFLAGS +DD32" + CXXFLAGS="$CXXFLAGS +DD32" + else + CFLAGS="$CFLAGS +DAportable +DS2.0" + CXXFLAGS="$CXXFLAGS +DAportable +DS2.0" + fi + else + if test "$OS_TEST" = "ia64"; then + CFLAGS="$CFLAGS +DD64" + CXXFLAGS="$CXXFLAGS +DD64" + else + CFLAGS="$CFLAGS +DA2.0W +DS2.0" + CXXFLAGS="$CXXFLAGS +DA2.0W +DS2.0" + fi + fi + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$DEFAULT_IMPL_STRATEGY" = "_EMU"; then + USE_NSPR_THREADS=1 + USE_PTHREADS= + USE_USER_THREADS= + elif test "$DEFAULT_IMPL_STRATEGY" = "_PTH"; then + USE_PTHREADS=1 + if test "$USE_NSPR_THREADS"; then + USE_PTHREADS= + fi + if test "$USE_USER_PTHREADS"; then + USE_PTHREADS= + fi + fi + ;; + +*-irix*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define IRIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define _SGI_MP_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + PR_MD_CSRCS=irix.c + PR_MD_ASFILES=os_Irix.s + MKSHLIB='$(LD) $(DSO_LDOPTS) -rdata_shared -shared -soname $(notdir $@) -o $@' + STRIP="$STRIP -f" + RESOLVE_LINK_SYMBOLS=1 + if test -n "$USE_64"; then + MDCPUCFG_H=_irix64.cfg + else + MDCPUCFG_H=_irix32.cfg + fi + case "${target_os}" in + irix6*) + cat >> confdefs.h <<\EOF +#define IRIX6 1 +EOF + + USE_PTHREADS=1 + USE_N32=1 + COMPILER_TAG=_n32 + IMPL_STRATEGY=_PTH + ;; + irix5*) + cat >> confdefs.h <<\EOF +#define IRIX5 1 +EOF + + USE_NSPR_THREADS=1 + ;; + *) + USE_PTHREADS=1 + USE_N32=1 + ;; + esac + if test "$GNU_CC"; then + AS='$(CC) -Wp,-P -x assembler-with-cpp -D_ASM -mips2 $(INCLUDES)' + CFLAGS="$CFLAGS -Wall -Wno-format" + _OPTIMIZE_FLAGS="-O6" + else + if test -n "$USE_N32"; then + AS='as -D_ASM $(INCLUDES) -n32' + else + AS='as -D_ASM $(INCLUDES)' + fi + CFLAGS="$CFLAGS -fullwarn -xansi" + if test "$USE_N32"; then + _OPTIMIZE_FLAGS="-O -OPT:Olimit=4000" + else + _OPTIMIZE_FLAGS="-O -Olimit 4000" + fi + if test "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + fi + case "${target}" in + *-irix6.*) + CFLAGS="$CFLAGS -multigot" + DSO_LDOPTS="-no_unresolved" + if test "$USE_N32"; then + CFLAGS="$CFLAGS -n32 -woff 1209" + DSO_LDOPTS="$DSO_LDOPTS -n32" + else + if test "$USE_64"; then + CFLAGS="$CFLAGS -64" + else + CFLAGS="$CFLAGS -32" + fi + fi + ;; + *) + CFLAGS="$CFLAGS -xgot" + ;; + esac + fi + if test "${target_os}" = "irix5.3"; then + cat >> confdefs.h <<\EOF +#define IRIX5_3 1 +EOF + + fi + case "${target_os}" in + irix6.5) + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS -mips3" + fi + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETPROTO_R 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETPROTO_R_POINTER 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_SGI_PRDA_PROCMASK 1 +EOF + + ;; + irix5*) + ;; + *) + cat >> confdefs.h <<\EOF +#define _PR_HAVE_SGI_PRDA_PROCMASK 1 +EOF + + ;; + esac + ;; + +*-linux*|*-gnu*|*-k*bsd*-gnu) + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + IMPL_STRATEGY=_PTH + fi + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _GNU_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + case "${target_os}" in + linux*) + cat >> confdefs.h <<\EOF +#define LINUX 1 +EOF + + ;; + esac + CFLAGS="$CFLAGS -Wall" + CXXFLAGS="$CXXFLAGS -Wall" + MDCPUCFG_H=_linux.cfg + PR_MD_CSRCS=linux.c + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS="-g -fno-inline" # most people on linux use gcc/gdb, and that + # combo is not yet good at debugging inlined + # functions (even when using DWARF2 as the + # debugging format) + COMPILER_TAG=_glibc + if echo "$OS_TEST" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + else + CPU_ARCH=$OS_TEST + fi + CPU_ARCH_TAG=_${CPU_ARCH} + case "${target_cpu}" in + alpha) + cat >> confdefs.h <<\EOF +#define _ALPHA_ 1 +EOF + + cat >> confdefs.h <<\EOF +#define __alpha 1 +EOF + + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + ;; + i*86) + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + PR_MD_ASFILES=os_Linux_x86.s + ;; + ia64) + PR_MD_ASFILES=os_Linux_ia64.s + ;; + x86_64) + if test -n "$USE_64"; then + PR_MD_ASFILES=os_Linux_x86_64.s + else + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + PR_MD_ASFILES=os_Linux_x86.s + CC="$CC -m32" + CXX="$CXX -m32" + fi + ;; + ppc|powerpc) + PR_MD_ASFILES=os_Linux_ppc.s + ;; + powerpc64) + if test -n "$USE_64"; then + CC="$CC -m64" + CXX="$CXX -m64" + else + PR_MD_ASFILES=os_Linux_ppc.s + fi + ;; + m68k) + CFLAGS="$CFLAGS -m68020-60" + CXXFLAGS="$CXXFLAGS -m68020-60" + ;; + esac + ;; + +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + cat >> confdefs.h <<\EOF +#define XP_PC 1 +EOF + + cat >> confdefs.h <<\EOF +#define WIN32 1 +EOF + + PR_MD_ARCH_DIR=windows + RESOLVE_LINK_SYMBOLS=1 + + if test -n "$GNU_CC"; then + CC="$CC -mno-cygwin" + CXX="$CXX -mno-cygwin" + DLL_SUFFIX=dll + MKSHLIB='$(CC) -shared -Wl,--export-all-symbols -Wl,--out-implib -Wl,$(IMPORT_LIBRARY) $(DLLBASE) -o $(subst $(OBJDIR)/,,$(SHARED_LIBRARY))' + RC=$WINDRES + # Use temp file for windres (bug 213281) + RCFLAGS='-O coff --use-temp-file' + else + CC=cl + CXX=cl + LD=link + AR='lib -NOLOGO -OUT:"$@"' + AR_FLAGS= + RANLIB='echo not_ranlib' + STRIP='echo not_strip' + RC=rc.exe + GARBAGE='$(OBJDIR)/vc20.pdb $(OBJDIR)/vc40.pdb' + OBJ_SUFFIX=obj + LIB_SUFFIX=lib + DLL_SUFFIX=dll + + # Determine compiler version + CC_VERSION=`"${CC}" -v 2>&1 | grep Version | sed -e 's|.* Version ||' -e 's| .*||'` + _CC_MAJOR_VERSION=`echo $CC_VERSION | awk -F\. '{ print $1 }'` + _CC_MINOR_VERSION=`echo $CC_VERSION | awk -F\. '{ print $2 }'` + MSC_VER=${_CC_MAJOR_VERSION}${_CC_MINOR_VERSION} + + # Ensure that mt is Microsoft (R) Manifest Tool and not magnetic + # tape manipulation utility (or something else) + if test "$MSC_VER" -ge "1400"; then + + _MSMT_VER_FILTER='s|.* \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p' + + + MSMT_TOOL=`mt 2>&1|grep 'Microsoft (R) Manifest Tool'` + if test -n "$MSMT_TOOL"; then + MSMANIFEST_TOOL_VERSION=`echo ${MSMT_TOOL}|sed -ne "$_MSMT_VER_FILTER"` + if test -z "$MSMANIFEST_TOOL_VERSION"; then + echo "configure: warning: Unknown version of the Microsoft (R) Manifest Tool." 1>&2 + fi + MT=mt + unset MSMT_TOOL + else + { echo "configure: error: Microsoft (R) Manifest Tool must be in your \$PATH." 1>&2; exit 1; } + fi + fi + + CFLAGS="$CFLAGS -W3 -nologo -GF -Gy" + DLLFLAGS="$DLLFLAGS -OUT:\"\$@\"" + _DEBUG_FLAGS=-Z7 + _OPTIMIZE_FLAGS=-O2 + if test -z "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS -Od" + fi + + if test -n "$USE_DEBUG_RTL"; then + CFLAGS="$CFLAGS -MDd" + else + CFLAGS="$CFLAGS -MD" + fi + + if test -n "$MOZ_DEBUG"; then + cat >> confdefs.h <<\EOF +#define _DEBUG 1 +EOF + + else + DEFINES="$DEFINES -U_DEBUG" + fi + + if test -n "$MOZ_OPTIMIZE"; then + if test -n "$MOZ_PROFILE"; then + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Z7" + fi + if test -n "$MOZ_DEBUG_SYMBOLS"; then + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Zi" + fi + if test -n "$MOZ_PROFILE" -o -n "$MOZ_DEBUG_SYMBOLS"; then + DLLFLAGS="$DLLFLAGS -DEBUG -OPT:REF" + LDFLAGS="$LDFLAGS -DEBUG -OPT:REF" + fi + fi + + if test -n "$MOZ_DEBUG"; then + DLLFLAGS="$DLLFLAGS -DEBUG" + LDFLAGS="$LDFLAGS -DEBUG" + fi + + OS_DLLFLAGS="-nologo -DLL -SUBSYSTEM:WINDOWS" + if test "$MSC_VER" -le "1200" -a -z "$MOZ_DEBUG_SYMBOLS"; then + OS_DLLFLAGS="$OS_DLLFLAGS -PDB:NONE" + fi + + if test "$OS_TARGET" = "WINNT"; then + CFLAGS="$CFLAGS -GT" + LIBNSPR='$(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + else + LIBNSPR='$(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + fi + fi # GNU_CC + + if test -n "$USE_STATIC_TLS"; then + cat >> confdefs.h <<\EOF +#define _PR_USE_STATIC_TLS 1 +EOF + + fi + + if test "$OS_TARGET" = "WINNT"; then + cat >> confdefs.h <<\EOF +#define WINNT 1 +EOF + + else + cat >> confdefs.h <<\EOF +#define WIN95 1 +EOF + + # undefine WINNT as some versions of mingw gcc define it by default + DEFINES="$DEFINES -UWINNT" + cat >> confdefs.h <<\EOF +#define _PR_GLOBAL_THREADS_ONLY 1 +EOF + + fi + + if test "$CPU_ARCH" = "x86"; then + CPU_ARCH_TAG= + else + CPU_ARCH_TAG=$CPU_ARCH + fi + + if test -n "$USE_DEBUG_RTL"; then + OBJDIR_SUFFIX=OBJD + fi + + case "$OS_TARGET" in + WINNT) + MDCPUCFG_H=_winnt.cfg + ;; + WIN95) + MDCPUCFG_H=_win95.cfg + ;; + WIN16) + MDCPUCFG_H=_win16.cfg + ;; + *) + { echo "configure: error: Missing OS_TARGET for ${target}. Use --enable-win32-target to set." 1>&2; exit 1; } + ;; + esac + + case "$target_cpu" in + i*86) + if test -n "$USE_64"; then + cat >> confdefs.h <<\EOF +#define _AMD64_ 1 +EOF + + cat >> confdefs.h <<\EOF +#define _M_AMD64 1 +EOF + + else + cat >> confdefs.h <<\EOF +#define _X86_ 1 +EOF + + fi + ;; + alpha) + cat >> confdefs.h <<\EOF +#define _ALPHA_ 1 +EOF + + ;; + mips) + cat >> confdefs.h <<\EOF +#define _MIPS_ 1 +EOF + + ;; + x86_64) + cat >> confdefs.h <<\EOF +#define _AMD64_ 1 +EOF + + cat >> confdefs.h <<\EOF +#define _M_AMD64 1 +EOF + + USE_64=1 + ;; + ia64) + cat >> confdefs.h <<\EOF +#define _IA64_ 1 +EOF + + cat >> confdefs.h <<\EOF +#define _M_IA64 1 +EOF + + USE_64=1 + ;; + *) + cat >> confdefs.h <<\EOF +#define _CPU_ARCH_NOT_DEFINED 1 +EOF + + ;; + esac + + if test "$USE_64"; then + cat >> confdefs.h <<\EOF +#define _WIN64 1 +EOF + + fi + + ;; + +*-ncr-sysv*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define NCR 1 +EOF + + USE_NSPR_THREADS=1 + if test "$OS_RELEASE" = "2.03"; then + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIM 1 +EOF + + else + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIM_UNION 1 +EOF + + fi + + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS -Hnocopyr" + CXXFLAGS="$CXXFLAGS -Hnocopyr" + else + CFLAGS="$CFLAGS -fPIC -Wall" + CXXFLAGS="$CXXFLAGS -fPIC -Wall" + DSO_LDOPTS=-G + fi + MDCPUCFG_H=_ncr.cfg + PR_MD_CSRCS=ncr.c + ;; + +mips-nec-sysv*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define __SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define NEC 1 +EOF + + cat >> confdefs.h <<\EOF +#define nec_ews 1 +EOF + + USE_NSPR_THREADS=1 + if test -z "$GNU_CC"; then + CC='$(NSDEPTH)/build/hcc cc -Xa -KGnum=0 -KOlimit=4000' + CXX=g++ + fi + OS_LIBS="$OS_LIBS -lsocket -lnsl -ldl" + DSO_LDOPTS=-G + MDCPUCFG_H=_nec.cfg + PR_MD_CSRCS=nec.c + ;; + +*-netbsd*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define NETBSD 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + USE_NSPR_THREADS=1 + MDCPUCFG_H=_netbsd.cfg + PR_MD_CSRCS=netbsd.c + + DSO_CFLAGS='-fPIC -DPIC' + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + MKSHLIB='$(CC) -o $@ $(DSO_LDOPTS)' + + if test -z "$OBJECT_FMT"; then + if echo __ELF__ | ${CC-cc} -E - | grep -q __ELF__ 2>/dev/null; then + OBJECT_FMT=a.out + DLL_SUFFIX=so.1.0 + DSO_LDOPTS='-shared' + else + OBJECT_FMT=ELF + DLL_SUFFIX=so + DSO_LDOPTS='-shared -Wl,-soname,$(notdir $@)' + fi + fi + + if test "$LIBRUNPATH"; then + DSO_LDOPTS="$DSO_LDOPTS -Wl,-R$LIBRUNPATH" + fi + ;; + +mips-sony-newsos*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SONY 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define __svr4 1 +EOF + + cat >> confdefs.h <<\EOF +#define __svr4__ 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SVID_GETTOD 1 +EOF + + USE_NSPR_THREADS=1 + CFLAGS="$CFLAGS -Xa -fullwarn" + CXXFLAGS="$CXXFLAGS -Xa -fullwarn" + DSO_LDOPTS=-G + MDCPUCFG_H=_sony.cfg + PR_MD_CSRCS=sony.c + ;; + +*-nextstep*|*-openstep*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define NEXTSTEP 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + CFLAGS="$CFLAGS -Wall -fno-common -traditional-cpp -posix" + CXXFLAGS="$CXXFLAGS -Wall -fno-common -traditional-cpp -posix" + USE_NSPR_THREADS=1 + DLL_SUFFIX=dylib + MDCPUCFG_H=_nextstep.cfg + PR_MD_CSRCS=nextstep.c + ;; + + +*-nto*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define NTO 1 +EOF + + cat >> confdefs.h <<\EOF +#define _QNX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + MDCPUCFG_H=_nto.cfg + PR_MD_CSRCS=nto.c + MKSHLIB='$(CC) $(DSO_LDOPTS) -Wl,-soname -Wl,$(notdir $@) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS=-shared + OS_LIBS="$OS_LIBS -lsocket" + _OPTIMIZE_FLAGS="-O1" + _DEBUG_FLAGS="-gstabs" + ;; + +*-openbsd*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define OPENBSD 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + DLL_SUFFIX=so.1.0 + DSO_CFLAGS=-fPIC + MDCPUCFG_H=_openbsd.cfg + PR_MD_CSRCS=openbsd.c + OS_LIBS="-lc" + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + fi + DSO_LDOPTS='-shared -fPIC' + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + ;; + +*-openvms*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define VMS 1 +EOF + + cat >> confdefs.h <<\EOF +#define PR_GETIPNODE_NOT_THREADSAFE 1 +EOF + + RESOLVE_LINK_SYMBOLS=1 + AR_FLAGS='c $@' + MDCPUCFG_H=_openvms.cfg + PR_MD_CSRCS=openvms.c + DSO_LDOPTS='-shared -auto_symvec $(LDFLAGS)' + if test -n "$MOZ_DEBUG"; then + DSO_LDOPTS="$DSO_LDOPTS $_DEBUG_FLAGS" + else + DSO_LDOPTS="$DSO_LDOPTS $_OPTIMIZE_FLAGS" + fi + ;; + +*-osf*) + SHELL_OVERRIDE="SHELL = /usr/bin/ksh" + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define OSF1 1 +EOF + + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + # OSF1 and HPUX report the POLLHUP event for a socket when the + # shutdown(SHUT_WR) operation is called for the remote end, even though + # the socket is still writeable. Use select(), instead of poll(), to + # workaround this problem. + cat >> confdefs.h <<\EOF +#define _PR_POLL_WITH_SELECT 1 +EOF + + + if echo "$OS_RELEASE" | egrep -c '(V2.0|V3.2)' 2>/dev/null ; then + USE_NSPR_THREADS=1 + fi + + if test -z "$GNU_CC"; then + CC="$CC -std1 -ieee_with_inexact" + if test "$OS_RELEASE" != "V2.0"; then + CC="$CC -readonly_strings" + fi + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Olimit 4000" + ac_safe=`echo "machine/builtins.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for machine/builtins.h""... $ac_c" 1>&6 +echo "configure:4508: checking for machine/builtins.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:4518: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define OSF1_HAVE_MACHINE_BUILTINS_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + + else + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + fi + + if echo $OS_RELEASE | egrep -c '(V2.0|V3.2)' 2>/dev/null; then + cat >> confdefs.h <<\EOF +#define HAVE_INT_LOCALTIME_R 1 +EOF + + else + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + if echo $OS_RELEASE | grep -c V4.0 >/dev/null; then + cat >> confdefs.h <<\EOF +#define OSF1V4_MAP_PRIVATE_BUG 1 +EOF + + fi + DSO_LDOPTS='-shared -all -expect_unresolved "*" -soname $(notdir $@)' + MDCPUCFG_H=_osf1.cfg + PR_MD_CSRCS=osf1.c + ;; + +*-qnx*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define QNX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + USE_NSPR_THREADS=1 + MDCPUCFG_H=_qnx.cfg + PR_MD_CSRCS=qnx.c + ;; + +*-riscos*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define RISCOS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + USE_PTHREADS=1 + MDCPUCFG_H=_riscos.cfg + PR_MD_CSRCS=riscos.c + DLL_SUFFIX=a + LD="/home/riscos/env/ro-ar cr" + ;; + +*-*-sco*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SCO 1 +EOF + + cat >> confdefs.h <<\EOF +#define sco 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define _SVID3 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + CC='cc -b elf -KPIC' + CXX='$(NSDEPTH)/build/hcpp CC +.cpp +w' + USE_NSPR_THREADS=1 + CPU_ARCH=x86 + DSO_LDOPTS='-b elf -G' + MDCPUCFG_H=_scoos.cfg + PR_MD_SRCS=scoos.c + ;; + +*-sinix*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SNI 1 +EOF + + cat >> confdefs.h <<\EOF +#define RELIANTUNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define sinix 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SVID_GETTOD 1 +EOF + + if echo "$OS_TEST" | grep -c 86 2>/dev/null; then + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + CPU_ARCH=x86 + else + CPU_ARCH=mips + fi + + if test "$GNU_CC"; then + AS='$(CC) -x assembler-with-cpp' + if test "$CPU_ARCH" = "mips"; then + LD=gld + fi + CFLAGS="$CFLAGS -Wall -Wno-format" + else + AS='/usr/bin/cc' + _OPTIMIZE_FLAGS='-O -F Olimit,4000' + fi + + DSO_LDOPTS='-G -z defs -h $(@:$(OBJDIR)/%.so=%.so)' + + if test "$OS_RELEASE" = "5.43"; then + cat >> confdefs.h <<\EOF +#define IP_MULTICAST 1 +EOF + + fi + + OS_LIBS="$OS_LIBS -lsocket -lnsl -lresolv -ldl -lc" + USE_NSPR_THREADS=1 + MDCPUCFG_H=_reliantunix.cfg + PR_MD_CSRCS=reliantunix.c + if test "${OS_ARCH}" = "mips"; then + PR_MD_ASFILES=os_ReliantUNIX.s + fi + ;; + +*-sunos*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SUNOS4 1 +EOF + + CFLAGS="$CFLAGS -Wall -Wno-format" + if test "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + fi + CPU_ARCH=sparc + DLL_SUFFIX=so.1.0 + DSO_LDOPTS= + DSO_CFLAGS=-fPIC + USE_NSPR_THREADS=1 + if test "$OS_RELEASE" = "4.1.3_U1"; then + _OPTIMIZE_FLAGS= + OS_LIBS="$OS_LIBS -lm" + fi + MDCPUCFG_H=_sunos4.cfg + PR_MD_CSRCS=sunos4.c + ;; + +*-solaris*) + if test -z "$USE_USER_THREADS" && test -z "$USE_NATIVE_THREADS"; then + USE_PTHREADS=1 + fi + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define __svr4 1 +EOF + + cat >> confdefs.h <<\EOF +#define __svr4__ 1 +EOF + + cat >> confdefs.h <<\EOF +#define SOLARIS 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + MDCPUCFG_H=_solaris.cfg + PR_MD_CSRCS=solaris.c + LD=/usr/ccs/bin/ld + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + RESOLVE_LINK_SYMBOLS=1 + if test -n "$GNU_CC"; then + DSO_CFLAGS=-fPIC + if `$CC -print-prog-name=ld` -v 2>&1 | grep -c GNU >/dev/null; then + GCC_USE_GNU_LD=1 + fi + DSO_LDOPTS='-shared -Wl,-h,$(notdir $@),-z,combreloc,-z,defs,-z,ignore' + else + DSO_CFLAGS=-KPIC + DSO_LDOPTS='-G -h $(notdir $@) -z combreloc -z defs -z ignore' + fi + if test -n "$GNU_CC"; then + CFLAGS="$CFLAGS -Wall" + CXXFLAGS="$CXXFLAGS -Wall" + if test -n "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + CXXFLAGS="$CXXFLAGS -MDupdate \$(DEPENDENCIES)" + fi + GCC_AS=`$CC -print-prog-name=as` + if test "`echo | $GCC_AS -v 2>&1 | grep -c GNU`" != "0"; then + GNU_AS=1 + fi + else + CFLAGS="$CFLAGS -xstrconst" + CXXFLAGS="$CXXFLAGS -Qoption cg -xstrconst -features=tmplife" + if test -z "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS -xs" + CXXFLAGS="$CXXFLAGS -xs" + fi + _OPTIMIZE_FLAGS=-xO4 + fi + if test -z "$GNU_AS"; then + ASFLAGS="$ASFLAGS -Wa,-P" + fi + if test -n "$USE_64"; then + if test -n "$GNU_CC"; then + CC="$CC -m64" + CXX="$CXX -m64" + else + if test "$OS_TEST" = "i86pc"; then + CC="$CC -xarch=amd64" + CXX="$CXX -xarch=amd64" + else + CC="$CC -xarch=v9" + CXX="$CXX -xarch=v9" + fi + fi + fi + if test "$OS_TEST" = "i86pc"; then + if test -z "$USE_64"; then + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + fi + CPU_ARCH_TAG=_$OS_TEST + # The default debug format, DWARF (-g), is not supported by gcc + # on i386-ANY-sysv4/solaris, but the stabs format is. It is + # assumed that the Solaris assembler /usr/ccs/bin/as is used. + # If your gcc uses GNU as, you do not need the -Wa,-s option. + if test -n "$MOZ_DEBUG" && test -n "$GNU_CC"; then + _DEBUG_FLAGS=-gstabs + if test -z "$GNU_AS"; then + _DEBUG_FLAGS="$_DEBUG_FLAGS -Wa,-s" + fi + fi + fi + case "${target_os}" in + solaris2.3*) + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + ;; + solaris2.4*) + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + ;; + solaris2.5*) + cat >> confdefs.h <<\EOF +#define SOLARIS2_5 1 +EOF + + ;; + *) + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + # The lfcompile64(5) man page on Solaris 2.6 says: + # For applications that do not wish to conform to the POSIX or + # X/Open specifications, the 64-bit transitional interfaces + # are available by default. No compile-time flags need to be + # set. + # But gcc 2.7.2.x fails to define _LARGEFILE64_SOURCE by default. + # The native compiler, gcc 2.8.x, and egcs don't have this problem. + if test -n "$GNU_CC"; then + cat >> confdefs.h <<\EOF +#define _LARGEFILE64_SOURCE 1 +EOF + + fi + ;; + esac + case "${target_os}" in + solaris2.3*) + ;; + solaris2.4*) + ;; + solaris2.5*) + ;; + solaris2.6*) + ;; + solaris2.7*) + ;; + *) + # Solaris 8 or higher has IPv6. + cat >> confdefs.h <<\EOF +#define _PR_INET6 1 +EOF + + ;; + esac + if test "$OS_TEST" = "sun4u"; then + # 64-bit Solaris requires SPARC V9 architecture, so the following + # is not needed. + if test -z "$USE_64"; then + ULTRASPARC_LIBRARY=nspr_flt + fi + fi + # Purify requires that binaries linked against nspr also + # be linked against -lrt (or -lposix4) so add it to OS_LIBS + _rev=`uname -r` + _librt=`echo $_rev 5.6 | awk '{ if ($1 > $2) print "-lrt"; else print "-lposix4" }'` + OS_LIBS="$OS_LIBS $_librt" + ;; + +*-sco-sysv5*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define UNIXWARE 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + USE_NSPR_THREADS=1 + if echo $OS_RELEASE | grep -c 2.1 2>/dev/null; then + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + CC='$(NSDEPTH)/build/hcc cc' + CXX='$(NSDEPTH)/build/hcpp CC' + MDCPUCFG_H=_unixware.cfg + else + cat >> confdefs.h <<\EOF +#define _LARGEFILE64_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_SOCKADDR_LEN 1 +EOF + + MDCPUCFG_H=_unixware7.cfg + fi + PR_MD_CSRCS=unixware.c + DSO_LDOPTS=-G + CPU_ARCH=x86 + ;; + +*-os2*) + cat >> confdefs.h <<\EOF +#define XP_OS2 1 +EOF + + cat >> confdefs.h <<\EOF +#define XP_PC 1 +EOF + + cat >> confdefs.h <<\EOF +#define BSD_SELECT 1 +EOF + + cat >> confdefs.h <<\EOF +#define TCPV40HDRS 1 +EOF + + LIB_SUFFIX=lib + DLL_SUFFIX=dll + RC=rc.exe + PR_MD_ARCH_DIR=os2 + PROG_SUFFIX=.exe + NSINSTALL=nsinstall + MDCPUCFG_H=_os2.cfg + RESOLVE_LINK_SYMBOLS=1 + + # EMX/GCC build + if test -n "$GNU_CC"; then + cat >> confdefs.h <<\EOF +#define XP_OS2_EMX 1 +EOF + + cat >> confdefs.h <<\EOF +#define OS2 1 +EOF + + AR=emxomfar + AR_FLAGS='r $@' + CFLAGS="$CFLAGS -Wall -Zomf" + CXXFLAGS="$CFLAGS -Wall -Zomf" + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS= + DSO_LDOPTS='-Zomf -Zdll -Zmap' + LDFLAGS='-Zmap' + _OPTIMIZE_FLAGS="-O2 -s" + _DEBUG_FLAGS="-g -fno-inline" + if test -n "$MOZ_OPTIMIZE"; then + DSO_LDOPTS="$DSO_LDOPTS -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA" + fi + OS_LIBS="-lsocket" + IMPLIB='emximp -o' + FILTER='emxexp -o' + if test -n "$MOZ_OS2_HIGH_MEMORY"; then + DSO_LDOPTS="$DSO_LDOPTS -Zhigh-mem" + LDFLAGS="$LDFLAGS -Zhigh-mem" + cat >> confdefs.h <<\EOF +#define MOZ_OS2_HIGH_MEMORY 1 +EOF + + fi + + # GCC for OS/2 currently predefines these, but we don't want them + DEFINES="$DEFINES -Uunix -U__unix -U__unix__" + + # Visual Age C++ build + elif test "$VACPP" = "yes"; then + cat >> confdefs.h <<\EOF +#define XP_OS2_VACPP 1 +EOF + + cat >> confdefs.h <<\EOF +#define OS2 4 +EOF + + cat >> confdefs.h <<\EOF +#define _X86_ 1 +EOF + + OBJ_SUFFIX=obj + AS=alp + ASFLAGS='-Mb' + ASM_SUFFIX=asm + AR=-ilib + AR_FLAGS='/NOL /NOI /O:$(subst /,\\,$@)' + CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + HOST_CFLAGS="$CFLAGS" + OS_CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + OS_EXE_CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + CXXFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + OS_LIBS='so32dll.lib tcp32dll.lib' + LD='-ilink' + MKSHLIB='$(LD) $(DSO_LDOPTS)' + IMPLIB='implib -nologo -noignorecase' + FILTER='cppfilt -q -B -P' + _OPTIMIZE_FLAGS='/O+ /Gl+ /qtune=pentium /qarch=pentium' + _DEBUG_FLAGS='/Ti+ ' + LDFLAGS='/NOL /M /L' + DLLFLAGS="$DLLFLAGS /O:\$@ /DLL /INC:_dllentry /MAP:\$(@:.dll=.map) /L /NOL" + EXEFLAGS='/OUT:$@ /PMTYPE:VIO /MAP:$(@:.exe=.map) /L /NOL' + if test -n "$MOZ_DEBUG"; then + LDFLAGS="$LDFLAGS /DE" + DLLFLAGS="$DLLFLAGS /DE" + EXEFLAGS="$EXEFLAGS /DE" + fi + if test -n "$MOZ_OPTIMIZE"; then + LDFLAGS="$LDFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + DLLFLAGS="$DLLFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + EXEFLAGS="$EXEFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + fi + LIBNSPR='$(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + fi + ;; + +*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + ;; + +esac + +if test -z "$SKIP_LIBRARY_CHECKS"; then + + + +case $target in +*-darwin*|*-beos*) + ;; +*) + echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 +echo "configure:5088: checking for dlopen in -ldl" >&5 +ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_safe=`echo "dlfcn.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for dlfcn.h""... $ac_c" 1>&6 +echo "configure:5124: checking for dlfcn.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:5134: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + OS_LIBS="-ldl $OS_LIBS" +else + echo "$ac_t""no" 1>&6 +fi + +else + echo "$ac_t""no" 1>&6 +fi + + ;; +esac + + + + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:5167: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext < +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext < +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +for ac_func in lchown strerror +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:5215: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:5243: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + + + +# Check whether --enable-strip or --disable-strip was given. +if test "${enable_strip+set}" = set; then + enableval="$enable_strip" + if test "$enableval" = "yes"; then + ENABLE_STRIP=1 + fi +fi + + +case "${target_os}" in +hpux*) +if test -z "$GNU_CC"; then + + echo $ac_n "checking for +Olit support""... $ac_c" 1>&6 +echo "configure:5284: checking for +Olit support" >&5 +if eval "test \"`echo '$''{'ac_cv_hpux_usable_olit_option'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_hpux_usable_olit_option=no + rm -f conftest* + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} ${CFLAGS} +Olit=all -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out`"; then + ac_cv_hpux_usable_olit_option=yes + fi + fi + rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_hpux_usable_olit_option" 1>&6 + + if test "$ac_cv_hpux_usable_olit_option" = "yes"; then + CFLAGS="$CFLAGS +Olit=all" + CXXFLAGS="$CXXFLAGS +Olit=all" + else + CFLAGS="$CFLAGS +ESlit" + CXXFLAGS="$CXXFLAGS +ESlit" + fi +fi +;; +esac + + + +case "$target_os" in +darwin*) + _HAVE_PTHREADS=1 + ;; +*) + +echo $ac_n "checking for pthread_create in -lpthreads""... $ac_c" 1>&6 +echo "configure:5323: checking for pthread_create in -lpthreads" >&5 +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthreads $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthreads $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthreads" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6 +echo "configure:5345: checking for pthread_create in -lpthread" >&5 +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthread $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthread $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthread" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lc_r""... $ac_c" 1>&6 +echo "configure:5367: checking for pthread_create in -lc_r" >&5 +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc_r $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc_r $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lc_r" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lc""... $ac_c" 1>&6 +echo "configure:5389: checking for pthread_create in -lc" >&5 +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + _HAVE_PTHREADS=1 + + else + echo "$ac_t""no" 1>&6 + + fi + + + fi + + + fi + + + fi + + ;; +esac + +# Check whether --with-pthreads or --without-pthreads was given. +if test "${with_pthreads+set}" = set; then + withval="$with_pthreads" + if test "$withval" = "yes"; then + if test -n "$_HAVE_PTHREADS"; then + USE_PTHREADS=1 + USE_USER_PTHREADS= + USE_NSPR_THREADS= + else + { echo "configure: error: --with-pthreads specified for a system without pthread support " 1>&2; exit 1; }; + fi + else + USE_PTHREADS= + _PTHREAD_LDFLAGS= + fi +else + if test -n "$_HAVE_PTHREADS" && test -z "$USE_USER_PTHREADS" && test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + USE_USER_PTHREADS= + USE_NSPR_THREADS= + fi +fi + + +# Check whether --enable-user-pthreads or --disable-user-pthreads was given. +if test "${enable_user_pthreads+set}" = set; then + enableval="$enable_user_pthreads" + if test "$enableval" = "yes"; then + if test -n "$_HAVE_PTHREADS"; then + USE_PTHREADS= + USE_USER_PTHREADS=1 + USE_NSPR_THREADS= + else + { echo "configure: error: --enable-user-pthreads specified for a system without pthread support " 1>&2; exit 1; }; + fi + fi +fi + + +# Check whether --enable-nspr-threads or --disable-nspr-threads was given. +if test "${enable_nspr_threads+set}" = set; then + enableval="$enable_nspr_threads" + if test "$enableval" = "yes"; then + USE_PTHREADS= + USE_USER_PTHREADS= + USE_NSPR_THREADS=1 + fi +fi + + +case "$target" in +*-beos*) + # Check whether --with-bthreads or --without-bthreads was given. +if test "${with_bthreads+set}" = set; then + withval="$with_bthreads" + if test "$withval" = "yes"; then + USE_BTHREADS=1 + USE_USER_PTHREADS= + USE_PTHREADS= + fi +fi + + ;; + +*-solaris*) + # Check whether --with-native-threads or --without-native-threads was given. +if test "${with_native_threads+set}" = set; then + withval="$with_native_threads" + if test "$withval" = "yes"; then + USE_NATIVE_THREADS=1 + USE_USER_PTHREADS= + USE_PTHREADS= + fi +fi + + ;; +esac + +fi # SKIP_LIBRARY_CHECKS + +# Check whether --enable-ipv6 or --disable-ipv6 was given. +if test "${enable_ipv6+set}" = set; then + enableval="$enable_ipv6" + if test "$enableval" = "yes"; then + USE_IPV6=1 + else + USE_IPV6= + fi +fi + + + +# Check whether --enable-boehm or --disable-boehm was given. +if test "${enable_boehm+set}" = set; then + enableval="$enable_boehm" + if test "$enableval" = "yes"; then + cat >> confdefs.h <<\EOF +#define GC_LEAK_DETECTOR 1 +EOF + + GC_LEAK_DETECTOR=1 + fi +fi + + +if test -n "$USE_PTHREADS"; then + rm -f conftest* + ac_cv_have_dash_pthread=no + echo $ac_n "checking whether ${CC-cc} accepts -pthread""... $ac_c" 1>&6 +echo "configure:5534: checking whether ${CC-cc} accepts -pthread" >&5 + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthread -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthread`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthread=yes + case "$target_os" in + freebsd*) +# Freebsd doesn't use -pthread for compiles, it uses them for linking + ;; + *) + CFLAGS="$CFLAGS -pthread" + CXXFLAGS="$CXXFLAGS -pthread" + ;; + esac + fi + fi + rm -f conftest* + echo "$ac_t""$ac_cv_have_dash_pthread" 1>&6 + + ac_cv_have_dash_pthreads=no + if test "$ac_cv_have_dash_pthread" = "no"; then + echo $ac_n "checking whether ${CC-cc} accepts -pthreads""... $ac_c" 1>&6 +echo "configure:5557: checking whether ${CC-cc} accepts -pthreads" >&5 + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthreads -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthreads`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthreads=yes + CFLAGS="$CFLAGS -pthreads" + CXXFLAGS="$CXXFLAGS -pthreads" + fi + fi + rm -f conftest* + echo "$ac_t""$ac_cv_have_dash_pthreads" 1>&6 + fi + + case "$target" in + *-solaris*) + if test "$ac_cv_have_dash_pthreads" = "yes"; then + _PTHREAD_LDFLAGS= + fi + ;; + *-freebsd*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _THREAD_SAFE 1 +EOF + + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + else + _PTHREAD_LDFLAGS="-lc_r" + fi + ;; + *-netbsd*) + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + fi + ;; + *-bsdi*) + cat >> confdefs.h <<\EOF +#define _THREAD_SAFE 1 +EOF + + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS= + fi + ;; + *-openbsd*) + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS=-pthread + fi + ;; + *-linux*|*-gnu*|*-k*bsd*-gnu) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + ;; + esac + +else + if test -n "$USE_USER_PTHREADS"; then + USE_PTHREADS= + USE_NSPR_THREADS= + else + _PTHREAD_LDFLAGS= + fi +fi + +case "$target" in +*-aix*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + case "$target_os" in + aix4.1*) + if test -z "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define AIX_RENAME_SELECT 1 +EOF + + fi + ;; + aix4.2*) + if test -z "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + ;; + aix4.3*) + if test -z "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + if test -n "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_HAVE_THREADSAFE_GETHOST 1 +EOF + + fi + ;; + *) + if test -z "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + if test -n "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_HAVE_THREADSAFE_GETHOST 1 +EOF + + fi + ;; + esac + ;; +*-bsdi*) + if test -n "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_NEED_PTHREAD_INIT 1 +EOF + + fi + ;; +*-freebsd*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + ;; +*-hpux*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + if test "$USE_PTHREADS"; then + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_DCETHREADS 1 +EOF + + else + cat >> confdefs.h <> confdefs.h <<\EOF +#define _PR_HAVE_THREADSAFE_GETHOST 1 +EOF + + fi + fi + if test "$USE_USER_PTHREADS"; then + cat >> confdefs.h <> confdefs.h <<\EOF +#define _PR_HAVE_GETHOST_R 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETHOST_R_POINTER 1 +EOF + + fi + fi + ;; +*-linux*|*-gnu*|*-k*bsd*-gnu) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + ;; +*-mingw*|*-cygwin*|*-msvc*|*-mks*|*-os2*|*-beos*) + USE_PTHREADS= + _PTHREAD_LDFLAGS= + USE_USER_PTHREADS= + ;; +*-netbsd*|*-openbsd*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + ;; +*-osf*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + if test -n "$USE_PTHREADS"; then + if echo $OS_RELEASE | egrep -c '(V2.0|V3.2)' 2>/dev/null; then + : + else + cat >> confdefs.h <<\EOF +#define _PR_HAVE_THREADSAFE_GETHOST 1 +EOF + + fi + fi + ;; +*-solaris*) + if test -n "$USE_NATIVE_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_GLOBAL_THREADS_ONLY 1 +EOF + + else + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + fi + if test -z "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + if test "$OS_TEST" = "i86pc"; then + if test -n "$USE_64"; then + PR_MD_ASFILES=os_SunOS_x86_64.s + else + PR_MD_ASFILES=os_SunOS_x86.s + fi + else + if test -n "$USE_64"; then + PR_MD_ASFILES=os_SunOS_sparcv9.s + fi + if test -n "$USE_NATIVE_THREADS"; then + PR_MD_ASFILES="$PR_MD_ASFILES os_SunOS.s" + fi + fi + fi + ;; +*-nto*) + if test -n "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETHOST_R 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETHOST_R_POINTER 1 +EOF + + fi + ;; +esac + +OS_LIBS="$_PTHREAD_LDFLAGS $OS_LIBS" + +if test -n "$_SAVE_OPTIMIZE_FLAGS"; then + _OPTIMIZE_FLAGS="$_SAVE_OPTIMIZE_FLAGS" +fi + +if test -n "$_SAVE_DEBUG_FLAGS"; then + _DEBUG_FLAGS="$_SAVE_DEBUG_FLAGS" +fi + +if test -n "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS $_OPTIMIZE_FLAGS" + CXXFLAGS="$CXXFLAGS $_OPTIMIZE_FLAGS" +fi + +if test -n "$MOZ_DEBUG"; then + CFLAGS="$CFLAGS $_DEBUG_FLAGS" + CXXFLAGS="$CXXFLAGS $_DEBUG_FLAGS" +fi + +if test -n "$MOZ_OPTIMIZE"; then + OBJDIR_TAG=_OPT +else + OBJDIR_TAG=_DBG +fi + +if test -n "$USE_64"; then + COMPILER_TAG=_64 +fi + +RELEASE_OBJDIR_NAME="${OS_CONFIG}${CPU_ARCH_TAG}${COMPILER_TAG}${IMPL_STRATEGY}${OBJDIR_TAG}.${OBJDIR_SUFFIX}" + +case "$target_os" in +cygwin*|msvc*|mks*) + CC="\$(CYGWIN_WRAPPER) $CC" + CXX="\$(CYGWIN_WRAPPER) $CXX" + RC="\$(CYGWIN_WRAPPER) $RC" + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MAKEFILES=" +Makefile +config/Makefile +config/autoconf.mk +config/nsprincl.mk +config/nsprincl.sh +config/nspr-config +lib/Makefile +lib/ds/Makefile +lib/libc/Makefile +lib/libc/include/Makefile +lib/libc/src/Makefile +lib/tests/Makefile +pkg/Makefile +pkg/linux/Makefile +pkg/solaris/Makefile +pkg/solaris/SUNWpr/Makefile +pkg/solaris/SUNWprd/Makefile +pr/Makefile +pr/include/Makefile +pr/include/md/Makefile +pr/include/obsolete/Makefile +pr/include/private/Makefile +pr/src/Makefile +pr/src/io/Makefile +pr/src/linking/Makefile +pr/src/malloc/Makefile +pr/src/md/Makefile +pr/src/md/${PR_MD_ARCH_DIR}/Makefile +pr/src/memory/Makefile +pr/src/misc/Makefile +pr/src/threads/Makefile +pr/tests/Makefile +pr/tests/dll/Makefile +" + + +if test -z "$USE_PTHREADS" && test -z "$USE_BTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/threads/combined/Makefile" +elif test -n "$USE_PTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/pthreads/Makefile" +elif test -n "$USE_BTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/bthreads/Makefile" +fi + +if test -n "$USE_CPLUS"; then + MAKEFILES="$MAKEFILES pr/src/cplus/Makefile pr/src/cplus/tests/Makefile" +fi + +echo $MAKEFILES > unallmakefiles + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' ' | tr '\015' ' '` +rm -f conftest.defs + + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "$MAKEFILES" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@dist_prefix@%$dist_prefix%g +s%@dist_bindir@%$dist_bindir%g +s%@dist_includedir@%$dist_includedir%g +s%@dist_libdir@%$dist_libdir%g +s%@WHOAMI@%$WHOAMI%g +s%@HOST_CC@%$HOST_CC%g +s%@CXX@%$CXX%g +s%@RANLIB@%$RANLIB%g +s%@AR@%$AR%g +s%@AS@%$AS%g +s%@LD@%$LD%g +s%@STRIP@%$STRIP%g +s%@WINDRES@%$WINDRES%g +s%@CPP@%$CPP%g +s%@PERL@%$PERL%g +s%@SHELL_OVERRIDE@%$SHELL_OVERRIDE%g +s%@MOZILLA_CLIENT@%$MOZILLA_CLIENT%g +s%@HOST_CFLAGS@%$HOST_CFLAGS%g +s%@HOST_LDFLAGS@%$HOST_LDFLAGS%g +s%@GNU_CC@%$GNU_CC%g +s%@GCC_USE_GNU_LD@%$GCC_USE_GNU_LD%g +s%@MSC_VER@%$MSC_VER%g +s%@CROSS_COMPILE@%$CROSS_COMPILE%g +s%@MOZ_OPTIMIZE@%$MOZ_OPTIMIZE%g +s%@USE_CPLUS@%$USE_CPLUS%g +s%@USE_IPV6@%$USE_IPV6%g +s%@USE_N32@%$USE_N32%g +s%@USE_64@%$USE_64%g +s%@OBJECT_MODE@%$OBJECT_MODE%g +s%@GC_LEAK_DETECTOR@%$GC_LEAK_DETECTOR%g +s%@ENABLE_STRIP@%$ENABLE_STRIP%g +s%@USE_PTHREADS@%$USE_PTHREADS%g +s%@USE_BTHREADS@%$USE_BTHREADS%g +s%@USE_USER_PTHREADS@%$USE_USER_PTHREADS%g +s%@USE_NATIVE_THREADS@%$USE_NATIVE_THREADS%g +s%@USE_NSPR_THREADS@%$USE_NSPR_THREADS%g +s%@LIBNSPR@%$LIBNSPR%g +s%@LIBPLC@%$LIBPLC%g +s%@MOD_MAJOR_VERSION@%$MOD_MAJOR_VERSION%g +s%@MOD_MINOR_VERSION@%$MOD_MINOR_VERSION%g +s%@MOD_PATCH_VERSION@%$MOD_PATCH_VERSION%g +s%@NSPR_MODNAME@%$NSPR_MODNAME%g +s%@MDCPUCFG_H@%$MDCPUCFG_H%g +s%@PR_MD_CSRCS@%$PR_MD_CSRCS%g +s%@PR_MD_ASFILES@%$PR_MD_ASFILES%g +s%@PR_MD_ARCH_DIR@%$PR_MD_ARCH_DIR%g +s%@CPU_ARCH@%$CPU_ARCH%g +s%@OBJ_SUFFIX@%$OBJ_SUFFIX%g +s%@LIB_SUFFIX@%$LIB_SUFFIX%g +s%@DLL_SUFFIX@%$DLL_SUFFIX%g +s%@ASM_SUFFIX@%$ASM_SUFFIX%g +s%@MKSHLIB@%$MKSHLIB%g +s%@DSO_CFLAGS@%$DSO_CFLAGS%g +s%@DSO_LDOPTS@%$DSO_LDOPTS%g +s%@OS_TARGET@%$OS_TARGET%g +s%@OS_ARCH@%$OS_ARCH%g +s%@OS_RELEASE@%$OS_RELEASE%g +s%@OS_TEST@%$OS_TEST%g +s%@MACOSX_DEPLOYMENT_TARGET@%$MACOSX_DEPLOYMENT_TARGET%g +s%@DEFINES@%$DEFINES%g +s%@AR_FLAGS@%$AR_FLAGS%g +s%@ASFLAGS@%$ASFLAGS%g +s%@FILTER@%$FILTER%g +s%@IMPLIB@%$IMPLIB%g +s%@OS_LIBS@%$OS_LIBS%g +s%@RESOLVE_LINK_SYMBOLS@%$RESOLVE_LINK_SYMBOLS%g +s%@AIX_LINK_OPTS@%$AIX_LINK_OPTS%g +s%@NOSUCHFILE@%$NOSUCHFILE%g +s%@MOZ_OBJFORMAT@%$MOZ_OBJFORMAT%g +s%@ULTRASPARC_LIBRARY@%$ULTRASPARC_LIBRARY%g +s%@OBJDIR@%$OBJDIR%g +s%@OBJDIR_NAME@%$OBJDIR_NAME%g +s%@RELEASE_OBJDIR_NAME@%$RELEASE_OBJDIR_NAME%g +s%@NSINSTALL@%$NSINSTALL%g +s%@OPTIMIZER@%$OPTIMIZER%g +s%@RC@%$RC%g +s%@RCFLAGS@%$RCFLAGS%g +s%@DLLFLAGS@%$DLLFLAGS%g +s%@EXEFLAGS@%$EXEFLAGS%g +s%@OS_DLLFLAGS@%$OS_DLLFLAGS%g +s%@CYGWIN_WRAPPER@%$CYGWIN_WRAPPER%g +s%@VISIBILITY_FLAGS@%$VISIBILITY_FLAGS%g +s%@WRAP_SYSTEM_INCLUDES@%$WRAP_SYSTEM_INCLUDES%g +s%@MACOS_SDK_DIR@%$MACOS_SDK_DIR%g +s%@NEXT_ROOT@%$NEXT_ROOT%g +s%@MT@%$MT%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +chmod +x config/nspr-config +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/nsprpub/configure.in b/nsprpub/configure.in new file mode 100644 index 00000000000..8743c9f78ce --- /dev/null +++ b/nsprpub/configure.in @@ -0,0 +1,2907 @@ +dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*- +dnl +dnl ***** BEGIN LICENSE BLOCK ***** +dnl Version: MPL 1.1/GPL 2.0/LGPL 2.1 +dnl +dnl The contents of this file are subject to the Mozilla Public License Version +dnl 1.1 (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl http://www.mozilla.org/MPL/ +dnl +dnl Software distributed under the License is distributed on an "AS IS" basis, +dnl WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +dnl for the specific language governing rights and limitations under the +dnl License. +dnl +dnl The Original Code is the Netscape Portable Runtime (NSPR). +dnl +dnl The Initial Developer of the Original Code is +dnl Netscape Communications Corporation. +dnl Portions created by the Initial Developer are Copyright (C) 1998 +dnl the Initial Developer. All Rights Reserved. +dnl +dnl Contributor(s): +dnl Christopher Seawood +dnl Howard Chu +dnl Mark Mentovai +dnl +dnl Alternatively, the contents of this file may be used under the terms of +dnl either the GNU General Public License Version 2 or later (the "GPL"), or +dnl the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +dnl in which case the provisions of the GPL or the LGPL are applicable instead +dnl of those above. If you wish to allow use of your version of this file only +dnl under the terms of either the GPL or the LGPL, and not to allow others to +dnl use your version of this file under the terms of the MPL, indicate your +dnl decision by deleting the provisions above and replace them with the notice +dnl and other provisions required by the GPL or the LGPL. If you do not delete +dnl the provisions above, a recipient may use your version of this file under +dnl the terms of any one of the MPL, the GPL or the LGPL. +dnl +dnl ***** END LICENSE BLOCK ***** + +AC_PREREQ(2.12) +AC_INIT(config/libc_r.h) + +AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf) +AC_CANONICAL_SYSTEM + +dnl ======================================================== +dnl = Defaults +dnl ======================================================== +MOD_MAJOR_VERSION=4 +MOD_MINOR_VERSION=7 +MOD_PATCH_VERSION=1 +NSPR_MODNAME=nspr20 +_HAVE_PTHREADS= +USE_PTHREADS= +USE_USER_PTHREADS= +USE_NSPR_THREADS= +USE_N32= +USE_64= +USE_CPLUS= +USE_IPV6= +USE_MDUPDATE= +_MACOSX_DEPLOYMENT_TARGET= +_OPTIMIZE_FLAGS=-O +_DEBUG_FLAGS=-g +MOZ_DEBUG=1 +MOZ_OPTIMIZE= +OBJDIR='$(OBJDIR_NAME)' +OBJDIR_NAME=. +OBJDIR_SUFFIX=OBJ +NSINSTALL='$(MOD_DEPTH)/config/$(OBJDIR_NAME)/nsinstall' +NOSUCHFILE=/no-such-file +LIBNSPR='-L$(dist_libdir) -lnspr$(MOD_MAJOR_VERSION)' +LIBPLC='-L$(dist_libdir) -lplc$(MOD_MAJOR_VERSION)' +CYGWIN_WRAPPER= +MACOS_SDK_DIR= +NEXT_ROOT= +MT= +MOZ_OS2_HIGH_MEMORY=1 + +dnl Link in libraries necessary to resolve all symbols for shared libs +RESOLVE_LINK_SYMBOLS= + +dnl ======================================================== +dnl = +dnl = Dont change the following lines. Doing so breaks: +dnl = +dnl = CFLAGS="-foo" ./configure +dnl = +dnl ======================================================== +CFLAGS="${CFLAGS=}" +CXXFLAGS="${CXXFLAGS=}" +LDFLAGS="${LDFLAGS=}" +DLLFLAGS="${DLLFLAGS=}" +HOST_CFLAGS="${HOST_CFLAGS=}" +HOST_LDFLAGS="${HOST_LDFLAGS=}" + +case "$target" in +*-cygwin*|*-mingw*) + # Check to see if we are really running in a msvc environemnt + _WIN32_MSVC= + AC_CHECK_PROGS(CC, cl) + if test "$CC" = "cl"; then + echo 'main() { return 0; }' > dummy.c + ${CC} -o dummy dummy.c >/dev/null 2>&1 + if test $? = 0; then + _WIN32_MSVC=1 + CXX=$CC + else + AC_MSG_WARN([$(CC) test failed. Using normal feature tests]) + fi + rm -f dummy dummy.o dummy.obj dummy.exe dummy.c + fi + ;; +*-msvc*) + _WIN32_MSVC=1 + ;; +*-mks*) + _WIN32_MSVC=1 + ;; +esac + +if test -n "$_WIN32_MSVC"; then + SKIP_PATH_CHECKS=1 + SKIP_COMPILER_CHECKS=1 + SKIP_LIBRARY_CHECKS=1 +fi + +dnl ======================================================== +dnl = +dnl = Check options that may affect the compiler +dnl = +dnl ======================================================== +dist_prefix='${MOD_DEPTH}/dist' +dist_bindir='${dist_prefix}/bin' +dist_includedir='${dist_prefix}/include/nspr' +dist_libdir='${dist_prefix}/lib' +dnl If the --includedir option was not specified, add '/nspr' to autoconf's +dnl default value of includedir. +if test "${includedir}" = '${prefix}/include'; then + includedir='${prefix}/include/nspr' +fi + +AC_ARG_WITH(dist-prefix, + [ --with-dist-prefix=DIST_PREFIX + place build files in DIST_PREFIX [dist]], + dist_prefix=$withval) + +AC_ARG_WITH(dist-bindir, + [ --with-dist-bindir=DIR build execuatables in DIR [DIST_PREFIX/bin]], + dist_bindir=$withval) + +AC_ARG_WITH(dist-includedir, + [ --with-dist-includedir=DIR + build include files in DIR [DIST_PREFIX/include/nspr]], + dist_includedir=$withval) + +AC_ARG_WITH(dist-libdir, + [ --with-dist-libdir=DIR build library files in DIR [DIST_PREFIX/lib]], + dist_libdir=$withval) + +AC_SUBST(dist_prefix) +AC_SUBST(dist_bindir) +AC_SUBST(dist_includedir) +AC_SUBST(dist_libdir) + +dnl Check if NSPR is being compiled for Mozilla +dnl Let --with-arg override environment setting +dnl +AC_ARG_WITH(mozilla, + [ --with-mozilla Compile NSPR with Mozilla support], + [ if test "$withval" = "yes"; then + AC_DEFINE(MOZILLA_CLIENT) + MOZILLA_CLIENT=1 + else + MOZILLA_CLIENT= + fi], + [ if test -n "$MOZILLA_CLIENT"; then + AC_DEFINE(MOZILLA_CLIENT) + fi]) + +AC_ARG_ENABLE(optimize, + [ --enable-optimize(=val) Enable code optimizations (val, ie. -O2) ], + [ if test "$enableval" != "no"; then + MOZ_OPTIMIZE=1 + if test -n "$enableval" && test "$enableval" != "yes"; then + _OPTIMIZE_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + _SAVE_OPTIMIZE_FLAGS=$_OPTIMIZE_FLAGS + fi + else + MOZ_OPTIMIZE= + fi ]) + +AC_ARG_ENABLE(debug, + [ --disable-debug Do not compile in debugging symbols + --enable-debug(=val) Enable debugging (debug flags val)], + [ if test "$enableval" = "no"; then + MOZ_DEBUG= + else + MOZ_DEBUG=1 + if test -n "$enableval" && test "$enableval" != "yes"; then + _DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + _SAVE_DEBUG_FLAGS=$_DEBUG_FLAGS + fi + fi]) + +AC_ARG_ENABLE(win32-target, + [ --enable-win32-target=\$t + Specify win32 flavor. (WIN95 or WINNT)], + OS_TARGET=`echo $enableval | tr a-z A-Z`, + OS_TARGET=) + +AC_ARG_ENABLE(debug-rtl, + [ --enable-debug-rtl Use the MSVC debug runtime library], + [ if test "$enableval" = "yes"; then + USE_DEBUG_RTL=1 + fi ]) + +AC_ARG_ENABLE(n32, + [ --enable-n32 Enable n32 ABI support (IRIX only)], + [ if test "$enableval" = "yes"; then + USE_N32=1 + else if test "$enableval" = "no"; then + USE_N32= + fi + fi ]) + +AC_ARG_ENABLE(64bit, + [ --enable-64bit Enable 64-bit support (on certain platforms)], + [ if test "$enableval" = "yes"; then + USE_64=1 + fi ]) + +AC_ARG_ENABLE(mdupdate, + [ --enable-mdupdate Enable use of certain compilers' mdupdate feature], + [ if test "$enableval" = "yes"; then + USE_MDUPDATE=1 + fi ]) + +AC_ARG_ENABLE(cplus, + [ --enable-cplus Enable some c++ api routines], + [ if test "$enableval" = "yes"; then + USE_CPLUS=1 + fi]) + +AC_ARG_WITH(arm-kuser, + [ --with-arm-kuser Use kuser helpers (Linux/ARM only) + (Requires kernel 2.6.13 or later)], + [ if test "$withval" = "yes"; then + AC_DEFINE(_PR_ARM_KUSER) + fi ]) + +dnl ======================================================== +dnl = Mac OS X SDK support +dnl ======================================================== +AC_ARG_WITH(macos-sdk, + [ --with-macos-sdk=dir Location of platform SDK to use (Mac OS X only)], + MACOS_SDK_DIR=$withval) + +AC_ARG_ENABLE(macos-target, + [ --enable-macos-target=VER + Set the minimum MacOS version needed at runtime + [10.2 for ppc, 10.4 for x86]], + [_MACOSX_DEPLOYMENT_TARGET=$enableval]) + +dnl ======================================================== +dnl = +dnl = Set the threading model +dnl = +dnl ======================================================== +case "$target" in + +*-aix*) + case "${target_os}" in + aix3.2*) + USE_NSPR_THREADS=1 + ;; + *) + USE_PTHREADS=1 + ;; + esac + ;; + +esac + +dnl ======================================================== +dnl = +dnl = Set the default C compiler +dnl = +dnl ======================================================== +if test -z "$CC"; then + case "$target" in + + *-aix*) + if test -z "$USE_NSPR_THREADS"; then + CC=xlc_r + else + CC=xlc + fi + ;; + + *-hpux*) + CC=cc + ;; + + *-irix*) + CC=cc + ;; + + *-openvms*) + CC=cc + ;; + + *-osf*) + CC=cc + ;; + + *-solaris*) + CC=cc + ;; + + esac +fi + +dnl ======================================================== +dnl = +dnl = Set the default C++ compiler +dnl = +dnl ======================================================== +if test -z "$CXX"; then + case "$target" in + + *-aix*) + if test -z "$USE_NSPR_THREADS"; then + CXX=xlC_r + else + CXX=xlC + fi + ;; + + *-hpux*) + case "${target_os}" in + hpux10.30) + CXX=aCC + ;; + hpux11.*) + CXX=aCC + ;; + *) + CXX=CC + ;; + esac + ;; + + *-irix*) + CXX=CC + ;; + + *-openvms*) + CXX=cxx + ;; + + *-osf*) + CXX=cxx + ;; + + *-solaris*) + CXX=CC + ;; + + esac +fi + +if test -z "$SKIP_PATH_CHECKS"; then + AC_PATH_PROG(WHOAMI, $WHOAMI whoami, echo not_whoami) +fi + +if test -n "$MOZ_DEBUG"; then + AC_DEFINE(DEBUG) + DEFINES="$DEFINES -UNDEBUG" + + case "${target_os}" in + beos*) + DEFINES="$DEFINES -DDEBUG_${USER}" + ;; + msvc*|mks*|cygwin*|mingw*|os2*) + DEFINES="$DEFINES -DDEBUG_`echo ${USERNAME} | sed -e 's| |_|g'`" + ;; + *) + DEFINES="$DEFINES -DDEBUG_`$WHOAMI`" + ;; + esac +else + AC_DEFINE(NDEBUG) + DEFINES="$DEFINES -UDEBUG" +fi + +if test -z "$SKIP_COMPILER_CHECKS"; then +dnl ======================================================== +dnl Checks for compilers. +dnl ======================================================== +if test "$target" != "$host"; then + echo "cross compiling from $host to $target" + cross_compiling=yes + + _SAVE_CC="$CC" + _SAVE_CFLAGS="$CFLAGS" + _SAVE_LDFLAGS="$LDFLAGS" + + AC_MSG_CHECKING([for $host compiler]) + AC_CHECK_PROGS(HOST_CC, $HOST_CC gcc cc /usr/ucb/cc, "") + if test -z "$HOST_CC"; then + AC_MSG_ERROR([no acceptable cc found in \$PATH]) + fi + AC_MSG_RESULT([$HOST_CC]) + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi + if test -z "$HOST_LDFLAGS"; then + HOST_LDFLAGS="$LDFLAGS" + fi + + CC="$HOST_CC" + CFLAGS="$HOST_CFLAGS" + LDFLAGS="$HOST_LDFLAGS" + + AC_MSG_CHECKING([whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works]) + AC_TRY_COMPILE([], [return(0);], + [ac_cv_prog_host_cc_works=1 AC_MSG_RESULT([yes])], + AC_MSG_ERROR([installation or configuration problem: $host compiler $HOST_CC cannot create executables.]) ) + + CC=$_SAVE_CC + CFLAGS=$_SAVE_CFLAGS + LDFLAGS=$_SAVE_LDFLAGS + + case "$build:$target" in + powerpc-apple-darwin8*:i?86-apple-darwin*) + dnl The Darwin cross compiler doesn't necessarily point itself at a + dnl root that has libraries for the proper architecture, it defaults + dnl to the system root. The libraries in the system root on current + dnl versions of PPC OS X 10.4 aren't fat, so these target compiler + dnl checks will fail. Fake a working SDK in that case. + _SAVE_CFLAGS=$CFLAGS + _SAVE_CXXFLAGS=$CXXLAGS + CFLAGS="-isysroot /Developer/SDKs/MacOSX10.4u.sdk $CFLAGS" + CXXFLAGS="-isysroot /Developer/SDKs/MacOSX10.4u.sdk $CXXFLAGS" + ;; + esac + + AC_CHECK_PROGS(CC, $CC "${target_alias}-gcc" "${target}-gcc", echo) + unset ac_cv_prog_CC + AC_PROG_CC + if test -n "$USE_CPLUS"; then + AC_CHECK_PROGS(CXX, $CXX "${target_alias}-g++" "${target}-g++", echo) + unset ac_cv_prog_CXX + AC_PROG_CXX + fi + + case "$build:$target" in + powerpc-apple-darwin8*:i?86-apple-darwin*) + dnl Revert the changes made above. From this point on, the target + dnl compiler will never be used without applying the SDK to CFLAGS + dnl (see --with-macos-sdk below). + CFLAGS=$_SAVE_CFLAGS + CXXFLAGS=$_SAVE_CXXFLAGS + ;; + esac + + AC_CHECK_PROGS(RANLIB, $RANLIB "${target_alias}-ranlib" "${target}-ranlib", echo) + AC_CHECK_PROGS(AR, $AR "${target_alias}-ar" "${target}-ar", echo) + AC_CHECK_PROGS(AS, $AS "${target_alias}-as" "${target}-as", echo) + AC_CHECK_PROGS(LD, $LD "${target_alias}-ld" "${target}-ld", echo) + AC_CHECK_PROGS(STRIP, $STRIP "${target_alias}-strip" "${target}-strip", echo) + AC_CHECK_PROGS(WINDRES, $WINDRES "${target_alias}-windres" "${target}-windres", echo) + +else + AC_PROG_CC + if test -n "$USE_CPLUS"; then + if test "$CC" = "cl" -a -z "$CXX"; then + CXX=$CC + else + AC_PROG_CXX + fi + fi + AC_PROG_CPP + AC_PROG_RANLIB + AC_PATH_PROGS(AS, as, $CC) + AC_PATH_PROGS(AR, ar, echo not_ar) + AC_PATH_PROGS(LD, ld link, echo not_ld) + AC_PATH_PROGS(STRIP, strip, echo not_strip) + AC_PATH_PROGS(WINDRES, windres, echo not_windres) + if test -z "$HOST_CC"; then + HOST_CC="$CC" + fi + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi +fi + +if test "$GCC" = "yes"; then + GNU_CC=1 +fi +if test "$GXX" = "yes"; then + GNU_CXX=1 +fi +if test "`echo | $AS -v 2>&1 | grep -c GNU`" != "0"; then + GNU_AS=1 +fi +rm -f a.out + +case "$build:$target" in + i?86-apple-darwin*:powerpc-apple-darwin*) + dnl cross_compiling will have erroneously been set to "no" in this + dnl case, because the x86 build host is able to run ppc code in a + dnl translated environment, making a cross compiler appear native. + cross_compiling=yes + ;; +esac + +if test "$cross_compiling" = "yes"; then + CROSS_COMPILE=1 +else + CROSS_COMPILE= +fi + +dnl ======================================================== +dnl Check for gcc -pipe support +dnl ======================================================== +AC_MSG_CHECKING([for gcc -pipe support]) +if test -n "$GNU_CC" && test -n "$GNU_CXX" && test -n "$GNU_AS"; then + echo '#include ' > dummy-hello.c + echo 'int main() { printf("Hello World\n"); return 0; }' >> dummy-hello.c + ${CC} -S dummy-hello.c -o dummy-hello.s 2>&5 + cat dummy-hello.s | ${AS} -o dummy-hello.S - 2>&5 + if test $? = 0; then + _res_as_stdin="yes" + else + _res_as_stdin="no" + fi + if test "$_res_as_stdin" = "yes"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -pipe" + AC_TRY_COMPILE( [ #include ], + [printf("Hello World\n");], + [_res_gcc_pipe="yes"], + [_res_gcc_pipe="no"] ) + CFLAGS=$_SAVE_CFLAGS + fi + if test "$_res_as_stdin" = "yes" && test "$_res_gcc_pipe" = "yes"; then + _res="yes"; + CFLAGS="$CFLAGS -pipe" + CXXFLAGS="$CXXFLAGS -pipe" + else + _res="no" + fi + rm -f dummy-hello.c dummy-hello.s dummy-hello.S dummy-hello a.out + AC_MSG_RESULT([$_res]) +else + AC_MSG_RESULT([no]) +fi + +dnl =============================================================== +dnl Check for .hidden assembler directive and visibility attribute. +dnl Borrowed from glibc configure.in +dnl =============================================================== +if test "$GNU_CC"; then + AC_CACHE_CHECK(for visibility(hidden) attribute, + ac_cv_visibility_hidden, + [cat > conftest.c </dev/null 2>&1; then + if grep '\.hidden.*foo' conftest.s >/dev/null; then + ac_cv_visibility_hidden=yes + fi + fi + rm -f conftest.[cs] + ]) + if test "$ac_cv_visibility_hidden" = "yes"; then + AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE) + AC_CACHE_CHECK(for visibility pragma support, + ac_cv_visibility_pragma, + [cat > conftest.c </dev/null 2>&1; then + if grep '\.hidden.*foo_hidden' conftest.s >/dev/null; then + if ! grep '\.hidden.*foo_default' conftest.s > /dev/null; then + ac_cv_visibility_pragma=yes + fi + fi + fi + rm -f conftest.[cs] + ]) + if test "$ac_cv_visibility_pragma" = "yes"; then + AC_DEFINE(HAVE_VISIBILITY_PRAGMA) + # To work around a build problem on Linux x86-64 (Bugzilla bug + # 293438), we use the -fvisibility=hidden flag. This flag is less + # optimal than #pragma GCC visibility push(hidden) because the flag + # assumes that symbols defined outside the current source file have + # the default visibility. This has the advantage that we don't need + # to wrap system header files, but has the disadvantage that calls + # to hidden symbols defined in other source files cannot be + # optimized by the compiler. The -fvisibility=hidden flag does + # hide and export symbols correctly. + #VISIBILITY_FLAGS='-I$(dist_includedir)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h' + #WRAP_SYSTEM_INCLUDES=1 + VISIBILITY_FLAGS="-fvisibility=hidden" + WRAP_SYSTEM_INCLUDES= + fi + fi +fi # GNU_CC + +fi # SKIP_COMPILER_CHECKS + +dnl ======================================================== +dnl Checks for programs. +dnl ======================================================== +if test -z "$SKIP_PATH_CHECKS"; then + AC_PATH_PROGS(PERL, perl5 perl, echo not_perl) +elif test -z "$PERL"; then + PERL=perl +fi + +dnl ======================================================== +dnl Default platform specific options +dnl ======================================================== +OBJ_SUFFIX=o +LIB_SUFFIX=a +DLL_SUFFIX=so +ASM_SUFFIX=s +MKSHLIB='$(LD) $(DSO_LDOPTS) -o $@' +PR_MD_ASFILES= +PR_MD_CSRCS= +PR_MD_ARCH_DIR=unix +AR_FLAGS='cr $@' +AS='$(CC)' +ASFLAGS='$(CFLAGS)' + +if test -n "$CROSS_COMPILE"; then + OS_ARCH=`echo $target_os | sed -e 's|/|_|g'` + OS_RELEASE= + OS_TEST="${target_cpu}" + case "${target_os}" in + linux*) OS_ARCH=Linux ;; + solaris*) OS_ARCH=SunOS OS_RELEASE=5 ;; + mingw*) OS_ARCH=WINNT ;; + darwin*) OS_ARCH=Darwin ;; + esac +else + OS_ARCH=`uname -s | sed -e 's|/|_|g'` + OS_RELEASE=`uname -r` + OS_TEST=`uname -m` +fi + +if test "$OS_ARCH" = "IRIX64"; then + OS_ARCH=IRIX +fi + +if test "$OS_ARCH" = "AIX"; then + OS_RELEASE=`uname -v`.`uname -r` +fi + +if test "$OS_ARCH" = "FreeBSD"; then + OS_RELEASE=`echo $OS_RELEASE | sed 's/-.*//'` +fi + +if test "$OS_ARCH" = "Linux"; then + OS_RELEASE=`echo $OS_RELEASE | sed 's/-.*//'` + OS_RELEASE=`echo $OS_RELEASE | awk -F\. '{ print $1 "." $2 }'` +fi + +if test "$OS_ARCH" = "OpenVMS"; then + OS_RELEASE=`uname -v` +fi + +####################################################################### +# Master "Core Components" macros for getting the OS target # +####################################################################### + +# +# Note: OS_TARGET should be specified on the command line for gmake. +# When OS_TARGET=WIN95 is specified, then a Windows 95 target is built. +# The difference between the Win95 target and the WinNT target is that +# the WinNT target uses Windows NT specific features not available +# in Windows 95. The Win95 target will run on Windows NT, but (supposedly) +# at lesser performance (the Win95 target uses threads; the WinNT target +# uses fibers). +# +# When OS_TARGET=WIN16 is specified, then a Windows 3.11 (16bit) target +# is built. See: win16_3.11.mk for lots more about the Win16 target. +# +# If OS_TARGET is not specified, it defaults to $(OS_ARCH), i.e., no +# cross-compilation. +# + +# +# The following hack allows one to build on a WIN95 machine (as if +# s/he were cross-compiling on a WINNT host for a WIN95 target). +# It also accomodates for MKS's uname.exe. If you never intend +# to do development on a WIN95 machine, you don't need this hack. +# +case "$OS_ARCH" in +WIN95) + OS_ARCH=WINNT + OS_TARGET=WIN95 + ;; +Windows_95) + OS_ARCH=Windows_NT + OS_TARGET=WIN95 + ;; +Windows_98) + OS_ARCH=Windows_NT + OS_TARGET=WIN95 + ;; +CYGWIN_9*|CYGWIN_ME*) + OS_ARCH='CYGWIN_NT-4.0' + OS_TARGET=WIN95 + ;; +OS_2) + OS_ARCH=OS2 + OS_TARGET=OS2 + ;; +esac + +# +# On WIN32, we also define the variable CPU_ARCH. +# + +case "$OS_ARCH" in +WINNT) + CPU_ARCH=`uname -p` + if test "$CPU_ARCH" = "I386"; then + CPU_ARCH=x86 + fi + ;; +Windows_NT) +# +# If uname -s returns "Windows_NT", we assume that we are using +# the uname.exe in MKS toolkit. +# +# The -r option of MKS uname only returns the major version number. +# So we need to use its -v option to get the minor version number. +# Moreover, it doesn't have the -p option, so we need to use uname -m. +# + OS_ARCH=WINNT + OS_MINOR_RELEASE=`uname -v` + if test "$OS_MINOR_RELEASE" = "00"; then + OS_MINOR_RELEASE=0 + fi + OS_RELEASE="${OS_RELEASE}.${OS_MINOR_RELEASE}" + CPU_ARCH=`uname -m` + # + # MKS's uname -m returns "586" on a Pentium machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi + ;; +CYGWIN_NT*|MINGW*_NT*) +# +# If uname -s returns "CYGWIN_NT-4.0", we assume that we are using +# the uname.exe in the Cygwin tools. +# If uname -s returns MINGW32_NT-5.1, we assume that we are using +# the uname.exe in the MSYS tools. +# + OS_RELEASE=`expr $OS_ARCH : '.*NT-\(.*\)'` + OS_ARCH=WINNT + CPU_ARCH=`uname -m` + # + # Cygwin's uname -m returns "i686" on a Pentium Pro machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi + ;; +esac + +if test -n "$MOZILLA_CLIENT" && test "$OS_ARCH" = "WINNT"; then + OS_TARGET=WIN95 + if test -n "$MOZ_DEBUG"; then + USE_DEBUG_RTL=1 + fi +fi +if test -z "$OS_TARGET"; then + OS_TARGET=$OS_ARCH +fi +if test "$OS_TARGET" = "WIN95"; then + OS_RELEASE="4.0" +fi +if test "$OS_TARGET" = "WIN16"; then + OS_RELEASE= +fi +OS_CONFIG="${OS_TARGET}${OS_RELEASE}" + +dnl ======================================================== +dnl Enable high-memory support on OS/2 by default. +dnl ======================================================== +AC_ARG_ENABLE(os2-high-mem, + [ --disable-os2-high-mem Disable high-memory support on OS/2], + [ if test "$enableval" = "no"; then + MOZ_OS2_HIGH_MEMORY= + else + MOZ_OS2_HIGH_MEMORY=1 + fi ]) + +dnl ======================================================== +dnl Override of system specific host options +dnl ======================================================== +case "$host" in +*-mingw*) + NSINSTALL=nsinstall + ;; +*-cygwin*|*-msvc*|*-mks*) + NSINSTALL='$(CYGWIN_WRAPPER) nsinstall' + if test `echo "${PATH}" | grep -c \;` = 0; then + CYGWIN_WRAPPER='sh $(topsrcdir)/build/cygwin-wrapper' + fi + ;; +*-beos*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_BEOS -DBeOS -DBEOS -D_POSIX_SOURCE" + ;; +*os2*) + ;; +*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + ;; +esac + +dnl ======================================================== +dnl Override of system specific target options +dnl ======================================================== +case "$target" in + +*-aix*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(AIX) + AC_DEFINE(SYSV) + DSO_LDOPTS='-brtl -bnortllib -bM:SRE -bnoentry -bexpall -blibpath:/usr/lib:/lib' + AC_CHECK_HEADER(sys/atomic_op.h, AC_DEFINE(AIX_HAVE_ATOMIC_OP_H)) + case "${target_os}" in + aix3.2*) + AC_DEFINE(AIX_RENAME_SELECT) + AC_DEFINE(_PR_NO_LARGE_FILES) + AIX_LINK_OPTS='-bnso -berok' + PR_MD_ASFILES=os_AIX.s + ;; + aix4.1*) + AC_DEFINE(AIX_TIMERS) + AC_DEFINE(_PR_NO_LARGE_FILES) + AC_DEFINE(AIX4_1) + MKSHLIB= + DSO_LDOPTS= + AIX_LINK_OPTS='-bnso -berok' + LIBNSPR='-L$(dist_libdir) -lnspr$(MOD_MAJOR_VERSION)_shr' + LIBPLC='-L$(dist_libdir) -lplc$(MOD_MAJOR_VERSION)_shr' + ;; + aix4.2*) + AC_DEFINE(AIX_TIMERS) + AC_DEFINE(_PR_HAVE_OFF64_T) + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + aix4.3*) + AC_DEFINE(AIX_TIMERS) + AC_DEFINE(_PR_HAVE_OFF64_T) + AC_DEFINE(AIX4_3_PLUS) + AC_DEFINE(HAVE_SOCKLEN_T) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + USE_IPV6=1 + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + *) + AC_DEFINE(AIX_TIMERS) + AC_DEFINE(_PR_HAVE_OFF64_T) + AC_DEFINE(AIX4_3_PLUS) + AC_DEFINE(HAVE_SOCKLEN_T) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + USE_IPV6=1 + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + esac + CFLAGS="$CFLAGS -qro -qroconst" + AIX_WRAP='$(DIST)/lib/aixwrap.o' + AIX_TMP='./_aix_tmp.o' + if test -n "$USE_64"; then + MDCPUCFG_H=_aix64.cfg + OBJECT_MODE=64 + else + MDCPUCFG_H=_aix32.cfg + fi + PR_MD_CSRCS=aix.c + RESOLVE_LINK_SYMBOLS=1 + ;; + +*-beos*) + AC_DEFINE(XP_BEOS) + AC_DEFINE(BeOS) + AC_DEFINE(BEOS) + AC_DEFINE(_POSIX_SOURCE) + DSO_LDOPTS=-nostart + MDCPUCFG_H=_beos.cfg + USE_BTHREADS=1 + PR_MD_ARCH_DIR=beos + RESOLVE_LINK_SYMBOLS=1 + case "${target_cpu}" in + i*86) + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS='-gdwarf-2 -O0' + MKSHLIB='$(CCC) $(DSO_LDOPTS) -o $@' + AC_CHECK_LIB(bind, gethostbyaddr, [OS_LIBS="$OS_LIBS -lbind -lsocket"]) + ;; + powerpc) + CC=mwcc + CCC=mwcc + LD=mwld + DSO_LDOPTS='-xms -export pragma -init _init_routine_ -term _term_routine_ -lroot -lnet /boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o /boot/develop/lib/ppc/start_dyn.o' + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS='-g -O0' + ;; + esac + ;; + +*-bsdi*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(BSDI) + AC_DEFINE(NEED_BSDREGEX) + + CFLAGS="$CFLAGS -Wall -Wno-format" + CXXFLAGS="$CXXFLAGS -Wall -Wno-format" + + if echo "$OS_TEST" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + elif echo "$OS_TEST" | grep -c sparc >/dev/null; then + CPU_ARCH=sparc + fi + + MDCPUCFG_H=_bsdi.cfg + PR_MD_CSRCS=bsdi.c + + DSO_LDOPTS=-r + + case "$target_os" in + bsdi1.1*) + AC_DEFINE(_PR_BSDI_JMPBUF_IS_ARRAY) + AC_DEFINE(_PR_STAT_HAS_ONLY_ST_ATIME) + AC_DEFINE(_PR_NEED_H_ERRNO) + MKSHLIB= + DSO_CFLAGS= + DSO_LDOPTS= + ;; + + bsdi2.1*) + AC_DEFINE(_PR_TIMESPEC_HAS_TS_SEC) + AC_DEFINE(_PR_BSDI_JMPBUF_IS_ARRAY) + AC_DEFINE(HAVE_DLL) + AC_DEFINE(USE_DLFCN) + AC_DEFINE(_PR_STAT_HAS_ST_ATIMESPEC) + PR_MD_ASFILES=os_BSD_OS_386_2.s + ;; + + bsdi4.* | bsdi5.*) + AC_DEFINE(_PR_SELECT_CONST_TIMEVAL) + AC_DEFINE(_PR_BSDI_JMPBUF_IS_STRUCT) + AC_DEFINE(HAVE_DLL) + AC_DEFINE(USE_DLFCN) + AC_DEFINE(_PR_STAT_HAS_ST_ATIMESPEC) + MKSHLIB='$(CC) -o $@ $(DSO_LDOPTS)' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname,$(@:$(OBJDIR)/%.so=%.so)' + STRIP="$STRIP -d" + case "$target_os" in + bsdi4.2* | bsdi4.3* | bsdi5.*) + AC_DEFINE(_PR_HAVE_GETPROTO_R) + AC_DEFINE(_PR_HAVE_GETPROTO_R_POINTER) + ;; + esac + ;; + *) + AC_DEFINE(_PR_SELECT_CONST_TIMEVAL) + AC_DEFINE(_PR_BSDI_JMPBUF_IS_STRUCT) + AC_DEFINE(HAVE_DLL) + AC_DEFINE(USE_DLFCN) + AC_DEFINE(_PR_STAT_HAS_ST_ATIMESPEC) + ;; + esac + + ;; + +*-darwin*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(DARWIN) + AC_DEFINE(HAVE_BSD_FLOCK) + CFLAGS="$CFLAGS -Wmost -fno-common" + case "${target_cpu}" in + i*86*) + AC_DEFINE(i386) + CPU_ARCH=i386 + PR_MD_ASFILES=os_Darwin_x86.s + ;; + *) + AC_DEFINE(ppc) + CPU_ARCH=ppc + PR_MD_ASFILES=os_Darwin_ppc.s + ;; + esac + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-dynamiclib -compatibility_version 1 -current_version 1 -all_load -install_name @executable_path/$@ -headerpad_max_install_names' + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + STRIP="$STRIP -x -S" + DLL_SUFFIX=dylib + USE_PTHREADS=1 + MDCPUCFG_H=_darwin.cfg + PR_MD_CSRCS=darwin.c + + # Add Mac OS X support for loading CFM & CFBundle plugins + if test -f /System/Library/Frameworks/Carbon.framework/Carbon; then + AC_DEFINE(XP_MACOSX) + OS_TARGET=MacOSX + + if test -n "$_MACOSX_DEPLOYMENT_TARGET" ; then + dnl Use the specified value + export MACOSX_DEPLOYMENT_TARGET=$_MACOSX_DEPLOYMENT_TARGET + elif test -z "$MACOSX_DEPLOYMENT_TARGET" ; then + dnl No value specified on the command line or in the environment, + dnl use the lesser of the library's minimum or the architecture's + dnl minimum. + case "${target_cpu}" in + powerpc*) + dnl Architecture minimum 10.2 + export MACOSX_DEPLOYMENT_TARGET=10.2 + ;; + i*86*) + dnl Architecture minimum 10.4 + export MACOSX_DEPLOYMENT_TARGET=10.4 + ;; + esac + fi + + dnl MACOS_SDK_DIR will be set to the SDK location whenever one is + dnl in use. NEXT_ROOT will be set and exported if it's needed for + dnl ld. + + if test "$MACOS_SDK_DIR"; then + dnl Sync this section with the one in Mozilla's top level. + + if test ! -d "$MACOS_SDK_DIR"; then + AC_MSG_ERROR([SDK not found. When using --with-macos-sdk, you must +specify a valid SDK. SDKs are installed when the optional cross-development +tools are selected during the Xcode/Developer Tools installation.]) + fi + + changequote(,) + CC_VERSION=`$CC -v 2>&1 | grep 'gcc version'` + GCC_VERSION_FULL=`echo $CC_VERSION | $PERL -pe 's/^.*gcc version ([^ ]*).*/$1/'` + GCC_VERSION=`echo $GCC_VERSION_FULL | $PERL -pe '(split(/\./))[0]>=4&&s/(^\d*\.\d*).*/$1/;'` + changequote([,]) + GCC_VERSION_MAJOR=`echo $GCC_VERSION_FULL | $PERL -pe 's/(^\d*).*/$1/;'` + if test "$GCC_VERSION_MAJOR" -lt "4" ; then + SDK_C_FRAMEWORK="-F${MACOS_SDK_DIR}/System/Library/Frameworks" + if test -d "${MACOS_SDK_DIR}/Library/Frameworks" ; then + SDK_C_FRAMEWORK="$SDK_C_FRAMEWORK -F${MACOS_SDK_DIR}/Library/Frameworks" + fi + + SDK_C_INCLUDE="-isystem ${MACOS_SDK_DIR}/usr/include/gcc/darwin/${GCC_VERSION} -isystem ${MACOS_SDK_DIR}/usr/include ${SDK_C_FRAMEWORK}" + + CFLAGS="$CFLAGS -nostdinc ${SDK_C_INCLUDE}" + + dnl CPP needs to be set for AC_CHECK_HEADER. + CPP="$CPP -nostdinc ${SDK_C_INCLUDE}" + + changequote(,) + HOST_DARWIN_MAJOR=`echo "$build_os" | sed -E -e 's/^darwin([0-9]+).*$/\1/'` + changequote([,]) + if test "$HOST_DARWIN_MAJOR" -lt 9 ; then + dnl The build host is running Tiger (10.4) or earlier. + dnl ld support for -syslibroot is compiler-agnostic, but + dnl only available on Tiger and later. On Tiger and + dnl earlier build hosts, just rely on NEXT_ROOT, because + dnl it's not been shown to cause any problems. + MACOS_SDK_LIBS="-L${MACOS_SDK_DIR}/usr/lib/gcc/darwin -L${MACOS_SDK_DIR}/usr/lib/gcc/darwin/${GCC_VERSION_FULL} -L${MACOS_SDK_DIR}/usr/lib ${SDK_C_FRAMEWORK}" + else + dnl The build host is running Leopard (10.5) or later. + dnl With NEXT_ROOT set, the linker will still not apply + dnl it when resolving dependencies. This causes problems + dnl on Leopard, where an SDK depends on frameworks which + dnl were present in earlier OS releases (and the associated + dnl SDK) but not in Leopard. -syslibroot does not have + dnl this problem, but it results in harmless warnings when + dnl NEXT_ROOT is set. NEXT_ROOT needs to remain set even + dnl on Leopard because the compiler uses it too. + MACOS_SDK_LIBS="-Wl,-syslibroot,${MACOS_SDK_DIR}" + fi + + dnl LDFLAGS is for the utilities built in config (now and + dnl nsinstall). DSO_LDOPTS is used when linking shared + dnl libraries. + LDFLAGS="${MACOS_SDK_LIBS} $LDFLAGS" + DSO_LDOPTS="${MACOS_SDK_LIBS} $DSO_LDOPTS" + export NEXT_ROOT=$MACOS_SDK_DIR + + if test -n "$CROSS_COMPILE" ; then + dnl NEXT_ROOT will be in the environment, but it + dnl shouldn't be set for the build host. HOST_CXX is + dnl presently unused. + HOST_CC="NEXT_ROOT= $HOST_CC" + HOST_CXX="NEXT_ROOT= $HOST_CXX" + fi + else + dnl gcc >= 4.0 uses different paths than above, but knows + dnl how to find them itself. + CFLAGS="$CFLAGS -isysroot ${MACOS_SDK_DIR}" + + dnl CPP needs to be set for AC_CHECK_HEADER. + CPP="$CPP -isysroot ${MACOS_SDK_DIR}" + + dnl If gcc >= 4.0.0, we're guaranteed to be on Tiger, which + dnl has an ld that supports -syslibroot. Don't set + dnl NEXT_ROOT because it will be ignored and cause + dnl warnings when -syslibroot is specified. + dnl + dnl Both LDFLAGS and DSO_LDOPTS are set here, see the + dnl gcc < 4.0 case for the explanation. + if test "$GCC_VERSION_FULL" != "4.0.0" ; then + dnl gcc > 4.0.0 will pass -syslibroot to ld automatically + dnl based on the -isysroot it receives. + LDFLAGS="$LDFLAGS -isysroot ${MACOS_SDK_DIR}" + DSO_LDOPTS="$DSO_LDOPTS -isysroot ${MACOS_SDK_DIR}" + else + dnl gcc 4.0.0 doesn't pass -syslibroot to ld, it needs + dnl to be explicit. + LDFLAGS="$LDFLAGS -Wl,-syslibroot,${MACOS_SDK_DIR}" + DSO_LDOPTS="$DSO_LDOPTS -Wl,-syslibroot,${MACOS_SDK_DIR}" + fi + fi + fi + fi + ;; + +*-dgux*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + AC_DEFINE(SVR4) + AC_DEFINE(SYSV) + AC_DEFINE(DGUX) + AC_DEFINE(_DGUX_SOURCE) + AC_DEFINE(_POSIX4A_DRAFT6_SOURCE) + DSO_LDOPTS=-G + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS= + MDCPUCFG_H=_dgux.cfg + PR_MD_CSRCS=dgux.c + ;; + +*-freebsd*) + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + fi + AC_DEFINE(XP_UNIX) + AC_DEFINE(FREEBSD) + AC_DEFINE(HAVE_BSD_FLOCK) + AC_DEFINE(HAVE_SOCKLEN_T) + CFLAGS="$CFLAGS $(DSO_CFLAGS) -ansi -Wall" + MOZ_OBJFORMAT=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + if test "$MOZ_OBJFORMAT" = "elf"; then + DLL_SUFFIX=so + else + DLL_SUFFIX=so.1.0 + fi + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' + MDCPUCFG_H=_freebsd.cfg + PR_MD_CSRCS=freebsd.c + ;; + +*-hpux*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(HPUX) + AC_DEFINE(_HPUX_SOURCE) + # OSF1 and HPUX report the POLLHUP event for a socket when the + # shutdown(SHUT_WR) operation is called for the remote end, even though + # the socket is still writeable. Use select(), instead of poll(), to + # workaround this problem. + AC_DEFINE(_PR_POLL_WITH_SELECT) + AC_DEFINE(_USE_BIG_FDS) + DSO_LDOPTS='-b +h $(notdir $@)' + PR_MD_CSRCS=hpux.c + if test "$OS_TEST" = "ia64"; then + DLL_SUFFIX=so + DSO_LDOPTS="$DSO_LDOPTS +b '\$\$ORIGIN'" + CPU_ARCH_TAG=_$OS_TEST + if test -z "$USE_64"; then + COMPILER_TAG=_32 + fi + PR_MD_ASFILES=os_HPUX_ia64.s + else + AC_DEFINE(hppa) + DLL_SUFFIX=sl + PR_MD_ASFILES=os_HPUX.s + fi + if test -n "$USE_64"; then + MDCPUCFG_H=_hpux64.cfg + else + MDCPUCFG_H=_hpux32.cfg + fi + if test -z "$GNU_CC"; then + CC="$CC -Ae" + CXX="$CXX -ext" + DSO_CFLAGS=+Z + else + DSO_CFLAGS=-fPIC + fi + + if test -n "$MOZILLA_CLIENT"; then + DEFAULT_IMPL_STRATEGY=_EMU + fi + + if echo "$OS_RELEASE" | grep ^A.09 >/dev/null; then + AC_DEFINE(_PR_NEED_H_ERRNO) + AC_DEFINE(HPUX9) + DEFAULT_IMPL_STRATEGY=_EMU + USE_NSPR_THREADS=1 + fi + + if echo "$OS_RELEASE" | egrep '^(A.09|B.10)' >/dev/null; then + AC_DEFINE(_PR_NO_LARGE_FILES) + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + AC_DEFINE(_PR_NEED_H_ERRNO) + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + AC_DEFINE(HAVE_INT_LOCALTIME_R) + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.30|B.11)' >/dev/null; then + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + + # HP-UX 11i v2 (B.11.23) or higher + changequote(<<,>>) + case "$OS_RELEASE" in + [C-Z]*|B.[2-9]*|B.1[2-9]*|B.11.[3-9]*|B.11.2[3-9]*) + USE_IPV6=1 + ;; + esac + changequote([,]) + + if test "$OS_RELEASE" = "B.10.01"; then + AC_DEFINE(HPUX10) + DEFAULT_IMPL_STRATEGY=_EMU + fi + + if test "$OS_RELEASE" = "B.10.10"; then + AC_DEFINE(HPUX10) + AC_DEFINE(HPUX10_10) + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$OS_RELEASE" = "B.10.20"; then + AC_DEFINE(HPUX10) + AC_DEFINE(HPUX10_20) + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS +DAportable +DS1.1" + CXXFLAGS="$CXXFLAGS +DAportable +DS1.1" + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$OS_RELEASE" = "B.10.30"; then + AC_DEFINE(HPUX10) + AC_DEFINE(HPUX10_30) + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS +DAportable +DS1.1" + CXXFLAGS="$CXXFLAGS +DAportable +DS1.1" + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if echo "$OS_RELEASE" | grep ^B.11 >/dev/null; then + AC_DEFINE(HPUX10) + AC_DEFINE(HPUX11) + AC_DEFINE(_LARGEFILE64_SOURCE) + AC_DEFINE(_PR_HAVE_OFF64_T) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + if test -z "$GNU_CC"; then + if test -z "$USE_64"; then + if test "$OS_TEST" = "ia64"; then + CFLAGS="$CFLAGS +DD32" + CXXFLAGS="$CXXFLAGS +DD32" + else + CFLAGS="$CFLAGS +DAportable +DS2.0" + CXXFLAGS="$CXXFLAGS +DAportable +DS2.0" + fi + else + if test "$OS_TEST" = "ia64"; then + CFLAGS="$CFLAGS +DD64" + CXXFLAGS="$CXXFLAGS +DD64" + else + CFLAGS="$CFLAGS +DA2.0W +DS2.0" + CXXFLAGS="$CXXFLAGS +DA2.0W +DS2.0" + fi + fi + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$DEFAULT_IMPL_STRATEGY" = "_EMU"; then + USE_NSPR_THREADS=1 + USE_PTHREADS= + USE_USER_THREADS= + elif test "$DEFAULT_IMPL_STRATEGY" = "_PTH"; then + USE_PTHREADS=1 + if test "$USE_NSPR_THREADS"; then + USE_PTHREADS= + fi + if test "$USE_USER_PTHREADS"; then + USE_PTHREADS= + fi + fi + ;; + +*-irix*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(IRIX) + AC_DEFINE(SVR4) + AC_DEFINE(_SGI_MP_SOURCE) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + PR_MD_CSRCS=irix.c + PR_MD_ASFILES=os_Irix.s + MKSHLIB='$(LD) $(DSO_LDOPTS) -rdata_shared -shared -soname $(notdir $@) -o $@' + STRIP="$STRIP -f" + RESOLVE_LINK_SYMBOLS=1 + if test -n "$USE_64"; then + MDCPUCFG_H=_irix64.cfg + else + MDCPUCFG_H=_irix32.cfg + fi + case "${target_os}" in + irix6*) + AC_DEFINE(IRIX6) + USE_PTHREADS=1 + USE_N32=1 + COMPILER_TAG=_n32 + IMPL_STRATEGY=_PTH + ;; + irix5*) + AC_DEFINE(IRIX5) + USE_NSPR_THREADS=1 + ;; + *) + USE_PTHREADS=1 + USE_N32=1 + ;; + esac + if test "$GNU_CC"; then + dnl + dnl If we are using gcc with native binutils, we need to + dnl suppress the + dnl #lineno "filename" num num + dnl lines, which confuse IRIX native as. Add -Wp,-P to the + dnl gcc command line, which passes -P to the preprocessor. + dnl + AS='$(CC) -Wp,-P -x assembler-with-cpp -D_ASM -mips2 $(INCLUDES)' + CFLAGS="$CFLAGS -Wall -Wno-format" + _OPTIMIZE_FLAGS="-O6" + else + if test -n "$USE_N32"; then + AS='as -D_ASM $(INCLUDES) -n32' + else + AS='as -D_ASM $(INCLUDES)' + fi + CFLAGS="$CFLAGS -fullwarn -xansi" + if test "$USE_N32"; then + _OPTIMIZE_FLAGS="-O -OPT:Olimit=4000" + else + _OPTIMIZE_FLAGS="-O -Olimit 4000" + fi + if test "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + fi + case "${target}" in + *-irix6.*) + CFLAGS="$CFLAGS -multigot" + DSO_LDOPTS="-no_unresolved" + if test "$USE_N32"; then + CFLAGS="$CFLAGS -n32 -woff 1209" + DSO_LDOPTS="$DSO_LDOPTS -n32" + else + if test "$USE_64"; then + CFLAGS="$CFLAGS -64" + else + CFLAGS="$CFLAGS -32" + fi + fi + ;; + *) + CFLAGS="$CFLAGS -xgot" + ;; + esac + fi + if test "${target_os}" = "irix5.3"; then + AC_DEFINE(IRIX5_3) + fi + case "${target_os}" in + irix6.5) + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS -mips3" + fi + AC_DEFINE(_PR_HAVE_GETPROTO_R) + AC_DEFINE(_PR_HAVE_GETPROTO_R_POINTER) + AC_DEFINE(_PR_HAVE_SGI_PRDA_PROCMASK) + ;; + irix5*) + ;; + *) + AC_DEFINE(_PR_HAVE_SGI_PRDA_PROCMASK) + ;; + esac + ;; + +*-linux*|*-gnu*|*-k*bsd*-gnu) + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + IMPL_STRATEGY=_PTH + fi + AC_DEFINE(XP_UNIX) + AC_DEFINE(_GNU_SOURCE) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + case "${target_os}" in + linux*) + AC_DEFINE(LINUX) + ;; + esac + CFLAGS="$CFLAGS -Wall" + CXXFLAGS="$CXXFLAGS -Wall" + MDCPUCFG_H=_linux.cfg + PR_MD_CSRCS=linux.c + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS="-g -fno-inline" # most people on linux use gcc/gdb, and that + # combo is not yet good at debugging inlined + # functions (even when using DWARF2 as the + # debugging format) + COMPILER_TAG=_glibc + if echo "$OS_TEST" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + else + CPU_ARCH=$OS_TEST + fi + CPU_ARCH_TAG=_${CPU_ARCH} + case "${target_cpu}" in + alpha) + AC_DEFINE(_ALPHA_) + AC_DEFINE(__alpha) + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + ;; + i*86) + AC_DEFINE(i386) + PR_MD_ASFILES=os_Linux_x86.s + ;; + ia64) + PR_MD_ASFILES=os_Linux_ia64.s + ;; + x86_64) + if test -n "$USE_64"; then + PR_MD_ASFILES=os_Linux_x86_64.s + else + AC_DEFINE(i386) + PR_MD_ASFILES=os_Linux_x86.s + CC="$CC -m32" + CXX="$CXX -m32" + fi + ;; + ppc|powerpc) + PR_MD_ASFILES=os_Linux_ppc.s + ;; + powerpc64) + if test -n "$USE_64"; then + CC="$CC -m64" + CXX="$CXX -m64" + else + PR_MD_ASFILES=os_Linux_ppc.s + fi + ;; + m68k) + CFLAGS="$CFLAGS -m68020-60" + CXXFLAGS="$CXXFLAGS -m68020-60" + ;; + esac + ;; + +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + AC_DEFINE(XP_PC) + AC_DEFINE(WIN32) + PR_MD_ARCH_DIR=windows + RESOLVE_LINK_SYMBOLS=1 + + if test -n "$GNU_CC"; then + CC="$CC -mno-cygwin" + CXX="$CXX -mno-cygwin" + DLL_SUFFIX=dll + MKSHLIB='$(CC) -shared -Wl,--export-all-symbols -Wl,--out-implib -Wl,$(IMPORT_LIBRARY) $(DLLBASE) -o $(subst $(OBJDIR)/,,$(SHARED_LIBRARY))' + RC=$WINDRES + # Use temp file for windres (bug 213281) + RCFLAGS='-O coff --use-temp-file' + else + CC=cl + CXX=cl + LD=link + AR='lib -NOLOGO -OUT:"$@"' + AR_FLAGS= + RANLIB='echo not_ranlib' + STRIP='echo not_strip' + RC=rc.exe + GARBAGE='$(OBJDIR)/vc20.pdb $(OBJDIR)/vc40.pdb' + OBJ_SUFFIX=obj + LIB_SUFFIX=lib + DLL_SUFFIX=dll + + # Determine compiler version + CC_VERSION=`"${CC}" -v 2>&1 | grep Version | sed -e 's|.* Version ||' -e 's| .*||'` + _CC_MAJOR_VERSION=`echo $CC_VERSION | awk -F\. '{ print $1 }'` + _CC_MINOR_VERSION=`echo $CC_VERSION | awk -F\. '{ print $2 }'` + MSC_VER=${_CC_MAJOR_VERSION}${_CC_MINOR_VERSION} + + # Ensure that mt is Microsoft (R) Manifest Tool and not magnetic + # tape manipulation utility (or something else) + if test "$MSC_VER" -ge "1400"; then + changequote(,) + _MSMT_VER_FILTER='s|.* \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p' + changequote([,]) + + MSMT_TOOL=`mt 2>&1|grep 'Microsoft (R) Manifest Tool'` + if test -n "$MSMT_TOOL"; then + MSMANIFEST_TOOL_VERSION=`echo ${MSMT_TOOL}|sed -ne "$_MSMT_VER_FILTER"` + if test -z "$MSMANIFEST_TOOL_VERSION"; then + AC_MSG_WARN([Unknown version of the Microsoft (R) Manifest Tool.]) + fi + MT=mt + unset MSMT_TOOL + else + AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.]) + fi + fi + + CFLAGS="$CFLAGS -W3 -nologo -GF -Gy" + DLLFLAGS="$DLLFLAGS -OUT:\"\$@\"" + _DEBUG_FLAGS=-Z7 + _OPTIMIZE_FLAGS=-O2 + if test -z "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS -Od" + fi + + if test -n "$USE_DEBUG_RTL"; then + CFLAGS="$CFLAGS -MDd" + else + CFLAGS="$CFLAGS -MD" + fi + + if test -n "$MOZ_DEBUG"; then + AC_DEFINE(_DEBUG) + else + DEFINES="$DEFINES -U_DEBUG" + fi + + if test -n "$MOZ_OPTIMIZE"; then + if test -n "$MOZ_PROFILE"; then + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Z7" + fi + if test -n "$MOZ_DEBUG_SYMBOLS"; then + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Zi" + fi + if test -n "$MOZ_PROFILE" -o -n "$MOZ_DEBUG_SYMBOLS"; then + DLLFLAGS="$DLLFLAGS -DEBUG -OPT:REF" + LDFLAGS="$LDFLAGS -DEBUG -OPT:REF" + fi + fi + + if test -n "$MOZ_DEBUG"; then + DLLFLAGS="$DLLFLAGS -DEBUG" + LDFLAGS="$LDFLAGS -DEBUG" + fi + + OS_DLLFLAGS="-nologo -DLL -SUBSYSTEM:WINDOWS" + if test "$MSC_VER" -le "1200" -a -z "$MOZ_DEBUG_SYMBOLS"; then + OS_DLLFLAGS="$OS_DLLFLAGS -PDB:NONE" + fi + + if test "$OS_TARGET" = "WINNT"; then + CFLAGS="$CFLAGS -GT" + LIBNSPR='$(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + else + LIBNSPR='$(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + fi + fi # GNU_CC + + if test -n "$USE_STATIC_TLS"; then + AC_DEFINE(_PR_USE_STATIC_TLS) + fi + + if test "$OS_TARGET" = "WINNT"; then + AC_DEFINE(WINNT) + else + AC_DEFINE(WIN95) + # undefine WINNT as some versions of mingw gcc define it by default + DEFINES="$DEFINES -UWINNT" + AC_DEFINE(_PR_GLOBAL_THREADS_ONLY) + fi + + if test "$CPU_ARCH" = "x86"; then + CPU_ARCH_TAG= + else + CPU_ARCH_TAG=$CPU_ARCH + fi + + if test -n "$USE_DEBUG_RTL"; then + OBJDIR_SUFFIX=OBJD + fi + + case "$OS_TARGET" in + WINNT) + MDCPUCFG_H=_winnt.cfg + ;; + WIN95) + MDCPUCFG_H=_win95.cfg + ;; + WIN16) + MDCPUCFG_H=_win16.cfg + ;; + *) + AC_MSG_ERROR([Missing OS_TARGET for ${target}. Use --enable-win32-target to set.]) + ;; + esac + + case "$target_cpu" in + i*86) + if test -n "$USE_64"; then + AC_DEFINE(_AMD64_) + AC_DEFINE(_M_AMD64) + else + AC_DEFINE(_X86_) + fi + ;; + alpha) + AC_DEFINE(_ALPHA_) + ;; + mips) + AC_DEFINE(_MIPS_) + ;; + x86_64) + AC_DEFINE(_AMD64_) + AC_DEFINE(_M_AMD64) + USE_64=1 + ;; + ia64) + AC_DEFINE(_IA64_) + AC_DEFINE(_M_IA64) + USE_64=1 + ;; + *) + AC_DEFINE(_CPU_ARCH_NOT_DEFINED) + ;; + esac + + if test "$USE_64"; then + AC_DEFINE(_WIN64) + fi + + ;; + +*-ncr-sysv*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SVR4) + AC_DEFINE(SYSV) + AC_DEFINE(NCR) + USE_NSPR_THREADS=1 + if test "$OS_RELEASE" = "2.03"; then + AC_DEFINE(_PR_STAT_HAS_ST_ATIM) + else + AC_DEFINE(_PR_STAT_HAS_ST_ATIM_UNION) + fi + + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS -Hnocopyr" + CXXFLAGS="$CXXFLAGS -Hnocopyr" + else + CFLAGS="$CFLAGS -fPIC -Wall" + CXXFLAGS="$CXXFLAGS -fPIC -Wall" + DSO_LDOPTS=-G + fi + MDCPUCFG_H=_ncr.cfg + PR_MD_CSRCS=ncr.c + ;; + +mips-nec-sysv*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SVR4) + AC_DEFINE(__SVR4) + AC_DEFINE(NEC) + AC_DEFINE(nec_ews) + USE_NSPR_THREADS=1 + if test -z "$GNU_CC"; then + CC='$(NSDEPTH)/build/hcc cc -Xa -KGnum=0 -KOlimit=4000' + CXX=g++ + fi + OS_LIBS="$OS_LIBS -lsocket -lnsl -ldl" + DSO_LDOPTS=-G + MDCPUCFG_H=_nec.cfg + PR_MD_CSRCS=nec.c + ;; + +*-netbsd*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(NETBSD) + AC_DEFINE(HAVE_BSD_FLOCK) + USE_NSPR_THREADS=1 + MDCPUCFG_H=_netbsd.cfg + PR_MD_CSRCS=netbsd.c + + DSO_CFLAGS='-fPIC -DPIC' + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + MKSHLIB='$(CC) -o $@ $(DSO_LDOPTS)' + + if test -z "$OBJECT_FMT"; then + if echo __ELF__ | ${CC-cc} -E - | grep -q __ELF__ 2>/dev/null; then + OBJECT_FMT=a.out + DLL_SUFFIX=so.1.0 + DSO_LDOPTS='-shared' + else + OBJECT_FMT=ELF + DLL_SUFFIX=so + DSO_LDOPTS='-shared -Wl,-soname,$(notdir $@)' + fi + fi + + if test "$LIBRUNPATH"; then + DSO_LDOPTS="$DSO_LDOPTS -Wl,-R$LIBRUNPATH" + fi + ;; + +mips-sony-newsos*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SONY) + AC_DEFINE(SYSV) + AC_DEFINE(SVR4) + AC_DEFINE(__svr4) + AC_DEFINE(__svr4__) + AC_DEFINE(HAVE_SVID_GETTOD) + USE_NSPR_THREADS=1 + CFLAGS="$CFLAGS -Xa -fullwarn" + CXXFLAGS="$CXXFLAGS -Xa -fullwarn" + DSO_LDOPTS=-G + MDCPUCFG_H=_sony.cfg + PR_MD_CSRCS=sony.c + ;; + +*-nextstep*|*-openstep*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(NEXTSTEP) + AC_DEFINE(HAVE_BSD_FLOCK) + AC_DEFINE(_POSIX_SOURCE) + CFLAGS="$CFLAGS -Wall -fno-common -traditional-cpp -posix" + CXXFLAGS="$CXXFLAGS -Wall -fno-common -traditional-cpp -posix" + USE_NSPR_THREADS=1 + DLL_SUFFIX=dylib + MDCPUCFG_H=_nextstep.cfg + PR_MD_CSRCS=nextstep.c + ;; + + +*-nto*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(NTO) + AC_DEFINE(_QNX_SOURCE) + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + MDCPUCFG_H=_nto.cfg + PR_MD_CSRCS=nto.c + MKSHLIB='$(CC) $(DSO_LDOPTS) -Wl,-soname -Wl,$(notdir $@) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS=-shared + OS_LIBS="$OS_LIBS -lsocket" + _OPTIMIZE_FLAGS="-O1" + _DEBUG_FLAGS="-gstabs" + ;; + +*-openbsd*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(OPENBSD) + AC_DEFINE(HAVE_BSD_FLOCK) + AC_DEFINE(HAVE_SOCKLEN_T) + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + DLL_SUFFIX=so.1.0 + DSO_CFLAGS=-fPIC + MDCPUCFG_H=_openbsd.cfg + PR_MD_CSRCS=openbsd.c + OS_LIBS="-lc" + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + fi + DSO_LDOPTS='-shared -fPIC' + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + ;; + +*-openvms*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(VMS) + AC_DEFINE(PR_GETIPNODE_NOT_THREADSAFE) + RESOLVE_LINK_SYMBOLS=1 + AR_FLAGS='c $@' + MDCPUCFG_H=_openvms.cfg + PR_MD_CSRCS=openvms.c + DSO_LDOPTS='-shared -auto_symvec $(LDFLAGS)' + if test -n "$MOZ_DEBUG"; then + DSO_LDOPTS="$DSO_LDOPTS $_DEBUG_FLAGS" + else + DSO_LDOPTS="$DSO_LDOPTS $_OPTIMIZE_FLAGS" + fi + ;; + +*-osf*) + SHELL_OVERRIDE="SHELL = /usr/bin/ksh" + AC_DEFINE(XP_UNIX) + AC_DEFINE(OSF1) + AC_DEFINE(_REENTRANT) + # OSF1 and HPUX report the POLLHUP event for a socket when the + # shutdown(SHUT_WR) operation is called for the remote end, even though + # the socket is still writeable. Use select(), instead of poll(), to + # workaround this problem. + AC_DEFINE(_PR_POLL_WITH_SELECT) + + if echo "$OS_RELEASE" | egrep -c '(V2.0|V3.2)' 2>/dev/null ; then + USE_NSPR_THREADS=1 + fi + + if test -z "$GNU_CC"; then + CC="$CC -std1 -ieee_with_inexact" + if test "$OS_RELEASE" != "V2.0"; then + CC="$CC -readonly_strings" + fi + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Olimit 4000" + AC_CHECK_HEADER(machine/builtins.h, AC_DEFINE(OSF1_HAVE_MACHINE_BUILTINS_H)) + else + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + fi + + if echo $OS_RELEASE | egrep -c '(V2.0|V3.2)' 2>/dev/null; then + AC_DEFINE(HAVE_INT_LOCALTIME_R) + else + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + if echo $OS_RELEASE | grep -c V4.0 >/dev/null; then + AC_DEFINE(OSF1V4_MAP_PRIVATE_BUG) + fi + DSO_LDOPTS='-shared -all -expect_unresolved "*" -soname $(notdir $@)' + MDCPUCFG_H=_osf1.cfg + PR_MD_CSRCS=osf1.c + ;; + +*-qnx*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(QNX) + AC_DEFINE(_PR_NEED_H_ERRNO) + USE_NSPR_THREADS=1 + MDCPUCFG_H=_qnx.cfg + PR_MD_CSRCS=qnx.c + ;; + +*-riscos*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(RISCOS) + AC_DEFINE(_PR_NEED_H_ERRNO) + USE_PTHREADS=1 + MDCPUCFG_H=_riscos.cfg + PR_MD_CSRCS=riscos.c + DLL_SUFFIX=a + LD="/home/riscos/env/ro-ar cr" + ;; + +*-*-sco*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SCO) + AC_DEFINE(sco) + AC_DEFINE(SYSV) + AC_DEFINE(_SVID3) + AC_DEFINE(_PR_NEED_H_ERRNO) + CC='cc -b elf -KPIC' + CXX='$(NSDEPTH)/build/hcpp CC +.cpp +w' + USE_NSPR_THREADS=1 + CPU_ARCH=x86 + DSO_LDOPTS='-b elf -G' + MDCPUCFG_H=_scoos.cfg + PR_MD_SRCS=scoos.c + ;; + +*-sinix*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SVR4) + AC_DEFINE(SNI) + AC_DEFINE(RELIANTUNIX) + AC_DEFINE(sinix) + AC_DEFINE(HAVE_SVID_GETTOD) + if echo "$OS_TEST" | grep -c 86 2>/dev/null; then + AC_DEFINE(i386) + CPU_ARCH=x86 + else + CPU_ARCH=mips + fi + + if test "$GNU_CC"; then + AS='$(CC) -x assembler-with-cpp' + if test "$CPU_ARCH" = "mips"; then + LD=gld + fi + CFLAGS="$CFLAGS -Wall -Wno-format" + else + AS='/usr/bin/cc' + _OPTIMIZE_FLAGS='-O -F Olimit,4000' + fi + + DSO_LDOPTS='-G -z defs -h $(@:$(OBJDIR)/%.so=%.so)' + + if test "$OS_RELEASE" = "5.43"; then + AC_DEFINE(IP_MULTICAST) + fi + + OS_LIBS="$OS_LIBS -lsocket -lnsl -lresolv -ldl -lc" + USE_NSPR_THREADS=1 + MDCPUCFG_H=_reliantunix.cfg + PR_MD_CSRCS=reliantunix.c + if test "${OS_ARCH}" = "mips"; then + PR_MD_ASFILES=os_ReliantUNIX.s + fi + ;; + +*-sunos*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SUNOS4) + CFLAGS="$CFLAGS -Wall -Wno-format" + if test "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + fi + CPU_ARCH=sparc + DLL_SUFFIX=so.1.0 + DSO_LDOPTS= + DSO_CFLAGS=-fPIC + USE_NSPR_THREADS=1 + if test "$OS_RELEASE" = "4.1.3_U1"; then + _OPTIMIZE_FLAGS= + OS_LIBS="$OS_LIBS -lm" + fi + MDCPUCFG_H=_sunos4.cfg + PR_MD_CSRCS=sunos4.c + ;; + +*-solaris*) + if test -z "$USE_USER_THREADS" && test -z "$USE_NATIVE_THREADS"; then + USE_PTHREADS=1 + fi + AC_DEFINE(XP_UNIX) + AC_DEFINE(SVR4) + AC_DEFINE(SYSV) + AC_DEFINE(__svr4) + AC_DEFINE(__svr4__) + AC_DEFINE(SOLARIS) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + MDCPUCFG_H=_solaris.cfg + PR_MD_CSRCS=solaris.c + LD=/usr/ccs/bin/ld + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + RESOLVE_LINK_SYMBOLS=1 + if test -n "$GNU_CC"; then + DSO_CFLAGS=-fPIC + if `$CC -print-prog-name=ld` -v 2>&1 | grep -c GNU >/dev/null; then + GCC_USE_GNU_LD=1 + fi + DSO_LDOPTS='-shared -Wl,-h,$(notdir $@),-z,combreloc,-z,defs,-z,ignore' + else + DSO_CFLAGS=-KPIC + DSO_LDOPTS='-G -h $(notdir $@) -z combreloc -z defs -z ignore' + fi + if test -n "$GNU_CC"; then + CFLAGS="$CFLAGS -Wall" + CXXFLAGS="$CXXFLAGS -Wall" + if test -n "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + CXXFLAGS="$CXXFLAGS -MDupdate \$(DEPENDENCIES)" + fi + GCC_AS=`$CC -print-prog-name=as` + if test "`echo | $GCC_AS -v 2>&1 | grep -c GNU`" != "0"; then + GNU_AS=1 + fi + else + CFLAGS="$CFLAGS -xstrconst" + CXXFLAGS="$CXXFLAGS -Qoption cg -xstrconst -features=tmplife" + if test -z "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS -xs" + CXXFLAGS="$CXXFLAGS -xs" + fi + _OPTIMIZE_FLAGS=-xO4 + fi + if test -z "$GNU_AS"; then + ASFLAGS="$ASFLAGS -Wa,-P" + fi + if test -n "$USE_64"; then + if test -n "$GNU_CC"; then + CC="$CC -m64" + CXX="$CXX -m64" + else + if test "$OS_TEST" = "i86pc"; then + CC="$CC -xarch=amd64" + CXX="$CXX -xarch=amd64" + else + CC="$CC -xarch=v9" + CXX="$CXX -xarch=v9" + fi + fi + fi + if test "$OS_TEST" = "i86pc"; then + if test -z "$USE_64"; then + AC_DEFINE(i386) + fi + CPU_ARCH_TAG=_$OS_TEST + # The default debug format, DWARF (-g), is not supported by gcc + # on i386-ANY-sysv4/solaris, but the stabs format is. It is + # assumed that the Solaris assembler /usr/ccs/bin/as is used. + # If your gcc uses GNU as, you do not need the -Wa,-s option. + if test -n "$MOZ_DEBUG" && test -n "$GNU_CC"; then + _DEBUG_FLAGS=-gstabs + if test -z "$GNU_AS"; then + _DEBUG_FLAGS="$_DEBUG_FLAGS -Wa,-s" + fi + fi + fi + case "${target_os}" in + solaris2.3*) + AC_DEFINE(_PR_NO_LARGE_FILES) + ;; + solaris2.4*) + AC_DEFINE(_PR_NO_LARGE_FILES) + ;; + solaris2.5*) + AC_DEFINE(SOLARIS2_5) + ;; + *) + AC_DEFINE(_PR_HAVE_OFF64_T) + # The lfcompile64(5) man page on Solaris 2.6 says: + # For applications that do not wish to conform to the POSIX or + # X/Open specifications, the 64-bit transitional interfaces + # are available by default. No compile-time flags need to be + # set. + # But gcc 2.7.2.x fails to define _LARGEFILE64_SOURCE by default. + # The native compiler, gcc 2.8.x, and egcs don't have this problem. + if test -n "$GNU_CC"; then + AC_DEFINE(_LARGEFILE64_SOURCE) + fi + ;; + esac + case "${target_os}" in + solaris2.3*) + ;; + solaris2.4*) + ;; + solaris2.5*) + ;; + solaris2.6*) + ;; + solaris2.7*) + ;; + *) + # Solaris 8 or higher has IPv6. + AC_DEFINE(_PR_INET6) + ;; + esac + if test "$OS_TEST" = "sun4u"; then + # 64-bit Solaris requires SPARC V9 architecture, so the following + # is not needed. + if test -z "$USE_64"; then + ULTRASPARC_LIBRARY=nspr_flt + fi + fi + # Purify requires that binaries linked against nspr also + # be linked against -lrt (or -lposix4) so add it to OS_LIBS + _rev=`uname -r` + _librt=`echo $_rev 5.6 | awk '{ if ($1 > $2) print "-lrt"; else print "-lposix4" }'` + OS_LIBS="$OS_LIBS $_librt" + ;; + +*-sco-sysv5*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(UNIXWARE) + AC_DEFINE(SVR4) + AC_DEFINE(SYSV) + USE_NSPR_THREADS=1 + if echo $OS_RELEASE | grep -c 2.1 2>/dev/null; then + AC_DEFINE(_PR_NO_LARGE_FILES) + CC='$(NSDEPTH)/build/hcc cc' + CXX='$(NSDEPTH)/build/hcpp CC' + MDCPUCFG_H=_unixware.cfg + else + AC_DEFINE(_LARGEFILE64_SOURCE) + AC_DEFINE(_PR_HAVE_OFF64_T) + AC_DEFINE(_PR_HAVE_SOCKADDR_LEN) + MDCPUCFG_H=_unixware7.cfg + fi + PR_MD_CSRCS=unixware.c + DSO_LDOPTS=-G + CPU_ARCH=x86 + ;; + +*-os2*) + AC_DEFINE(XP_OS2) + AC_DEFINE(XP_PC) + AC_DEFINE(BSD_SELECT) + AC_DEFINE(TCPV40HDRS) + LIB_SUFFIX=lib + DLL_SUFFIX=dll + RC=rc.exe + PR_MD_ARCH_DIR=os2 + PROG_SUFFIX=.exe + NSINSTALL=nsinstall + MDCPUCFG_H=_os2.cfg + RESOLVE_LINK_SYMBOLS=1 + + # EMX/GCC build + if test -n "$GNU_CC"; then + AC_DEFINE(XP_OS2_EMX) + AC_DEFINE(OS2) + AR=emxomfar + AR_FLAGS='r $@' + CFLAGS="$CFLAGS -Wall -Zomf" + CXXFLAGS="$CFLAGS -Wall -Zomf" + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS= + DSO_LDOPTS='-Zomf -Zdll -Zmap' + LDFLAGS='-Zmap' + _OPTIMIZE_FLAGS="-O2 -s" + _DEBUG_FLAGS="-g -fno-inline" + if test -n "$MOZ_OPTIMIZE"; then + DSO_LDOPTS="$DSO_LDOPTS -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA" + fi + OS_LIBS="-lsocket" + IMPLIB='emximp -o' + FILTER='emxexp -o' + if test -n "$MOZ_OS2_HIGH_MEMORY"; then + DSO_LDOPTS="$DSO_LDOPTS -Zhigh-mem" + LDFLAGS="$LDFLAGS -Zhigh-mem" + AC_DEFINE(MOZ_OS2_HIGH_MEMORY) + fi + + # GCC for OS/2 currently predefines these, but we don't want them + DEFINES="$DEFINES -Uunix -U__unix -U__unix__" + + # Visual Age C++ build + elif test "$VACPP" = "yes"; then + AC_DEFINE(XP_OS2_VACPP) + AC_DEFINE(OS2,4) + AC_DEFINE(_X86_) + OBJ_SUFFIX=obj + AS=alp + ASFLAGS='-Mb' + ASM_SUFFIX=asm + AR=-ilib + AR_FLAGS='/NOL /NOI /O:$(subst /,\\,$@)' + CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + HOST_CFLAGS="$CFLAGS" + OS_CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + OS_EXE_CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + CXXFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + OS_LIBS='so32dll.lib tcp32dll.lib' + LD='-ilink' + MKSHLIB='$(LD) $(DSO_LDOPTS)' + IMPLIB='implib -nologo -noignorecase' + FILTER='cppfilt -q -B -P' + _OPTIMIZE_FLAGS='/O+ /Gl+ /qtune=pentium /qarch=pentium' + _DEBUG_FLAGS='/Ti+ ' + LDFLAGS='/NOL /M /L' + DLLFLAGS="$DLLFLAGS /O:\$@ /DLL /INC:_dllentry /MAP:\$(@:.dll=.map) /L /NOL" + EXEFLAGS='/OUT:$@ /PMTYPE:VIO /MAP:$(@:.exe=.map) /L /NOL' + if test -n "$MOZ_DEBUG"; then + LDFLAGS="$LDFLAGS /DE" + DLLFLAGS="$DLLFLAGS /DE" + EXEFLAGS="$EXEFLAGS /DE" + fi + if test -n "$MOZ_OPTIMIZE"; then + LDFLAGS="$LDFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + DLLFLAGS="$DLLFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + EXEFLAGS="$EXEFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + fi + LIBNSPR='$(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + fi + ;; + +*) + AC_DEFINE(XP_UNIX) + ;; + +esac + +if test -z "$SKIP_LIBRARY_CHECKS"; then +dnl ======================================================== +dnl Check for system libraries +dnl ======================================================== +dnl AC_CHECK_LIB(C, main) +dnl AC_CHECK_LIB(C_r, main) +dnl AC_CHECK_LIB(c, main) +dnl AC_CHECK_LIB(c_r, main) +dnl AC_CHECK_LIB(dce, main) +dnl AC_CHECK_LIB(dl, main) +dnl AC_CHECK_LIB(dld, main) +dnl AC_CHECK_LIB(gen, main) +dnl AC_CHECK_LIB(ip6, main) +dnl AC_CHECK_LIB(l, main) +dnl AC_CHECK_LIB(m, main) +dnl AC_CHECK_LIB(nsl, main) +dnl AC_CHECK_LIB(posix4, main) +dnl AC_CHECK_LIB(prstrms, main) +dnl AC_CHECK_LIB(prstrms_shr, main) +dnl AC_CHECK_LIB(pthread, main) +dnl AC_CHECK_LIB(pthreads, main) +dnl AC_CHECK_LIB(resolv, main) +dnl AC_CHECK_LIB(rt, main) +dnl AC_CHECK_LIB(socket, main) +dnl AC_CHECK_LIB(svld, main) +dnl AC_CHECK_LIB(thread, main) +dnl AC_CHECK_LIB(vms_jackets, main) + + +dnl We don't want anything to link with libdl even if it's present on OS X, +dnl since it's not used and not part of the default installation. +dnl The same goes for BeOS. + +case $target in +*-darwin*|*-beos*) + ;; +*) + AC_CHECK_LIB(dl, dlopen, + AC_CHECK_HEADER(dlfcn.h, + OS_LIBS="-ldl $OS_LIBS")) + ;; +esac + + +dnl ======================================================== +dnl Check for system header files. +dnl ======================================================== +dnl AC_HEADER_DIRENT +dnl AC_HEADER_STDC +dnl AC_HEADER_SYS_WAIT +dnl AC_CHECK_HEADERS(fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h unistd.h) + +dnl ======================================================== +dnl Check for typedefs and structs +dnl ======================================================== +dnl AC_C_CONST +dnl AC_TYPE_UID_T +dnl AC_TYPE_MODE_T +dnl AC_TYPE_OFF_T +dnl AC_TYPE_PID_T +dnl AC_TYPE_SIZE_T +dnl AC_STRUCT_ST_BLKSIZE +dnl AC_STRUCT_ST_BLOCKS +dnl AC_STRUCT_ST_RDEV +dnl AC_HEADER_TIME +dnl AC_STRUCT_TM + +dnl ======================================================== +dnl Checks for library functions. +dnl ======================================================== +AC_PROG_GCC_TRADITIONAL +AC_CHECK_FUNCS(lchown strerror) + +dnl AC_FUNC_MEMCMP +dnl AC_FUNC_MMAP +dnl AC_FUNC_SETVBUF_REVERSED +dnl AC_FUNC_STRCOLL +dnl AC_FUNC_STRFTIME +dnl AC_FUNC_UTIME_NULL +dnl AC_FUNC_VPRINTF +dnl AC_CHECK_FUNCS(ftime getcwd gethostname gettimeofday getwd mkdir mktime putenv rmdir select socket strdup strerror strstr strtol strtoul uname) + +dnl ======================================================== +dnl Check options +dnl ======================================================== + +dnl ======================================================== +dnl = +dnl = --enable-strip +dnl = +dnl = Enable stripping of libs and executables +dnl = +dnl ======================================================== +AC_ARG_ENABLE(strip, + [ --enable-strip Enable stripping of shared libs and programs], + [ if test "$enableval" = "yes"; then + ENABLE_STRIP=1 + fi ]) + +dnl Check for hpux options +case "${target_os}" in +hpux*) +if test -z "$GNU_CC"; then + + AC_CACHE_CHECK(for +Olit support, + ac_cv_hpux_usable_olit_option, + dnl since aCC doesn't throw an error on invalid options, + dnl we have to test this the hard way + [ac_cv_hpux_usable_olit_option=no + rm -f conftest* + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} ${CFLAGS} +Olit=all -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out`"; then + ac_cv_hpux_usable_olit_option=yes + fi + fi + rm -f conftest* + ]) + + if test "$ac_cv_hpux_usable_olit_option" = "yes"; then + CFLAGS="$CFLAGS +Olit=all" + CXXFLAGS="$CXXFLAGS +Olit=all" + else + CFLAGS="$CFLAGS +ESlit" + CXXFLAGS="$CXXFLAGS +ESlit" + fi +fi +;; +esac + +dnl +dnl Apparently, some systems cannot properly check for the pthread +dnl library unless is included so we need to test +dnl using it +dnl +dnl MOZ_CHECK_PTHREADS(lib, success, failure) +AC_DEFUN(MOZ_CHECK_PTHREADS, +[ +AC_MSG_CHECKING([for pthread_create in -l$1]) +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -l[$1] $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -l[$1] $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + AC_MSG_RESULT([yes]) + [$2] + else + AC_MSG_RESULT([no]) + [$3] + fi +]) + +case "$target_os" in +darwin*) + _HAVE_PTHREADS=1 + ;; +*) + MOZ_CHECK_PTHREADS(pthreads, + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthreads", + MOZ_CHECK_PTHREADS(pthread, + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthread", + MOZ_CHECK_PTHREADS(c_r, + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lc_r", + MOZ_CHECK_PTHREADS(c, + _HAVE_PTHREADS=1 + ) + ) + ) + ) + ;; +esac + +AC_ARG_WITH(pthreads, + [ --with-pthreads Use system pthreads library as thread subsystem], + [ if test "$withval" = "yes"; then + if test -n "$_HAVE_PTHREADS"; then + USE_PTHREADS=1 + USE_USER_PTHREADS= + USE_NSPR_THREADS= + else + AC_MSG_ERROR([ --with-pthreads specified for a system without pthread support ]); + fi + else + USE_PTHREADS= + _PTHREAD_LDFLAGS= + fi], + [ if test -n "$_HAVE_PTHREADS" && test -z "$USE_USER_PTHREADS" && test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + USE_USER_PTHREADS= + USE_NSPR_THREADS= + fi]) + +AC_ARG_ENABLE(user-pthreads, + [ --enable-user-pthreads Build using userland pthreads], + [ if test "$enableval" = "yes"; then + if test -n "$_HAVE_PTHREADS"; then + USE_PTHREADS= + USE_USER_PTHREADS=1 + USE_NSPR_THREADS= + else + AC_MSG_ERROR([ --enable-user-pthreads specified for a system without pthread support ]); + fi + fi]) + +AC_ARG_ENABLE(nspr-threads, + [ --enable-nspr-threads Build using classic nspr threads], + [ if test "$enableval" = "yes"; then + USE_PTHREADS= + USE_USER_PTHREADS= + USE_NSPR_THREADS=1 + fi]) + +case "$target" in +*-beos*) + AC_ARG_WITH(bthreads, + [ --with-bthreads Use system bthreads library as thread subsystem + (BeOS only)], + [ if test "$withval" = "yes"; then + USE_BTHREADS=1 + USE_USER_PTHREADS= + USE_PTHREADS= + fi]) + ;; + +*-solaris*) + AC_ARG_WITH(native-threads, + [ --with-native-threads Use native system threads as thread subsystem + (Solaris only)], + [ if test "$withval" = "yes"; then + USE_NATIVE_THREADS=1 + USE_USER_PTHREADS= + USE_PTHREADS= + fi]) + ;; +esac + +fi # SKIP_LIBRARY_CHECKS + +AC_ARG_ENABLE(ipv6, + [ --enable-ipv6 Compile ipv6 support], + [ if test "$enableval" = "yes"; then + USE_IPV6=1 + else + USE_IPV6= + fi]) + + +AC_ARG_ENABLE(boehm, + [ --enable-boehm Enable the Boehm Garbage Collector], + [ if test "$enableval" = "yes"; then + AC_DEFINE(GC_LEAK_DETECTOR) + GC_LEAK_DETECTOR=1 + fi]) + +if test -n "$USE_PTHREADS"; then + dnl See if -pthread is supported. + rm -f conftest* + ac_cv_have_dash_pthread=no + AC_MSG_CHECKING(whether ${CC-cc} accepts -pthread) + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthread -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthread`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthread=yes + case "$target_os" in + freebsd*) +# Freebsd doesn't use -pthread for compiles, it uses them for linking + ;; + *) + CFLAGS="$CFLAGS -pthread" + CXXFLAGS="$CXXFLAGS -pthread" + ;; + esac + fi + fi + rm -f conftest* + AC_MSG_RESULT($ac_cv_have_dash_pthread) + + dnl + dnl See if -pthreads is supported. + dnl + ac_cv_have_dash_pthreads=no + if test "$ac_cv_have_dash_pthread" = "no"; then + AC_MSG_CHECKING(whether ${CC-cc} accepts -pthreads) + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthreads -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthreads`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthreads=yes + CFLAGS="$CFLAGS -pthreads" + CXXFLAGS="$CXXFLAGS -pthreads" + fi + fi + rm -f conftest* + AC_MSG_RESULT($ac_cv_have_dash_pthreads) + fi + + case "$target" in + *-solaris*) + if test "$ac_cv_have_dash_pthreads" = "yes"; then + _PTHREAD_LDFLAGS= + fi + ;; + *-freebsd*) + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + dnl -pthread links in -lc_r, so don't specify it explicitly. + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + else + _PTHREAD_LDFLAGS="-lc_r" + fi + ;; + *-netbsd*) + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + fi + ;; + *-bsdi*) + AC_DEFINE(_THREAD_SAFE) + dnl -pthread links in -lc_r, so don't specify it explicitly. + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS= + fi + ;; + *-openbsd*) + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS=-pthread + fi + ;; + *-linux*|*-gnu*|*-k*bsd*-gnu) + AC_DEFINE(_REENTRANT) + ;; + esac + +else + if test -n "$USE_USER_PTHREADS"; then + USE_PTHREADS= + USE_NSPR_THREADS= + else + _PTHREAD_LDFLAGS= + fi +fi +dnl Special thread exceptions + +case "$target" in +*-aix*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + case "$target_os" in + aix4.1*) + if test -z "$USE_PTHREADS"; then + AC_DEFINE(AIX_RENAME_SELECT) + fi + ;; + aix4.2*) + if test -z "$USE_NSPR_THREADS"; then + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + ;; + aix4.3*) + if test -z "$USE_NSPR_THREADS"; then + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST) + fi + ;; + *) + if test -z "$USE_NSPR_THREADS"; then + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST) + fi + ;; + esac + ;; +*-bsdi*) + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_NEED_PTHREAD_INIT) + fi + ;; +*-freebsd*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + ;; +*-hpux*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + if test "$USE_PTHREADS"; then + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + AC_DEFINE(_REENTRANT) + AC_DEFINE(_PR_DCETHREADS) + else + AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE,199506L) + AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST) + fi + fi + if test "$USE_USER_PTHREADS"; then + AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE,199506L) + fi + ;; +*-irix*) + if test "${target_os}" = "irix6.5"; then + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_HAVE_GETHOST_R) + AC_DEFINE(_PR_HAVE_GETHOST_R_POINTER) + fi + fi + ;; +*-linux*|*-gnu*|*-k*bsd*-gnu) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + ;; +*-mingw*|*-cygwin*|*-msvc*|*-mks*|*-os2*|*-beos*) + dnl win32, os2 & beos cannot use pthreads + USE_PTHREADS= + _PTHREAD_LDFLAGS= + USE_USER_PTHREADS= + ;; +*-netbsd*|*-openbsd*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + ;; +*-osf*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + if test -n "$USE_PTHREADS"; then + if echo $OS_RELEASE | egrep -c '(V2.0|V3.2)' 2>/dev/null; then + : + else + AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST) + fi + fi + ;; +*-solaris*) + if test -n "$USE_NATIVE_THREADS"; then + AC_DEFINE(_PR_GLOBAL_THREADS_ONLY) + else + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + fi + if test -z "$USE_NSPR_THREADS"; then + AC_DEFINE(_REENTRANT) + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + if test "$OS_TEST" = "i86pc"; then + if test -n "$USE_64"; then + PR_MD_ASFILES=os_SunOS_x86_64.s + else + PR_MD_ASFILES=os_SunOS_x86.s + fi + else + if test -n "$USE_64"; then + PR_MD_ASFILES=os_SunOS_sparcv9.s + fi + if test -n "$USE_NATIVE_THREADS"; then + PR_MD_ASFILES="$PR_MD_ASFILES os_SunOS.s" + fi + fi + fi + ;; +*-nto*) + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_HAVE_GETHOST_R) + AC_DEFINE(_PR_HAVE_GETHOST_R_POINTER) + fi + ;; +esac + +OS_LIBS="$_PTHREAD_LDFLAGS $OS_LIBS" + +dnl If the user passed in arg to --enable-optimize or --enable-debug, +dnl make sure that we use it. +if test -n "$_SAVE_OPTIMIZE_FLAGS"; then + _OPTIMIZE_FLAGS="$_SAVE_OPTIMIZE_FLAGS" +fi + +if test -n "$_SAVE_DEBUG_FLAGS"; then + _DEBUG_FLAGS="$_SAVE_DEBUG_FLAGS" +fi + +if test -n "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS $_OPTIMIZE_FLAGS" + CXXFLAGS="$CXXFLAGS $_OPTIMIZE_FLAGS" +fi + +if test -n "$MOZ_DEBUG"; then + CFLAGS="$CFLAGS $_DEBUG_FLAGS" + CXXFLAGS="$CXXFLAGS $_DEBUG_FLAGS" +fi + +if test -n "$MOZ_OPTIMIZE"; then + OBJDIR_TAG=_OPT +else + OBJDIR_TAG=_DBG +fi + +if test -n "$USE_64"; then + COMPILER_TAG=_64 +fi + +RELEASE_OBJDIR_NAME="${OS_CONFIG}${CPU_ARCH_TAG}${COMPILER_TAG}${IMPL_STRATEGY}${OBJDIR_TAG}.${OBJDIR_SUFFIX}" + +dnl ======================================================== +dnl Use cygwin wrapper for win32 builds, except MSYS/MinGW +dnl ======================================================== +case "$target_os" in +cygwin*|msvc*|mks*) + CC="\$(CYGWIN_WRAPPER) $CC" + CXX="\$(CYGWIN_WRAPPER) $CXX" + RC="\$(CYGWIN_WRAPPER) $RC" + ;; +esac + +dnl ======================================================== +dnl Substitution of found variables. +dnl ======================================================== +AC_SUBST(SHELL_OVERRIDE) + +AC_SUBST(MOZILLA_CLIENT) +AC_SUBST(CC) +AC_SUBST(CXX) +AC_SUBST(CFLAGS) +AC_SUBST(CXXFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(HOST_CC) +AC_SUBST(HOST_CFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(HOST_LDFLAGS) +AC_SUBST(GNU_CC) +AC_SUBST(GCC_USE_GNU_LD) +AC_SUBST(MSC_VER) +AC_SUBST(CROSS_COMPILE) + +AC_SUBST(MOZ_OPTIMIZE) + +AC_SUBST(USE_CPLUS) +AC_SUBST(USE_IPV6) +AC_SUBST(USE_N32) +AC_SUBST(USE_64) +AC_SUBST(OBJECT_MODE) +AC_SUBST(GC_LEAK_DETECTOR) +AC_SUBST(ENABLE_STRIP) + +AC_SUBST(USE_PTHREADS) +AC_SUBST(USE_BTHREADS) +AC_SUBST(USE_USER_PTHREADS) +AC_SUBST(USE_NATIVE_THREADS) +AC_SUBST(USE_NSPR_THREADS) + +AC_SUBST(LIBNSPR) +AC_SUBST(LIBPLC) + +AC_SUBST(MOD_MAJOR_VERSION) +AC_SUBST(MOD_MINOR_VERSION) +AC_SUBST(MOD_PATCH_VERSION) +AC_SUBST(NSPR_MODNAME) +AC_SUBST(MDCPUCFG_H) +AC_SUBST(PR_MD_CSRCS) +AC_SUBST(PR_MD_ASFILES) +AC_SUBST(PR_MD_ARCH_DIR) +AC_SUBST(CPU_ARCH) + +AC_SUBST(OBJ_SUFFIX) +AC_SUBST(LIB_SUFFIX) +AC_SUBST(DLL_SUFFIX) +AC_SUBST(ASM_SUFFIX) +AC_SUBST(MKSHLIB) +AC_SUBST(DSO_CFLAGS) +AC_SUBST(DSO_LDOPTS) + +AC_SUBST(OS_TARGET) +AC_SUBST(OS_ARCH) +AC_SUBST(OS_RELEASE) +AC_SUBST(OS_TEST) +AC_SUBST(MACOSX_DEPLOYMENT_TARGET) + +AC_SUBST(DEFINES) +AC_SUBST(DEFS) +AC_SUBST(AR) +AC_SUBST(AR_FLAGS) +AC_SUBST(AS) +AC_SUBST(ASFLAGS) +AC_SUBST(LD) +AC_SUBST(RANLIB) +AC_SUBST(PERL) +AC_SUBST(STRIP) +AC_SUBST(FILTER) +AC_SUBST(IMPLIB) + +AC_SUBST(OS_LIBS) +AC_SUBST(RESOLVE_LINK_SYMBOLS) +AC_SUBST(AIX_LINK_OPTS) +AC_SUBST(NOSUCHFILE) +AC_SUBST(MOZ_OBJFORMAT) +AC_SUBST(ULTRASPARC_LIBRARY) + +AC_SUBST(OBJDIR) +AC_SUBST(OBJDIR_NAME) +AC_SUBST(RELEASE_OBJDIR_NAME) +AC_SUBST(NSINSTALL) +AC_SUBST(OPTIMIZER) +AC_SUBST(RC) +AC_SUBST(RCFLAGS) +AC_SUBST(DLLFLAGS) +AC_SUBST(EXEFLAGS) +AC_SUBST(OS_DLLFLAGS) +AC_SUBST(CYGWIN_WRAPPER) +AC_SUBST(VISIBILITY_FLAGS) +AC_SUBST(WRAP_SYSTEM_INCLUDES) +AC_SUBST(MACOS_SDK_DIR) +AC_SUBST(NEXT_ROOT) +AC_SUBST(MT) + +dnl ======================================================== +dnl Generate output files. +dnl ======================================================== +MAKEFILES=" +Makefile +config/Makefile +config/autoconf.mk +config/nsprincl.mk +config/nsprincl.sh +config/nspr-config +lib/Makefile +lib/ds/Makefile +lib/libc/Makefile +lib/libc/include/Makefile +lib/libc/src/Makefile +lib/tests/Makefile +pkg/Makefile +pkg/linux/Makefile +pkg/solaris/Makefile +pkg/solaris/SUNWpr/Makefile +pkg/solaris/SUNWprd/Makefile +pr/Makefile +pr/include/Makefile +pr/include/md/Makefile +pr/include/obsolete/Makefile +pr/include/private/Makefile +pr/src/Makefile +pr/src/io/Makefile +pr/src/linking/Makefile +pr/src/malloc/Makefile +pr/src/md/Makefile +pr/src/md/${PR_MD_ARCH_DIR}/Makefile +pr/src/memory/Makefile +pr/src/misc/Makefile +pr/src/threads/Makefile +pr/tests/Makefile +pr/tests/dll/Makefile +" + +dnl lib/tests/Makefile +dnl pr/tests/w16gui/Makefile +dnl tools/Makefile + +if test -z "$USE_PTHREADS" && test -z "$USE_BTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/threads/combined/Makefile" +elif test -n "$USE_PTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/pthreads/Makefile" +elif test -n "$USE_BTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/bthreads/Makefile" +fi + +if test -n "$USE_CPLUS"; then + MAKEFILES="$MAKEFILES pr/src/cplus/Makefile pr/src/cplus/tests/Makefile" +fi + +echo $MAKEFILES > unallmakefiles + +AC_OUTPUT([$MAKEFILES], [chmod +x config/nspr-config]) diff --git a/nsprpub/lib/.cvsignore b/nsprpub/lib/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/Makefile.in b/nsprpub/lib/Makefile.in new file mode 100644 index 00000000000..9bdc078e9cb --- /dev/null +++ b/nsprpub/lib/Makefile.in @@ -0,0 +1,56 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +export NSPR20=1 + +include $(topsrcdir)/config/config.mk + +DIRS = ds libc + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/lib/ds/.cvsignore b/nsprpub/lib/ds/.cvsignore new file mode 100644 index 00000000000..bcab60f5aad --- /dev/null +++ b/nsprpub/lib/ds/.cvsignore @@ -0,0 +1,2 @@ +Makefile +_pl_bld.h diff --git a/nsprpub/lib/ds/MANIFEST b/nsprpub/lib/ds/MANIFEST new file mode 100644 index 00000000000..ceda33b7bf8 --- /dev/null +++ b/nsprpub/lib/ds/MANIFEST @@ -0,0 +1,7 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +plarenas.h +plarena.h +plhash.h diff --git a/nsprpub/lib/ds/Makefile.in b/nsprpub/lib/ds/Makefile.in new file mode 100644 index 00000000000..5a2e0722875 --- /dev/null +++ b/nsprpub/lib/ds/Makefile.in @@ -0,0 +1,197 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include + +CSRCS = \ + plarena.c \ + plhash.c \ + plvrsion.c \ + $(NULL) + +HEADERS = \ + plarenas.h \ + plarena.h \ + plhash.h \ + $(NULL) + +HEADERS := $(addprefix $(srcdir)/, $(HEADERS)) + +ifeq ($(OS_ARCH), WINNT) +RES=$(OBJDIR)/plds.res +RESNAME=plds.rc +endif # WINNT + +ifeq ($(OS_ARCH), AIX) +ifeq ($(CLASSIC_NSPR),1) +OS_LIBS = -lc +else +OS_LIBS = -lc_r +endif +endif + +ifeq ($(OS_ARCH),IRIX) +OS_LIBS = -lc +endif + +ifeq ($(OS_ARCH),SunOS) +OS_LIBS = -lc +MAPFILE = $(OBJDIR)/pldsmap.sun +GARBAGE += $(MAPFILE) +ifdef NS_USE_GCC +ifdef GCC_USE_GNU_LD +MKSHLIB += -Wl,--version-script,$(MAPFILE) +else +MKSHLIB += -Wl,-M,$(MAPFILE) +endif +else +MKSHLIB += -M $(MAPFILE) +endif +# The -R '$ORIGIN' linker option instructs this library to search for its +# dependencies in the same directory where it resides. +MKSHLIB += -R '$$ORIGIN' +endif + +ifeq ($(OS_ARCH),OS2) +MAPFILE = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).def +GARBAGE += $(MAPFILE) +MKSHLIB += $(MAPFILE) +endif + +EXTRA_LIBS = $(LIBNSPR) + +# On NCR and SCOOS, we can't link with extra libraries when +# we build a shared library. If we do so, the linker doesn't +# complain, but we would run into weird problems at run-time. +# Therefore on these platforms, we link just the .o files. +ifeq ($(OS_ARCH),NCR) +EXTRA_LIBS = +endif +ifeq ($(OS_ARCH),SCOOS) +EXTRA_LIBS = +endif + +ifdef RESOLVE_LINK_SYMBOLS +EXTRA_LIBS += $(OS_LIBS) +endif + +LIBRARY_NAME = plds +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) +RELEASE_LIBS = $(TARGETS) + +include $(topsrcdir)/config/rules.mk + +# +# Version information generation (begin) +# +ECHO = echo +TINC = $(OBJDIR)/_pl_bld.h +PROD = $(notdir $(SHARED_LIBRARY)) +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date "+%Y-%m-%d %T") +SH_NOW = $(shell $(NOW)) + +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + SUF = i64 +else + SUF = LL +endif + +GARBAGE += $(TINC) + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) '#define _BUILD_STRING "$(SH_DATE)"' > $(TINC) + @if test ! -z "$(SH_NOW)"; then \ + $(ECHO) '#define _BUILD_TIME $(SH_NOW)$(SUF)' >> $(TINC); \ + else \ + true; \ + fi + @$(ECHO) '#define _PRODUCTION "$(PROD)"' >> $(TINC) + + +$(OBJDIR)/plvrsion.$(OBJ_SUFFIX): plvrsion.c $(TINC) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else +ifeq ($(MOZ_OS2_TOOLS), VACPP) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +endif +endif +# +# Version information generation (end) +# + +# +# The Client build wants the shared libraries in $(dist_bindir), +# so we also install them there. +# + +export:: $(TARGETS) + $(INSTALL) -m 444 $(HEADERS) $(dist_includedir) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifdef SHARED_LIBRARY +ifeq ($(OS_ARCH),HP-UX) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_libdir) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_bindir) +else + $(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_bindir) +endif +endif +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(HEADERS) $(MOZ_INCL) + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin +endif + + diff --git a/nsprpub/lib/ds/plarena.c b/nsprpub/lib/ds/plarena.c new file mode 100644 index 00000000000..dc3af0b4ae4 --- /dev/null +++ b/nsprpub/lib/ds/plarena.c @@ -0,0 +1,446 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + */ +#include +#include +#include "plarena.h" +#include "prmem.h" +#include "prbit.h" +#include "prlog.h" +#include "prlock.h" +#include "prinit.h" + +static PLArena *arena_freelist; + +#ifdef PL_ARENAMETER +static PLArenaStats *arena_stats_list; + +#define COUNT(pool,what) (pool)->stats.what++ +#else +#define COUNT(pool,what) /* nothing */ +#endif + +#define PL_ARENA_DEFAULT_ALIGN sizeof(double) + +static PRLock *arenaLock; +static PRCallOnceType once; + +/* +** InitializeArenas() -- Initialize arena operations. +** +** InitializeArenas() is called exactly once and only once from +** LockArena(). This function creates the arena protection +** lock: arenaLock. +** +** Note: If the arenaLock cannot be created, InitializeArenas() +** fails quietly, returning only PR_FAILURE. This percolates up +** to the application using the Arena API. He gets no arena +** from PL_ArenaAllocate(). It's up to him to fail gracefully +** or recover. +** +*/ +static PRStatus InitializeArenas( void ) +{ + PR_ASSERT( arenaLock == NULL ); + arenaLock = PR_NewLock(); + if ( arenaLock == NULL ) + return PR_FAILURE; + else + return PR_SUCCESS; +} /* end ArenaInitialize() */ + +static PRStatus LockArena( void ) +{ + PRStatus rc = PR_CallOnce( &once, InitializeArenas ); + + if ( PR_FAILURE != rc ) + PR_Lock( arenaLock ); + return(rc); +} /* end LockArena() */ + +static void UnlockArena( void ) +{ + PR_Unlock( arenaLock ); + return; +} /* end UnlockArena() */ + +PR_IMPLEMENT(void) PL_InitArenaPool( + PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align) +{ +#if defined(XP_MAC) +#pragma unused (name) +#endif + + /* + * Look-up table of PR_BITMASK(PR_CeilingLog2(align)) values for + * align = 1 to 32. + */ + static const PRUint8 pmasks[33] = { + 0, /* not used */ + 0, 1, 3, 3, 7, 7, 7, 7,15,15,15,15,15,15,15,15, /* 1 ... 16 */ + 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31}; /* 17 ... 32 */ + + if (align == 0) + align = PL_ARENA_DEFAULT_ALIGN; + + if (align < sizeof(pmasks)/sizeof(pmasks[0])) + pool->mask = pmasks[align]; + else + pool->mask = PR_BITMASK(PR_CeilingLog2(align)); + + pool->first.next = NULL; + pool->first.base = pool->first.avail = pool->first.limit = + (PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1); + pool->current = &pool->first; + pool->arenasize = size; +#ifdef PL_ARENAMETER + memset(&pool->stats, 0, sizeof pool->stats); + pool->stats.name = strdup(name); + pool->stats.next = arena_stats_list; + arena_stats_list = &pool->stats; +#endif +} + + +/* +** PL_ArenaAllocate() -- allocate space from an arena pool +** +** Description: PL_ArenaAllocate() allocates space from an arena +** pool. +** +** First, try to satisfy the request from arenas starting at +** pool->current. +** +** If there is not enough space in the arena pool->current, try +** to claim an arena, on a first fit basis, from the global +** freelist (arena_freelist). +** +** If no arena in arena_freelist is suitable, then try to +** allocate a new arena from the heap. +** +** Returns: pointer to allocated space or NULL +** +** Notes: The original implementation had some difficult to +** solve bugs; the code was difficult to read. Sometimes it's +** just easier to rewrite it. I did that. larryh. +** +** See also: bugzilla: 45343. +** +*/ + +PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb) +{ + PLArena *a; + char *rp; /* returned pointer */ + + PR_ASSERT((nb & pool->mask) == 0); + + nb = (PRUword)PL_ARENA_ALIGN(pool, nb); /* force alignment */ + + /* attempt to allocate from arenas at pool->current */ + { + a = pool->current; + do { + if ( a->avail +nb <= a->limit ) { + pool->current = a; + rp = (char *)a->avail; + a->avail += nb; + return rp; + } + } while( NULL != (a = a->next) ); + } + + /* attempt to allocate from arena_freelist */ + { + PLArena *p; /* previous pointer, for unlinking from freelist */ + + /* lock the arena_freelist. Make access to the freelist MT-Safe */ + if ( PR_FAILURE == LockArena()) + return(0); + + for ( a = arena_freelist, p = NULL; a != NULL ; p = a, a = a->next ) { + if ( a->base +nb <= a->limit ) { + if ( p == NULL ) + arena_freelist = a->next; + else + p->next = a->next; + UnlockArena(); + a->avail = a->base; + rp = (char *)a->avail; + a->avail += nb; + /* the newly allocated arena is linked after pool->current + * and becomes pool->current */ + a->next = pool->current->next; + pool->current->next = a; + pool->current = a; + if ( NULL == pool->first.next ) + pool->first.next = a; + return(rp); + } + } + UnlockArena(); + } + + /* attempt to allocate from the heap */ + { + PRUint32 sz = PR_MAX(pool->arenasize, nb); + sz += sizeof *a + pool->mask; /* header and alignment slop */ + a = (PLArena*)PR_MALLOC(sz); + if ( NULL != a ) { + a->limit = (PRUword)a + sz; + a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1); + rp = (char *)a->avail; + a->avail += nb; + /* the newly allocated arena is linked after pool->current + * and becomes pool->current */ + a->next = pool->current->next; + pool->current->next = a; + pool->current = a; + if ( NULL == pool->first.next ) + pool->first.next = a; + PL_COUNT_ARENA(pool,++); + COUNT(pool, nmallocs); + return(rp); + } + } + + /* we got to here, and there's no memory to allocate */ + return(NULL); +} /* --- end PL_ArenaAllocate() --- */ + +PR_IMPLEMENT(void *) PL_ArenaGrow( + PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr) +{ + void *newp; + + PL_ARENA_ALLOCATE(newp, pool, size + incr); + if (newp) + memcpy(newp, p, size); + return newp; +} + +/* + * Free tail arenas linked after head, which may not be the true list head. + * Reset pool->current to point to head in case it pointed at a tail arena. + */ +static void FreeArenaList(PLArenaPool *pool, PLArena *head, PRBool reallyFree) +{ + PLArena **ap, *a; + + ap = &head->next; + a = *ap; + if (!a) + return; + +#ifdef DEBUG + do { + PR_ASSERT(a->base <= a->avail && a->avail <= a->limit); + a->avail = a->base; + PL_CLEAR_UNUSED(a); + } while ((a = a->next) != 0); + a = *ap; +#endif + + if (reallyFree) { + do { + *ap = a->next; + PL_CLEAR_ARENA(a); + PL_COUNT_ARENA(pool,--); + PR_DELETE(a); + } while ((a = *ap) != 0); + } else { + /* Insert the whole arena chain at the front of the freelist. */ + do { + ap = &(*ap)->next; + } while (*ap); + LockArena(); + *ap = arena_freelist; + arena_freelist = a; + head->next = 0; + UnlockArena(); + } + + pool->current = head; +} + +PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark) +{ + PLArena *a; + + for (a = pool->first.next; a; a = a->next) { + if (PR_UPTRDIFF(mark, a->base) < PR_UPTRDIFF(a->avail, a->base)) { + a->avail = (PRUword)PL_ARENA_ALIGN(pool, mark); + FreeArenaList(pool, a, PR_FALSE); + return; + } + } +} + +PR_IMPLEMENT(void) PL_FreeArenaPool(PLArenaPool *pool) +{ + FreeArenaList(pool, &pool->first, PR_FALSE); + COUNT(pool, ndeallocs); +} + +PR_IMPLEMENT(void) PL_FinishArenaPool(PLArenaPool *pool) +{ + FreeArenaList(pool, &pool->first, PR_TRUE); +#ifdef PL_ARENAMETER + { + PLArenaStats *stats, **statsp; + + if (pool->stats.name) + PR_DELETE(pool->stats.name); + for (statsp = &arena_stats_list; (stats = *statsp) != 0; + statsp = &stats->next) { + if (stats == &pool->stats) { + *statsp = stats->next; + return; + } + } + } +#endif +} + +PR_IMPLEMENT(void) PL_CompactArenaPool(PLArenaPool *ap) +{ +#if XP_MAC +#pragma unused (ap) +#if 0 + PRArena *curr = &(ap->first); + while (curr) { + reallocSmaller(curr, curr->avail - (uprword_t)curr); + curr->limit = curr->avail; + curr = curr->next; + } +#endif +#endif +} + +PR_IMPLEMENT(void) PL_ArenaFinish(void) +{ + PLArena *a, *next; + + for (a = arena_freelist; a; a = next) { + next = a->next; + PR_DELETE(a); + } + arena_freelist = NULL; + + if (arenaLock) { + PR_DestroyLock(arenaLock); + arenaLock = NULL; + } +} + +#ifdef PL_ARENAMETER +PR_IMPLEMENT(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb) +{ + pool->stats.nallocs++; + pool->stats.nbytes += nb; + if (nb > pool->stats.maxalloc) + pool->stats.maxalloc = nb; + pool->stats.variance += nb * nb; +} + +PR_IMPLEMENT(void) PL_ArenaCountInplaceGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr) +{ + pool->stats.ninplace++; +} + +PR_IMPLEMENT(void) PL_ArenaCountGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr) +{ + pool->stats.ngrows++; + pool->stats.nbytes += incr; + pool->stats.variance -= size * size; + size += incr; + if (size > pool->stats.maxalloc) + pool->stats.maxalloc = size; + pool->stats.variance += size * size; +} + +PR_IMPLEMENT(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark) +{ + pool->stats.nreleases++; +} + +PR_IMPLEMENT(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark) +{ + pool->stats.nfastrels++; +} + +#include +#include + +PR_IMPLEMENT(void) PL_DumpArenaStats(FILE *fp) +{ + PLArenaStats *stats; + double mean, variance; + + for (stats = arena_stats_list; stats; stats = stats->next) { + if (stats->nallocs != 0) { + mean = (double)stats->nbytes / stats->nallocs; + variance = fabs(stats->variance / stats->nallocs - mean * mean); + } else { + mean = variance = 0; + } + + fprintf(fp, "\n%s allocation statistics:\n", stats->name); + fprintf(fp, " number of arenas: %u\n", stats->narenas); + fprintf(fp, " number of allocations: %u\n", stats->nallocs); + fprintf(fp, " number of free arena reclaims: %u\n", stats->nreclaims); + fprintf(fp, " number of malloc calls: %u\n", stats->nmallocs); + fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs); + fprintf(fp, " number of allocation growths: %u\n", stats->ngrows); + fprintf(fp, " number of in-place growths: %u\n", stats->ninplace); + fprintf(fp, "number of released allocations: %u\n", stats->nreleases); + fprintf(fp, " number of fast releases: %u\n", stats->nfastrels); + fprintf(fp, " total bytes allocated: %u\n", stats->nbytes); + fprintf(fp, " mean allocation size: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sqrt(variance)); + fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc); + } +} +#endif /* PL_ARENAMETER */ diff --git a/nsprpub/lib/ds/plarena.h b/nsprpub/lib/ds/plarena.h new file mode 100644 index 00000000000..38f3e3990a5 --- /dev/null +++ b/nsprpub/lib/ds/plarena.h @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#ifndef plarena_h___ +#define plarena_h___ +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + * + * Also supports LIFO allocation (PL_ARENA_MARK/PL_ARENA_RELEASE). + */ +#include "prtypes.h" +#include "plarenas.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLArena PLArena; + +struct PLArena { + PLArena *next; /* next arena for this lifetime */ + PRUword base; /* aligned base address, follows this header */ + PRUword limit; /* one beyond last byte in arena */ + PRUword avail; /* points to next available byte */ +}; + +#ifdef PL_ARENAMETER +typedef struct PLArenaStats PLArenaStats; + +struct PLArenaStats { + PLArenaStats *next; /* next in arenaStats list */ + char *name; /* name for debugging */ + PRUint32 narenas; /* number of arenas in pool */ + PRUint32 nallocs; /* number of PL_ARENA_ALLOCATE() calls */ + PRUint32 nreclaims; /* number of reclaims from freeArenas */ + PRUint32 nmallocs; /* number of malloc() calls */ + PRUint32 ndeallocs; /* number of lifetime deallocations */ + PRUint32 ngrows; /* number of PL_ARENA_GROW() calls */ + PRUint32 ninplace; /* number of in-place growths */ + PRUint32 nreleases; /* number of PL_ARENA_RELEASE() calls */ + PRUint32 nfastrels; /* number of "fast path" releases */ + PRUint32 nbytes; /* total bytes allocated */ + PRUint32 maxalloc; /* maximum allocation size in bytes */ + PRFloat64 variance; /* size variance accumulator */ +}; +#endif + +struct PLArenaPool { + PLArena first; /* first arena in pool list */ + PLArena *current; /* arena from which to allocate space */ + PRUint32 arenasize; /* net exact size of a new arena */ + PRUword mask; /* alignment mask (power-of-2 - 1) */ +#ifdef PL_ARENAMETER + PLArenaStats stats; +#endif +}; + +/* + * If the including .c file uses only one power-of-2 alignment, it may define + * PL_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions + * per ALLOCATE and GROW. + */ +#ifdef PL_ARENA_CONST_ALIGN_MASK +#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + PL_ARENA_CONST_ALIGN_MASK) \ + & ~PL_ARENA_CONST_ALIGN_MASK) + +#define PL_INIT_ARENA_POOL(pool, name, size) \ + PL_InitArenaPool(pool, name, size, PL_ARENA_CONST_ALIGN_MASK + 1) +#else +#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + (pool)->mask) & ~(pool)->mask) +#endif + +#define PL_ARENA_ALLOCATE(p, pool, nb) \ + PR_BEGIN_MACRO \ + PLArena *_a = (pool)->current; \ + PRUint32 _nb = PL_ARENA_ALIGN(pool, nb); \ + PRUword _p = _a->avail; \ + PRUword _q = _p + _nb; \ + if (_q > _a->limit) \ + _p = (PRUword)PL_ArenaAllocate(pool, _nb); \ + else \ + _a->avail = _q; \ + p = (void *)_p; \ + PL_ArenaCountAllocation(pool, nb); \ + PR_END_MACRO + +#define PL_ARENA_GROW(p, pool, size, incr) \ + PR_BEGIN_MACRO \ + PLArena *_a = (pool)->current; \ + PRUint32 _incr = PL_ARENA_ALIGN(pool, incr); \ + PRUword _p = _a->avail; \ + PRUword _q = _p + _incr; \ + if (_p == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \ + _q <= _a->limit) { \ + _a->avail = _q; \ + PL_ArenaCountInplaceGrowth(pool, size, incr); \ + } else { \ + p = PL_ArenaGrow(pool, p, size, incr); \ + } \ + PL_ArenaCountGrowth(pool, size, incr); \ + PR_END_MACRO + +#define PL_ARENA_MARK(pool) ((void *) (pool)->current->avail) +#define PR_UPTRDIFF(p,q) ((PRUword)(p) - (PRUword)(q)) + +#ifdef DEBUG +#define PL_FREE_PATTERN 0xDA +#define PL_CLEAR_UNUSED(a) (PR_ASSERT((a)->avail <= (a)->limit), \ + memset((void*)(a)->avail, PL_FREE_PATTERN, \ + (a)->limit - (a)->avail)) +#define PL_CLEAR_ARENA(a) memset((void*)(a), PL_FREE_PATTERN, \ + (a)->limit - (PRUword)(a)) +#else +#define PL_CLEAR_UNUSED(a) +#define PL_CLEAR_ARENA(a) +#endif + +#define PL_ARENA_RELEASE(pool, mark) \ + PR_BEGIN_MACRO \ + char *_m = (char *)(mark); \ + PLArena *_a = (pool)->current; \ + if (PR_UPTRDIFF(_m, _a->base) <= PR_UPTRDIFF(_a->avail, _a->base)) { \ + _a->avail = (PRUword)PL_ARENA_ALIGN(pool, _m); \ + PL_CLEAR_UNUSED(_a); \ + PL_ArenaCountRetract(pool, _m); \ + } else { \ + PL_ArenaRelease(pool, _m); \ + } \ + PL_ArenaCountRelease(pool, _m); \ + PR_END_MACRO + +#ifdef PL_ARENAMETER +#define PL_COUNT_ARENA(pool,op) ((pool)->stats.narenas op) +#else +#define PL_COUNT_ARENA(pool,op) +#endif + +#define PL_ARENA_DESTROY(pool, a, pnext) \ + PR_BEGIN_MACRO \ + PL_COUNT_ARENA(pool,--); \ + if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ + *(pnext) = (a)->next; \ + PL_CLEAR_ARENA(a); \ + free(a); \ + (a) = 0; \ + PR_END_MACRO + +#ifdef PL_ARENAMETER + +#include + +PR_EXTERN(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb); + +PR_EXTERN(void) PL_ArenaCountInplaceGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaCountGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark); + +PR_EXTERN(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark); + +PR_EXTERN(void) PL_DumpArenaStats(FILE *fp); + +#else /* !PL_ARENAMETER */ + +#define PL_ArenaCountAllocation(ap, nb) /* nothing */ +#define PL_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */ +#define PL_ArenaCountGrowth(ap, size, incr) /* nothing */ +#define PL_ArenaCountRelease(ap, mark) /* nothing */ +#define PL_ArenaCountRetract(ap, mark) /* nothing */ + +#endif /* !PL_ARENAMETER */ + +PR_END_EXTERN_C + +#endif /* plarena_h___ */ diff --git a/nsprpub/lib/ds/plarenas.h b/nsprpub/lib/ds/plarenas.h new file mode 100644 index 00000000000..e3eca358b48 --- /dev/null +++ b/nsprpub/lib/ds/plarenas.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if defined(PLARENAS_H) +#else /* defined(PLARENAS_H) */ +#define PLARENAS_H + +PR_BEGIN_EXTERN_C + +typedef struct PLArenaPool PLArenaPool; + +/* +** Allocate an arena pool as specified by the parameters. +** +** This is equivelant to allocating the space yourself and then +** calling PL_InitArenaPool(). +** +** This function may fail (and return a NULL) for a variety of +** reasons. The reason for a particular failure can be discovered +** by calling PR_GetError(). +*/ +#if 0 /* Not implemented */ +PR_EXTERN(PLArenaPool*) PL_AllocArenaPool( + const char *name, PRUint32 size, PRUint32 align); +#endif + +/* +** Destroy an arena pool previously allocated by PL_AllocArenaPool(). +** +** This function may fail if the arena is not empty and the caller +** wishes to check for empty upon descruction. +*/ +#if 0 /* Not implemented */ +PR_EXTERN(PRStatus) PL_DestroyArenaPool(PLArenaPool *pool, PRBool checkEmpty); +#endif + + +/* +** Initialize an arena pool with the given name for debugging and metering, +** with a minimum size per arena of size bytes. +**/ +PR_EXTERN(void) PL_InitArenaPool( + PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align); + +/* +** Finish using arenas, freeing all memory associated with them. +**/ +PR_EXTERN(void) PL_ArenaFinish(void); + +/* +** Free the arenas in pool. The user may continue to allocate from pool +** after calling this function. There is no need to call PL_InitArenaPool() +** again unless PL_FinishArenaPool(pool) has been called. +**/ +PR_EXTERN(void) PL_FreeArenaPool(PLArenaPool *pool); + +/* +** Free the arenas in pool and finish using it altogether. +**/ +PR_EXTERN(void) PL_FinishArenaPool(PLArenaPool *pool); + +/* +** Compact all of the arenas in a pool so that no space is wasted. +**/ +PR_EXTERN(void) PL_CompactArenaPool(PLArenaPool *pool); + +/* +** Friend functions used by the PL_ARENA_*() macros. +**/ +PR_EXTERN(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb); + +PR_EXTERN(void *) PL_ArenaGrow( + PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaRelease(PLArenaPool *pool, char *mark); + +PR_END_EXTERN_C + +#endif /* defined(PLARENAS_H) */ + +/* plarenas */ diff --git a/nsprpub/lib/ds/plds.def b/nsprpub/lib/ds/plds.def new file mode 100644 index 00000000000..d72796a4c21 --- /dev/null +++ b/nsprpub/lib/ds/plds.def @@ -0,0 +1,83 @@ +;+# +;+# ***** BEGIN LICENSE BLOCK ***** +;+# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +;+# +;+# The contents of this file are subject to the Mozilla Public License Version +;+# 1.1 (the "License"); you may not use this file except in compliance with +;+# the License. You may obtain a copy of the License at +;+# http://www.mozilla.org/MPL/ +;+# +;+# Software distributed under the License is distributed on an "AS IS" basis, +;+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +;+# for the specific language governing rights and limitations under the +;+# License. +;+# +;+# The Original Code is the Netscape Portable Runtime (NSPR). +;+# +;+# The Initial Developer of the Original Code is +;+# Netscape Communications Corporation. +;+# Portions created by the Initial Developer are Copyright (C) 2002-2003 +;+# the Initial Developer. All Rights Reserved. +;+# +;+# Contributor(s): +;+# +;+# Alternatively, the contents of this file may be used under the terms of +;+# either the GNU General Public License Version 2 or later (the "GPL"), or +;+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +;+# in which case the provisions of the GPL or the LGPL are applicable instead +;+# of those above. If you wish to allow use of your version of this file only +;+# under the terms of either the GPL or the LGPL, and not to allow others to +;+# use your version of this file under the terms of the MPL, indicate your +;+# decision by deleting the provisions above and replace them with the notice +;+# and other provisions required by the GPL or the LGPL. If you do not delete +;+# the provisions above, a recipient may use your version of this file under +;+# the terms of any one of the MPL, the GPL or the LGPL. +;+# +;+# ***** END LICENSE BLOCK ***** +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+NSPR_4.0 { +;+ global: +LIBRARY plds4 ;- +EXPORTS ;- +PL_ArenaAllocate; +PL_ArenaFinish; +PL_ArenaGrow; +PL_ArenaRelease; +PL_CompactArenaPool; +PL_CompareStrings; +PL_CompareValues; +PL_FinishArenaPool; +PL_FreeArenaPool; +PL_HashString; +PL_HashTableAdd; +PL_HashTableDestroy; +PL_HashTableDump; +PL_HashTableEnumerateEntries; +PL_HashTableLookup; +PL_HashTableRawAdd; +PL_HashTableRawLookup; +PL_HashTableRawRemove; +PL_HashTableRemove; +PL_InitArenaPool; +PL_NewHashTable; +libVersionPoint; +;+ local: *; +;+}; +;+ +;+NSPR_4.1 { +;+ global: +PL_HashTableLookupConst; +PL_HashTableRawLookupConst; +;+} NSPR_4.0; diff --git a/nsprpub/lib/ds/plds.rc b/nsprpub/lib/ds/plds.rc new file mode 100644 index 00000000000..7a310df00aa --- /dev/null +++ b/nsprpub/lib/ds/plds.rc @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include + +#define MY_LIBNAME "plds" +#define MY_FILEDESCRIPTION "PLDS Library" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define PR_VMAJOR_STR STRINGIZE2(PR_VMAJOR) + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if PR_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#define MY_INTERNAL_NAME "lib" MY_LIBNAME PR_VMAJOR_STR +#else +#define MY_FILEOS VOS__WINDOWS32 +#define MY_INTERNAL_NAME MY_LIBNAME PR_VMAJOR_STR +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + PRODUCTVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Mozilla Foundation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", PR_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Netscape Portable Runtime\0" + VALUE "ProductVersion", PR_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/nsprpub/lib/ds/plds_symvec.opt b/nsprpub/lib/ds/plds_symvec.opt new file mode 100644 index 00000000000..7178454093b --- /dev/null +++ b/nsprpub/lib/ds/plds_symvec.opt @@ -0,0 +1,37 @@ +! Fixed section of symbol vector for LIBPLDS4 +! +GSMATCH=LEQUAL,2,2 +case_sensitive=YES +! +! -------------------------------------------------------------------------- +! Ident 2,2 introduced for Mozilla 1.3 +! Previously this was empty. Now we include everything that's specified in +! plds.def. +! -------------------------------------------------------------------------- +! +! NSPR 4.0 +SYMBOL_VECTOR=(PL_ArenaAllocate=PROCEDURE) +SYMBOL_VECTOR=(PL_ArenaFinish=PROCEDURE) +SYMBOL_VECTOR=(PL_ArenaGrow=PROCEDURE) +SYMBOL_VECTOR=(PL_ArenaRelease=PROCEDURE) +SYMBOL_VECTOR=(PL_CompactArenaPool=PROCEDURE) +SYMBOL_VECTOR=(PL_CompareStrings=PROCEDURE) +SYMBOL_VECTOR=(PL_CompareValues=PROCEDURE) +SYMBOL_VECTOR=(PL_FinishArenaPool=PROCEDURE) +SYMBOL_VECTOR=(PL_FreeArenaPool=PROCEDURE) +SYMBOL_VECTOR=(PL_HashString=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableAdd=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableDestroy=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableDump=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableEnumerateEntries=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableLookup=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRawAdd=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRawLookup=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRawRemove=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRemove=PROCEDURE) +SYMBOL_VECTOR=(PL_InitArenaPool=PROCEDURE) +SYMBOL_VECTOR=(PL_NewHashTable=PROCEDURE) +SYMBOL_VECTOR=(libVersionPoint=PROCEDURE) +! NSPR 4.1 +SYMBOL_VECTOR=(PL_HashTableLookupConst=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRawLookupConst=PROCEDURE) diff --git a/nsprpub/lib/ds/plhash.c b/nsprpub/lib/ds/plhash.c new file mode 100644 index 00000000000..48825bb3c4a --- /dev/null +++ b/nsprpub/lib/ds/plhash.c @@ -0,0 +1,541 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PL hash table package. + */ +#include "plhash.h" +#include "prbit.h" +#include "prlog.h" +#include "prmem.h" +#include "prtypes.h" +#include +#include + +/* Compute the number of buckets in ht */ +#define NBUCKETS(ht) (1 << (PL_HASH_BITS - (ht)->shift)) + +/* The smallest table has 16 buckets */ +#define MINBUCKETSLOG2 4 +#define MINBUCKETS (1 << MINBUCKETSLOG2) + +/* Compute the maximum entries given n buckets that we will tolerate, ~90% */ +#define OVERLOADED(n) ((n) - ((n) >> 3)) + +/* Compute the number of entries below which we shrink the table by half */ +#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0) + +/* +** Stubs for default hash allocator ops. +*/ +static void * PR_CALLBACK +DefaultAllocTable(void *pool, PRSize size) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + return PR_MALLOC(size); +} + +static void PR_CALLBACK +DefaultFreeTable(void *pool, void *item) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + PR_Free(item); +} + +static PLHashEntry * PR_CALLBACK +DefaultAllocEntry(void *pool, const void *key) +{ +#if defined(XP_MAC) +#pragma unused (pool,key) +#endif + + return PR_NEW(PLHashEntry); +} + +static void PR_CALLBACK +DefaultFreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + if (flag == HT_FREE_ENTRY) + PR_Free(he); +} + +static PLHashAllocOps defaultHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, DefaultFreeEntry +}; + +PR_IMPLEMENT(PLHashTable *) +PL_NewHashTable(PRUint32 n, PLHashFunction keyHash, + PLHashComparator keyCompare, PLHashComparator valueCompare, + const PLHashAllocOps *allocOps, void *allocPriv) +{ + PLHashTable *ht; + PRSize nb; + + if (n <= MINBUCKETS) { + n = MINBUCKETSLOG2; + } else { + n = PR_CeilingLog2(n); + if ((PRInt32)n < 0) + return 0; + } + + if (!allocOps) allocOps = &defaultHashAllocOps; + + ht = (PLHashTable*)((*allocOps->allocTable)(allocPriv, sizeof *ht)); + if (!ht) + return 0; + memset(ht, 0, sizeof *ht); + ht->shift = PL_HASH_BITS - n; + n = 1 << n; +#if defined(WIN16) + if (n > 16000) { + (*allocOps->freeTable)(allocPriv, ht); + return 0; + } +#endif /* WIN16 */ + nb = n * sizeof(PLHashEntry *); + ht->buckets = (PLHashEntry**)((*allocOps->allocTable)(allocPriv, nb)); + if (!ht->buckets) { + (*allocOps->freeTable)(allocPriv, ht); + return 0; + } + memset(ht->buckets, 0, nb); + + ht->keyHash = keyHash; + ht->keyCompare = keyCompare; + ht->valueCompare = valueCompare; + ht->allocOps = allocOps; + ht->allocPriv = allocPriv; + return ht; +} + +PR_IMPLEMENT(void) +PL_HashTableDestroy(PLHashTable *ht) +{ + PRUint32 i, n; + PLHashEntry *he, *next; + const PLHashAllocOps *allocOps = ht->allocOps; + void *allocPriv = ht->allocPriv; + + n = NBUCKETS(ht); + for (i = 0; i < n; i++) { + for (he = ht->buckets[i]; he; he = next) { + next = he->next; + (*allocOps->freeEntry)(allocPriv, he, HT_FREE_ENTRY); + } + } +#ifdef DEBUG + memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]); +#endif + (*allocOps->freeTable)(allocPriv, ht->buckets); +#ifdef DEBUG + memset(ht, 0xDB, sizeof *ht); +#endif + (*allocOps->freeTable)(allocPriv, ht); +} + +/* +** Multiplicative hash, from Knuth 6.4. +*/ +#define GOLDEN_RATIO 0x9E3779B9U /* 2/(1+sqrt(5))*(2^32) */ + +PR_IMPLEMENT(PLHashEntry **) +PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key) +{ + PLHashEntry *he, **hep, **hep0; + PLHashNumber h; + +#ifdef HASHMETER + ht->nlookups++; +#endif + h = keyHash * GOLDEN_RATIO; + h >>= ht->shift; + hep = hep0 = &ht->buckets[h]; + while ((he = *hep) != 0) { + if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) { + /* Move to front of chain if not already there */ + if (hep != hep0) { + *hep = he->next; + he->next = *hep0; + *hep0 = he; + } + return hep0; + } + hep = &he->next; +#ifdef HASHMETER + ht->nsteps++; +#endif + } + return hep; +} + +/* +** Same as PL_HashTableRawLookup but doesn't reorder the hash entries. +*/ +PR_IMPLEMENT(PLHashEntry **) +PL_HashTableRawLookupConst(PLHashTable *ht, PLHashNumber keyHash, + const void *key) +{ + PLHashEntry *he, **hep; + PLHashNumber h; + +#ifdef HASHMETER + ht->nlookups++; +#endif + h = keyHash * GOLDEN_RATIO; + h >>= ht->shift; + hep = &ht->buckets[h]; + while ((he = *hep) != 0) { + if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) { + break; + } + hep = &he->next; +#ifdef HASHMETER + ht->nsteps++; +#endif + } + return hep; +} + +PR_IMPLEMENT(PLHashEntry *) +PL_HashTableRawAdd(PLHashTable *ht, PLHashEntry **hep, + PLHashNumber keyHash, const void *key, void *value) +{ + PRUint32 i, n; + PLHashEntry *he, *next, **oldbuckets; + PRSize nb; + + /* Grow the table if it is overloaded */ + n = NBUCKETS(ht); + if (ht->nentries >= OVERLOADED(n)) { + oldbuckets = ht->buckets; +#if defined(WIN16) + if (2 * n > 16000) + return 0; +#endif /* WIN16 */ + nb = 2 * n * sizeof(PLHashEntry *); + ht->buckets = (PLHashEntry**) + ((*ht->allocOps->allocTable)(ht->allocPriv, nb)); + if (!ht->buckets) { + ht->buckets = oldbuckets; + return 0; + } + memset(ht->buckets, 0, nb); +#ifdef HASHMETER + ht->ngrows++; +#endif + ht->shift--; + + for (i = 0; i < n; i++) { + for (he = oldbuckets[i]; he; he = next) { + next = he->next; + hep = PL_HashTableRawLookup(ht, he->keyHash, he->key); + PR_ASSERT(*hep == 0); + he->next = 0; + *hep = he; + } + } +#ifdef DEBUG + memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]); +#endif + (*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets); + hep = PL_HashTableRawLookup(ht, keyHash, key); + } + + /* Make a new key value entry */ + he = (*ht->allocOps->allocEntry)(ht->allocPriv, key); + if (!he) + return 0; + he->keyHash = keyHash; + he->key = key; + he->value = value; + he->next = *hep; + *hep = he; + ht->nentries++; + return he; +} + +PR_IMPLEMENT(PLHashEntry *) +PL_HashTableAdd(PLHashTable *ht, const void *key, void *value) +{ + PLHashNumber keyHash; + PLHashEntry *he, **hep; + + keyHash = (*ht->keyHash)(key); + hep = PL_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) != 0) { + /* Hit; see if values match */ + if ((*ht->valueCompare)(he->value, value)) { + /* key,value pair is already present in table */ + return he; + } + if (he->value) + (*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_VALUE); + he->value = value; + return he; + } + return PL_HashTableRawAdd(ht, hep, keyHash, key, value); +} + +PR_IMPLEMENT(void) +PL_HashTableRawRemove(PLHashTable *ht, PLHashEntry **hep, PLHashEntry *he) +{ + PRUint32 i, n; + PLHashEntry *next, **oldbuckets; + PRSize nb; + + *hep = he->next; + (*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_ENTRY); + + /* Shrink table if it's underloaded */ + n = NBUCKETS(ht); + if (--ht->nentries < UNDERLOADED(n)) { + oldbuckets = ht->buckets; + nb = n * sizeof(PLHashEntry*) / 2; + ht->buckets = (PLHashEntry**)( + (*ht->allocOps->allocTable)(ht->allocPriv, nb)); + if (!ht->buckets) { + ht->buckets = oldbuckets; + return; + } + memset(ht->buckets, 0, nb); +#ifdef HASHMETER + ht->nshrinks++; +#endif + ht->shift++; + + for (i = 0; i < n; i++) { + for (he = oldbuckets[i]; he; he = next) { + next = he->next; + hep = PL_HashTableRawLookup(ht, he->keyHash, he->key); + PR_ASSERT(*hep == 0); + he->next = 0; + *hep = he; + } + } +#ifdef DEBUG + memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]); +#endif + (*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets); + } +} + +PR_IMPLEMENT(PRBool) +PL_HashTableRemove(PLHashTable *ht, const void *key) +{ + PLHashNumber keyHash; + PLHashEntry *he, **hep; + + keyHash = (*ht->keyHash)(key); + hep = PL_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) == 0) + return PR_FALSE; + + /* Hit; remove element */ + PL_HashTableRawRemove(ht, hep, he); + return PR_TRUE; +} + +PR_IMPLEMENT(void *) +PL_HashTableLookup(PLHashTable *ht, const void *key) +{ + PLHashNumber keyHash; + PLHashEntry *he, **hep; + + keyHash = (*ht->keyHash)(key); + hep = PL_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) != 0) { + return he->value; + } + return 0; +} + +/* +** Same as PL_HashTableLookup but doesn't reorder the hash entries. +*/ +PR_IMPLEMENT(void *) +PL_HashTableLookupConst(PLHashTable *ht, const void *key) +{ + PLHashNumber keyHash; + PLHashEntry *he, **hep; + + keyHash = (*ht->keyHash)(key); + hep = PL_HashTableRawLookupConst(ht, keyHash, key); + if ((he = *hep) != 0) { + return he->value; + } + return 0; +} + +/* +** Iterate over the entries in the hash table calling func for each +** entry found. Stop if "f" says to (return value & PR_ENUMERATE_STOP). +** Return a count of the number of elements scanned. +*/ +PR_IMPLEMENT(int) +PL_HashTableEnumerateEntries(PLHashTable *ht, PLHashEnumerator f, void *arg) +{ + PLHashEntry *he, **hep; + PRUint32 i, nbuckets; + int rv, n = 0; + PLHashEntry *todo = 0; + + nbuckets = NBUCKETS(ht); + for (i = 0; i < nbuckets; i++) { + hep = &ht->buckets[i]; + while ((he = *hep) != 0) { + rv = (*f)(he, n, arg); + n++; + if (rv & (HT_ENUMERATE_REMOVE | HT_ENUMERATE_UNHASH)) { + *hep = he->next; + if (rv & HT_ENUMERATE_REMOVE) { + he->next = todo; + todo = he; + } + } else { + hep = &he->next; + } + if (rv & HT_ENUMERATE_STOP) { + goto out; + } + } + } + +out: + hep = &todo; + while ((he = *hep) != 0) { + PL_HashTableRawRemove(ht, hep, he); + } + return n; +} + +#ifdef HASHMETER +#include +#include + +PR_IMPLEMENT(void) +PL_HashTableDumpMeter(PLHashTable *ht, PLHashEnumerator dump, FILE *fp) +{ + double mean, variance; + PRUint32 nchains, nbuckets; + PRUint32 i, n, maxChain, maxChainLen; + PLHashEntry *he; + + variance = 0; + nchains = 0; + maxChainLen = 0; + nbuckets = NBUCKETS(ht); + for (i = 0; i < nbuckets; i++) { + he = ht->buckets[i]; + if (!he) + continue; + nchains++; + for (n = 0; he; he = he->next) + n++; + variance += n * n; + if (n > maxChainLen) { + maxChainLen = n; + maxChain = i; + } + } + mean = (double)ht->nentries / nchains; + variance = fabs(variance / nchains - mean * mean); + + fprintf(fp, "\nHash table statistics:\n"); + fprintf(fp, " number of lookups: %u\n", ht->nlookups); + fprintf(fp, " number of entries: %u\n", ht->nentries); + fprintf(fp, " number of grows: %u\n", ht->ngrows); + fprintf(fp, " number of shrinks: %u\n", ht->nshrinks); + fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps + / ht->nlookups); + fprintf(fp, "mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sqrt(variance)); + fprintf(fp, " max hash chain length: %u\n", maxChainLen); + fprintf(fp, " max hash chain: [%u]\n", maxChain); + + for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++) + if ((*dump)(he, i, fp) != HT_ENUMERATE_NEXT) + break; +} +#endif /* HASHMETER */ + +PR_IMPLEMENT(int) +PL_HashTableDump(PLHashTable *ht, PLHashEnumerator dump, FILE *fp) +{ + int count; + + count = PL_HashTableEnumerateEntries(ht, dump, fp); +#ifdef HASHMETER + PL_HashTableDumpMeter(ht, dump, fp); +#endif + return count; +} + +PR_IMPLEMENT(PLHashNumber) +PL_HashString(const void *key) +{ + PLHashNumber h; + const PRUint8 *s; + + h = 0; + for (s = (const PRUint8*)key; *s; s++) + h = PR_ROTATE_LEFT32(h, 4) ^ *s; + return h; +} + +PR_IMPLEMENT(int) +PL_CompareStrings(const void *v1, const void *v2) +{ + return strcmp((const char*)v1, (const char*)v2) == 0; +} + +PR_IMPLEMENT(int) +PL_CompareValues(const void *v1, const void *v2) +{ + return v1 == v2; +} diff --git a/nsprpub/lib/ds/plhash.h b/nsprpub/lib/ds/plhash.h new file mode 100644 index 00000000000..45c9773fa27 --- /dev/null +++ b/nsprpub/lib/ds/plhash.h @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef plhash_h___ +#define plhash_h___ +/* + * API to portable hash table code. + */ +#include +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLHashEntry PLHashEntry; +typedef struct PLHashTable PLHashTable; +typedef PRUint32 PLHashNumber; +#define PL_HASH_BITS 32 /* Number of bits in PLHashNumber */ +typedef PLHashNumber (PR_CALLBACK *PLHashFunction)(const void *key); +typedef PRIntn (PR_CALLBACK *PLHashComparator)(const void *v1, const void *v2); + +#if defined(XP_OS2_VACPP) && defined(VACPP_FLIP) /* for nsSpaceManager.cpp */ +PR_END_EXTERN_C /* and nsHTMLDocument.cpp */ +#endif +typedef PRIntn (PR_CALLBACK *PLHashEnumerator)(PLHashEntry *he, PRIntn i, void *arg); + +#if defined(XP_OS2_VACPP) && defined(VACPP_FLIP) +PR_BEGIN_EXTERN_C +#endif + +/* Flag bits in PLHashEnumerator's return value */ +#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */ +#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */ +#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */ +#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */ + +typedef struct PLHashAllocOps { + void * (PR_CALLBACK *allocTable)(void *pool, PRSize size); + void (PR_CALLBACK *freeTable)(void *pool, void *item); + PLHashEntry * (PR_CALLBACK *allocEntry)(void *pool, const void *key); + void (PR_CALLBACK *freeEntry)(void *pool, PLHashEntry *he, PRUintn flag); +} PLHashAllocOps; + +#define HT_FREE_VALUE 0 /* just free the entry's value */ +#define HT_FREE_ENTRY 1 /* free value and entire entry */ + +struct PLHashEntry { + PLHashEntry *next; /* hash chain linkage */ + PLHashNumber keyHash; /* key hash function result */ + const void *key; /* ptr to opaque key */ + void *value; /* ptr to opaque value */ +}; + +struct PLHashTable { + PLHashEntry **buckets; /* vector of hash buckets */ + PRUint32 nentries; /* number of entries in table */ + PRUint32 shift; /* multiplicative hash shift */ + PLHashFunction keyHash; /* key hash function */ + PLHashComparator keyCompare; /* key comparison function */ + PLHashComparator valueCompare; /* value comparison function */ + const PLHashAllocOps *allocOps; /* allocation operations */ + void *allocPriv; /* allocation private data */ +#ifdef HASHMETER + PRUint32 nlookups; /* total number of lookups */ + PRUint32 nsteps; /* number of hash chains traversed */ + PRUint32 ngrows; /* number of table expansions */ + PRUint32 nshrinks; /* number of table contractions */ +#endif +}; + +/* + * Create a new hash table. + * If allocOps is null, use default allocator ops built on top of malloc(). + */ +PR_EXTERN(PLHashTable *) +PL_NewHashTable(PRUint32 numBuckets, PLHashFunction keyHash, + PLHashComparator keyCompare, PLHashComparator valueCompare, + const PLHashAllocOps *allocOps, void *allocPriv); + +PR_EXTERN(void) +PL_HashTableDestroy(PLHashTable *ht); + +/* Higher level access methods */ +PR_EXTERN(PLHashEntry *) +PL_HashTableAdd(PLHashTable *ht, const void *key, void *value); + +PR_EXTERN(PRBool) +PL_HashTableRemove(PLHashTable *ht, const void *key); + +PR_EXTERN(void *) +PL_HashTableLookup(PLHashTable *ht, const void *key); + +PR_EXTERN(void *) +PL_HashTableLookupConst(PLHashTable *ht, const void *key); + +PR_EXTERN(PRIntn) +PL_HashTableEnumerateEntries(PLHashTable *ht, PLHashEnumerator f, void *arg); + +/* General-purpose C string hash function. */ +PR_EXTERN(PLHashNumber) +PL_HashString(const void *key); + +/* Compare strings using strcmp(), return true if equal. */ +PR_EXTERN(PRIntn) +PL_CompareStrings(const void *v1, const void *v2); + +/* Stub function just returns v1 == v2 */ +PR_EXTERN(PRIntn) +PL_CompareValues(const void *v1, const void *v2); + +/* Low level access methods */ +PR_EXTERN(PLHashEntry **) +PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key); + +PR_EXTERN(PLHashEntry **) +PL_HashTableRawLookupConst(PLHashTable *ht, PLHashNumber keyHash, + const void *key); + +PR_EXTERN(PLHashEntry *) +PL_HashTableRawAdd(PLHashTable *ht, PLHashEntry **hep, PLHashNumber keyHash, + const void *key, void *value); + +PR_EXTERN(void) +PL_HashTableRawRemove(PLHashTable *ht, PLHashEntry **hep, PLHashEntry *he); + +/* This can be trivially implemented using PL_HashTableEnumerateEntries. */ +PR_EXTERN(PRIntn) +PL_HashTableDump(PLHashTable *ht, PLHashEnumerator dump, FILE *fp); + +PR_END_EXTERN_C + +#endif /* plhash_h___ */ diff --git a/nsprpub/lib/ds/plvrsion.c b/nsprpub/lib/ds/plvrsion.c new file mode 100644 index 00000000000..486a6cb1ff6 --- /dev/null +++ b/nsprpub/lib/ds/plvrsion.c @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#include "_pl_bld.h" +#if !defined(_BUILD_TIME) +#ifdef HAVE_LONG_LONG +#define _BUILD_TIME 0 +#else +#define _BUILD_TIME {0, 0} +#endif +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * A trick to expand the PR_VMAJOR macro before concatenation. + */ +#define CONCAT(x, y) x ## y +#define CONCAT2(x, y) CONCAT(x, y) +#define VERSION_DESC_NAME CONCAT2(prVersionDescription_libplds, PR_VMAJOR) + +PRVersionDescription VERSION_DESC_NAME = +{ + /* 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 */ "http://www.mozilla.org/MPL/", + /* specialString */ "" +}; + +#ifdef XP_UNIX + +/* + * Version information for the 'ident' and 'what commands + * + * NOTE: the first component of the concatenated rcsid string + * must not end in a '$' to prevent rcs keyword substitution. + */ +static char rcsid[] = "$Header: NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING " $"; +static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING; + +#endif /* XP_UNIX */ + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint() +{ +#ifdef XP_UNIX + /* + * Add dummy references to rcsid and sccsid to prevent them + * from being optimized away as unused variables. + */ + const char *dummy; + + dummy = rcsid; + dummy = sccsid; +#endif + return &VERSION_DESC_NAME; +} /* versionEntryPointType */ + +/* plvrsion.c */ + diff --git a/nsprpub/lib/libc/.cvsignore b/nsprpub/lib/libc/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/libc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/libc/Makefile.in b/nsprpub/lib/libc/Makefile.in new file mode 100644 index 00000000000..9755225a3dc --- /dev/null +++ b/nsprpub/lib/libc/Makefile.in @@ -0,0 +1,56 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +export NSPR20=1 + +include $(topsrcdir)/config/config.mk + +DIRS = include src + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/lib/libc/README b/nsprpub/lib/libc/README new file mode 100644 index 00000000000..74f246907f9 --- /dev/null +++ b/nsprpub/lib/libc/README @@ -0,0 +1,20 @@ +NSPR 2.0 libc functions +----------------------- + +Last edited: AOF 04 March 1997 + +This directory contains various libc-types of functions. All functions in +this directory are platform independent, thread friendly (both safe and +efficient). They are contributed from various sources, though the contri- +butions are monitored by the NSPR group (mailto:freier). + +All API items exported by these functions will contain the same three +character prefix, "PL_" (Portable Library). Internal function names +that are not exported (static) are of little concern, though some caution +must be used on those elements that are 'extern' but not really intended +to be part of the API. Those should all have a prefix of "_PL_" (is that +legal?). + +The responsibility for contributions in this area are distributed among +all interested parties. + diff --git a/nsprpub/lib/libc/include/.cvsignore b/nsprpub/lib/libc/include/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/libc/include/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/libc/include/MANIFEST b/nsprpub/lib/libc/include/MANIFEST new file mode 100644 index 00000000000..63e8861de2c --- /dev/null +++ b/nsprpub/lib/libc/include/MANIFEST @@ -0,0 +1,9 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +plbase64.h +plerror.h +plgetopt.h +plresolv.h +plstr.h diff --git a/nsprpub/lib/libc/include/Makefile.in b/nsprpub/lib/libc/include/Makefile.in new file mode 100644 index 00000000000..9d5e2e18668 --- /dev/null +++ b/nsprpub/lib/libc/include/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/config.mk + +HEADERS = $(wildcard $(srcdir)/*.h) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) + +include $(topsrcdir)/config/rules.mk + +export:: $(HEADERS) + $(INSTALL) -m 444 $(HEADERS) $(dist_includedir) +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(HEADERS) $(MOZ_INCL) +endif + + diff --git a/nsprpub/lib/libc/include/README b/nsprpub/lib/libc/include/README new file mode 100644 index 00000000000..2b85218910d --- /dev/null +++ b/nsprpub/lib/libc/include/README @@ -0,0 +1,7 @@ +NSPR 2.0 libc functions +----------------------- + +Last edited: AOF 04 March 1997 + +This directory contains the API for various libc-types of functions. + diff --git a/nsprpub/lib/libc/include/plbase64.h b/nsprpub/lib/libc/include/plbase64.h new file mode 100644 index 00000000000..ac07e837351 --- /dev/null +++ b/nsprpub/lib/libc/include/plbase64.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _plbase64_h +#define _plbase64_h + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* + * PL_Base64Encode + * + * This routine encodes the data pointed to by the "src" parameter using the + * base64 algorithm, and returns a pointer to the result. If the "srclen" + * parameter is not zero, it specifies the length of the source data. If it + * is zero, the source data is assumed to be null-terminated, and PL_strlen + * is used to determine the source length. If the "dest" parameter is not + * null, it is assumed to point to a buffer of sufficient size (which may be + * calculated: ((srclen + 2)/3)*4) into which the encoded data is placed + * (without any termination). If the "dest" parameter is null, a buffer is + * allocated from the heap to hold the encoded data, and the result *will* + * be terminated with an extra null character. It is the caller's + * responsibility to free the result when it is allocated. A null is returned + * if the allocation fails. + */ + +PR_EXTERN(char *) +PL_Base64Encode +( + const char *src, + PRUint32 srclen, + char *dest +); + +/* + * PL_Base64Decode + * + * This routine decodes the data pointed to by the "src" parameter using + * the base64 algorithm, and returns a pointer to the result. The source + * may either include or exclude any trailing '=' characters. If the + * "srclen" parameter is not zero, it specifies the length of the source + * data. If it is zero, PL_strlen will be used to determine the source + * length. If the "dest" parameter is not null, it is assumed to point to + * a buffer of sufficient size (which may be calculated: (srclen * 3)/4 + * when srclen includes the '=' characters) into which the decoded data + * is placed (without any termination). If the "dest" parameter is null, + * a buffer is allocated from the heap to hold the decoded data, and the + * result *will* be terminated with an extra null character. It is the + * caller's responsibility to free the result when it is allocated. A null + * is retuned if the allocation fails, or if the source is not well-coded. + */ + +PR_EXTERN(char *) +PL_Base64Decode +( + const char *src, + PRUint32 srclen, + char *dest +); + +PR_END_EXTERN_C + +#endif /* _plbase64_h */ diff --git a/nsprpub/lib/libc/include/plerror.h b/nsprpub/lib/libc/include/plerror.h new file mode 100644 index 00000000000..a2b8d0b2203 --- /dev/null +++ b/nsprpub/lib/libc/include/plerror.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: plerror.h +** Description: Simple routine to print translate the calling thread's +** error numbers and print them. +*/ + +#if defined(PLERROR_H) +#else +#define PLERROR_H + +#include "prio.h" +#include "prtypes.h" + +PR_BEGIN_EXTERN_C +/* +** Print the messages to "syserr" prepending 'msg' if not NULL. +*/ +PR_EXTERN(void) PL_PrintError(const char *msg); + +/* +** Print the messages to specified output file prepending 'msg' if not NULL. +*/ +PR_EXTERN(void) PL_FPrintError(PRFileDesc *output, const char *msg); + +PR_END_EXTERN_C + +#endif /* defined(PLERROR_H) */ + +/* plerror.h */ diff --git a/nsprpub/lib/libc/include/plgetopt.h b/nsprpub/lib/libc/include/plgetopt.h new file mode 100644 index 00000000000..fcdf23b6fc7 --- /dev/null +++ b/nsprpub/lib/libc/include/plgetopt.h @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: plgetopt.h +** Description: utilities to parse argc/argv +*/ + +#if defined(PLGETOPT_H_) +#else +#define PLGETOPT_H_ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLOptionInternal PLOptionInternal; + +typedef enum +{ + PL_OPT_OK, /* all's well with the option */ + PL_OPT_EOL, /* end of options list */ + PL_OPT_BAD /* invalid option (and value) */ +} PLOptStatus; + +typedef struct PLLongOpt +{ + const char * longOptName; /* long option name string */ + PRIntn longOption; /* value put in PLOptState for this option. */ + PRBool valueRequired; /* If option name not followed by '=', */ + /* value is the next argument from argv. */ +} PLLongOpt; + +typedef struct PLOptState +{ + char option; /* the name of the option */ + const char *value; /* the value of that option | NULL */ + + PLOptionInternal *internal; /* private processing state */ + + PRIntn longOption; /* value from PLLongOpt put here */ + PRIntn longOptIndex; /* index into caller's array of PLLongOpts */ +} PLOptState; + +/* + * PL_CreateOptState + * + * The argument "options" points to a string of single-character option + * names. Option names that may have an option argument value must be + * followed immediately by a ':' character. + */ +PR_EXTERN(PLOptState*) PL_CreateOptState( + PRIntn argc, char **argv, const char *options); + +/* + * PL_CreateLongOptState + * + * Alternative to PL_CreateOptState. + * Allows caller to specify BOTH a string of single-character option names, + * AND an array of structures describing "long" (keyword) option names. + * The array is terminated by a structure in which longOptName is NULL. + * Long option values (arguments) may always be given as "--name=value". + * If PLLongOpt.valueRequired is not PR_FALSE, and the option name was not + * followed by '=' then the next argument from argv is taken as the value. + */ +PR_EXTERN(PLOptState*) PL_CreateLongOptState( + PRIntn argc, char **argv, const char *options, + const PLLongOpt *longOpts); +/* + * PL_DestroyOptState + * + * Call this to destroy the PLOptState returned from PL_CreateOptState or + * PL_CreateLongOptState. + */ +PR_EXTERN(void) PL_DestroyOptState(PLOptState *opt); + +/* + * PL_GetNextOpt + * + * When this function returns PL_OPT_OK, + * - opt->option will hold the single-character option name that was parsed, + * or zero. + * When opt->option is zero, the token parsed was either a "long" (keyword) + * option or a positional parameter. + * For a positional parameter, + * - opt->longOptIndex will contain -1, and + * - opt->value will point to the positional parameter string. + * For a long option name, + * - opt->longOptIndex will contain the non-negative index of the + * PLLongOpt structure in the caller's array of PLLongOpt structures + 8 corresponding to the long option name, and + * For a single-character or long option, + * - opt->longOption will contain the value of the single-character option + * name, or the value of the longOption from the PLLongOpt structure + * for that long option. See notes below. + * - opt->value will point to the argument option string, or will + * be NULL if no argument option string was given. + * When opt->option is non-zero, + * - opt->longOptIndex will be -1 + * When this function returns PL_OPT_EOL, or PL_OPT_BAD, the contents of + * opt are undefined. + * + * Notes: It is possible to ignore opt->option, and always look at + * opt->longOption instead. opt->longOption will contain the same value + * as opt->option for single-character option names, and will contain the + * value of longOption from the PLLongOpt structure for long option names. + * This means that it is possible to equivalence long option names to + * single character names by giving the longOption in the PLLongOpt struct + * the same value as the single-character option name. + * For long options that are NOT intended to be equivalent to any single- + * character option, the longOption value should be chosen to not match + * any possible single character name. It might be advisable to choose + * longOption values greater than 0xff for such long options. + */ +PR_EXTERN(PLOptStatus) PL_GetNextOpt(PLOptState *opt); + +PR_END_EXTERN_C + +#endif /* defined(PLGETOPT_H_) */ + +/* plgetopt.h */ + diff --git a/nsprpub/lib/libc/include/plresolv.h b/nsprpub/lib/libc/include/plresolv.h new file mode 100644 index 00000000000..8e8926c6c16 --- /dev/null +++ b/nsprpub/lib/libc/include/plresolv.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * plresolv.h - asynchronous name resolution using DNS + */ + +#ifndef _PLRESOLV_H_ +#define _PLRESOLV_H_ + +/* +** THIS IS WORK IN PROGRESS. DO NOT ATTEMPT TO USE ANY PORTION OF THIS +** API UNTIL THIS MESSAGE NO LONGER EXISTS. IF YOU DO, THEN YOU SURRENDER +** THE RIGHT TO COMPLAIN ABOUT ANY CONTENT. +*/ + +#if defined(XP_UNIX) + +#include +#include + +NSPR_BEGIN_EXTERN_C + +#define PL_RESOLVE_MAXHOSTENTBUF 1024 +#define PL_RESOLVE_DEFAULT_TIMEOUT 0 + +/* Error return codes */ +#define PL_RESOLVE_OK 0 +#define PL_RESOLVE_EWINIT 1 /* Failed to initialize window */ +#define PL_RESOLVE_EMAKE 2 /* Failed to create request */ +#define PL_RESOLVE_ELAUNCH 3 /* Error launching Async request */ +#define PL_RESOLVE_ETIMEDOUT 4 /* Request timed-out */ +#define PL_RESOLVE_EINVAL 5 /* Invalid argument */ +#define PL_RESOLVE_EOVERFLOW 6 /* Buffer Overflow */ +#define PL_RESOLVE_EUNKNOWN 7 /* berserk error */ + +/* ----------- Function Prototypes ----------------*/ + +PR_EXTERN(PRStatus) PL_ResolveName( + const char *name, unsigned char *buf, + PRIntn bufsize, PRIntervalTime timeout, + PRHostEnt *hostentry, PRIntervalTime *ttl); + +PR_EXTERN(PRStatus) PL_ResolveAddr( + const PRNetAddr *address, unsigned char *buf, + PRIntn bufsize, PRIntervalTime timeout, + PRHostEnt *hostentry, PRIntervalTime *ttl); + +typedef struct PLResolveStats { + int re_errors; + int re_nu_look; + int re_na_look; + int re_replies; + int re_requests; + int re_resends; + int re_sent; + int re_timeouts; +} PLResolveStats; + +typedef struct PLResoveInfo { + PRBool enabled; + PRUint32 numNameLookups; + PRUint32 numAddrLookups; + PRUint32 numLookupsInProgress; + PLResolveStats stats; +} PLResoveInfo; + +PR_EXTERN(void) PL_ResolveInfo(PLResoveInfo *info); + +NSPR_END_EXTERN_C + +#endif /* defined(XP_UNIX) */ + +#endif /* _PLRESOLV_H_ */ diff --git a/nsprpub/lib/libc/include/plstr.h b/nsprpub/lib/libc/include/plstr.h new file mode 100644 index 00000000000..4d21cc46ef0 --- /dev/null +++ b/nsprpub/lib/libc/include/plstr.h @@ -0,0 +1,470 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Roland Mainz + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _plstr_h +#define _plstr_h + +/* + * plstr.h + * + * This header file exports the API to the NSPR portable library or string- + * handling functions. + * + * This API was not designed as an "optimal" or "ideal" string library; it + * was based on the good ol' unix string.3 functions, and was written to + * + * 1) replace the libc functions, for cross-platform consistency, + * 2) complete the API on platforms lacking common functions (e.g., + * strcase*), and + * 3) to implement some obvious "closure" functions that I've seen + * people hacking around in our code. + * + * Point number three largely means that most functions have an "strn" + * limited-length version, and all comparison routines have a non-case- + * sensitive version available. + */ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C +/* + * PL_strlen + * + * Returns the length of the provided string, not including the trailing '\0'. + */ + +PR_EXTERN(PRUint32) +PL_strlen(const char *str); + +/* + * PL_strnlen + * + * Returns the length of the provided string, not including the trailing '\0', + * up to the indicated maximum. The string will not be examined beyond the + * maximum; if no terminating '\0' is found, the maximum will be returned. + */ + +PR_EXTERN(PRUint32) +PL_strnlen(const char *str, PRUint32 max); + +/* + * PL_strcpy + * + * Copies the source string, up to and including the trailing '\0', into the + * destination buffer. It does not (can not) verify that the destination + * buffer is large enough. It returns the "dest" argument. + */ + +PR_EXTERN(char *) +PL_strcpy(char *dest, const char *src); + +/* + * PL_strncpy + * + * Copies the source string into the destination buffer, up to and including + * the trailing '\0' or up to and including the max'th character, whichever + * comes first. It does not (can not) verify that the destination buffer is + * large enough. If the source string is longer than the maximum length, + * the result will *not* be null-terminated (JLRU). + */ + +PR_EXTERN(char *) +PL_strncpy(char *dest, const char *src, PRUint32 max); + +/* + * PL_strncpyz + * + * Copies the source string into the destination buffer, up to and including + * the trailing '\0' or up but not including the max'th character, whichever + * comes first. It does not (can not) verify that the destination buffer is + * large enough. The destination string is always terminated with a '\0', + * unlike the traditional libc implementation. It returns the "dest" argument. + * + * NOTE: If you call this with a source "abcdefg" and a max of 5, the + * destination will end up with "abcd\0" (i.e., its strlen length will be 4)! + * + * This means you can do this: + * + * char buffer[ SOME_SIZE ]; + * PL_strncpyz(buffer, src, sizeof(buffer)); + * + * and the result will be properly terminated. + */ + +PR_EXTERN(char *) +PL_strncpyz(char *dest, const char *src, PRUint32 max); + +/* + * PL_strdup + * + * Returns a pointer to a malloc'd extent of memory containing a duplicate + * of the argument string. The size of the allocated extent is one greater + * than the length of the argument string, because of the terminator. A + * null argument, like a zero-length argument, will result in a pointer to + * a one-byte extent containing the null value. This routine returns null + * upon malloc failure. + */ + +PR_EXTERN(char *) +PL_strdup(const char *s); + +/* + * PL_strfree + * + * Free memory allocated by PL_strdup + */ + +PR_EXTERN(void) +PL_strfree(char *s); + +/* + * PL_strndup + * + * Returns a pointer to a malloc'd extent of memory containing a duplicate + * of the argument string, up to the maximum specified. If the argument + * string has a length greater than the value of the specified maximum, the + * return value will be a pointer to an extent of memory of length one + * greater than the maximum specified. A null string, a zero-length string, + * or a zero maximum will all result in a pointer to a one-byte extent + * containing the null value. This routine returns null upon malloc failure. + */ + +PR_EXTERN(char *) +PL_strndup(const char *s, PRUint32 max); + +/* + * PL_strcat + * + * Appends a copy of the string pointed to by the second argument to the + * end of the string pointed to by the first. The destination buffer is + * not (can not be) checked for sufficient size. A null destination + * argument returns null; otherwise, the first argument is returned. + */ + +PR_EXTERN(char *) +PL_strcat(char *dst, const char *src); + +/* + * PL_strncat + * + * Appends a copy of the string pointed to by the second argument, up to + * the maximum size specified, to the end of the string pointed to by the + * first. The destination buffer is not (can not be) checked for sufficient + * size. A null destination argument returns null; otherwise, the first + * argument is returned. If the maximum size limits the copy, then the + * result will *not* be null-terminated (JLRU). A null destination + * returns null; otherwise, the destination argument is returned. + */ + +PR_EXTERN(char *) +PL_strncat(char *dst, const char *src, PRUint32 max); + +/* + * PL_strcatn + * + * Appends a copy of the string pointed to by the third argument, to the + * end of the string pointed to by the first. The second argument specifies + * the maximum size of the destination buffer, including the null termination. + * If the existing string in dst is longer than the max, no action is taken. + * The resulting string will be null-terminated. A null destination returns + * null; otherwise, the destination argument is returned. + */ + +PR_EXTERN(char *) +PL_strcatn(char *dst, PRUint32 max, const char *src); + +/* + * PL_strcmp + * + * Returns an integer, the sign of which -- positive, zero, or negative -- + * reflects the lexical sorting order of the two strings indicated. The + * result is positive if the first string comes after the second. The + * NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strcmp(const char *a, const char *b); + +/* + * PL_strncmp + * + * Returns an integer, the sign of which -- positive, zero, or negative -- + * reflects the lexical sorting order of the two strings indicated, up to + * the maximum specified. The result is positive if the first string comes + * after the second. The NSPR implementation is not i18n. If the maximum + * is zero, only the existance or non-existance (pointer is null) of the + * strings is compared. + */ + +PR_EXTERN(PRIntn) +PL_strncmp(const char *a, const char *b, PRUint32 max); + +/* + * PL_strcasecmp + * + * Returns an integer, the sign of which -- positive, zero or negative -- + * reflects the case-insensitive lexical sorting order of the two strings + * indicated. The result is positive if the first string comes after the + * second. The NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strcasecmp(const char *a, const char *b); + +/* + * PL_strncasecmp + * + * Returns an integer, the sign of which -- positive, zero or negative -- + * reflects the case-insensitive lexical sorting order of the first n characters + * of the two strings indicated. The result is positive if the first string comes + * after the second. The NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strncasecmp(const char *a, const char *b, PRUint32 max); + +/* + * PL_strchr + * + * Returns a pointer to the first instance of the specified character in the + * provided string. It returns null if the character is not found, or if the + * provided string is null. The character may be the null character. + */ + +PR_EXTERN(char *) +PL_strchr(const char *s, char c); + +/* + * PL_strrchr + * + * Returns a pointer to the last instance of the specified character in the + * provided string. It returns null if the character is not found, or if the + * provided string is null. The character may be the null character. + */ + +PR_EXTERN(char *) +PL_strrchr(const char *s, char c); + +/* + * PL_strnchr + * + * Returns a pointer to the first instance of the specified character within the + * first n characters of the provided string. It returns null if the character + * is not found, or if the provided string is null. The character may be the + * null character. + */ + +PR_EXTERN(char *) +PL_strnchr(const char *s, char c, PRUint32 n); + +/* + * PL_strnrchr + * + * Returns a pointer to the last instance of the specified character within the + * first n characters of the provided string. It returns null if the character is + * not found, or if the provided string is null. The character may be the null + * character. + */ + +PR_EXTERN(char *) +PL_strnrchr(const char *s, char c, PRUint32 n); + +/* + * NOTE: Looking for strcasechr, strcaserchr, strncasechr, or strncaserchr? + * Use strpbrk, strprbrk, strnpbrk or strnprbrk. + */ + +/* + * PL_strpbrk + * + * Returns a pointer to the first instance in the first string of any character + * (not including the terminating null character) of the second string. It returns + * null if either string is null. + */ + +PR_EXTERN(char *) +PL_strpbrk(const char *s, const char *list); + +/* + * PL_strprbrk + * + * Returns a pointer to the last instance in the first string of any character + * (not including the terminating null character) of the second string. It returns + * null if either string is null. + */ + +PR_EXTERN(char *) +PL_strprbrk(const char *s, const char *list); + +/* + * PL_strnpbrk + * + * Returns a pointer to the first instance (within the first n characters) of any + * character (not including the terminating null character) of the second string. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strnpbrk(const char *s, const char *list, PRUint32 n); + +/* + * PL_strnprbrk + * + * Returns a pointer to the last instance (within the first n characters) of any + * character (not including the terminating null character) of the second string. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strnprbrk(const char *s, const char *list, PRUint32 n); + +/* + * PL_strstr + * + * Returns a pointer to the first instance of the little string within the + * big one. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strstr(const char *big, const char *little); + +/* + * PL_strrstr + * + * Returns a pointer to the last instance of the little string within the big one. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strrstr(const char *big, const char *little); + +/* + * PL_strnstr + * + * Returns a pointer to the first instance of the little string within the first + * n characters of the big one. It returns null if either string is null. It + * returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strnstr(const char *big, const char *little, PRUint32 n); + +/* + * PL_strnrstr + * + * Returns a pointer to the last instance of the little string within the first + * n characters of the big one. It returns null if either string is null. It + * returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strnrstr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strcasestr + * + * Returns a pointer to the first instance of the little string within the big one, + * ignoring case. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strcasestr(const char *big, const char *little); + +/* + * PL_strcaserstr + * + * Returns a pointer to the last instance of the little string within the big one, + * ignoring case. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strcaserstr(const char *big, const char *little); + +/* + * PL_strncasestr + * + * Returns a pointer to the first instance of the little string within the first + * n characters of the big one, ignoring case. It returns null if either string is + * null. It returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strncasestr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strncaserstr + * + * Returns a pointer to the last instance of the little string within the first + * n characters of the big one, ignoring case. It returns null if either string is + * null. It returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strncaserstr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strtok_r + * + * Splits the string s1 into tokens, separated by one or more characters + * from the separator string s2. The argument lasts points to a + * user-supplied char * pointer in which PL_strtok_r stores information + * for it to continue scanning the same string. + * + * In the first call to PL_strtok_r, s1 points to a string and the value + * of *lasts is ignored. PL_strtok_r returns a pointer to the first + * token, writes '\0' into the character following the first token, and + * updates *lasts. + * + * In subsequent calls, s1 is null and lasts must stay unchanged from the + * previous call. The separator string s2 may be different from call to + * call. PL_strtok_r returns a pointer to the next token in s1. When no + * token remains in s1, PL_strtok_r returns null. + */ + +PR_EXTERN(char *) +PL_strtok_r(char *s1, const char *s2, char **lasts); + +/* + * Things not (yet?) included: strspn/strcspn, strsep. + * memchr, memcmp, memcpy, memccpy, index, rindex, bcmp, bcopy, bzero. + * Any and all i18n/l10n stuff. + */ + +PR_END_EXTERN_C + +#endif /* _plstr_h */ diff --git a/nsprpub/lib/libc/src/.cvsignore b/nsprpub/lib/libc/src/.cvsignore new file mode 100644 index 00000000000..bcab60f5aad --- /dev/null +++ b/nsprpub/lib/libc/src/.cvsignore @@ -0,0 +1,2 @@ +Makefile +_pl_bld.h diff --git a/nsprpub/lib/libc/src/Makefile.in b/nsprpub/lib/libc/src/Makefile.in new file mode 100644 index 00000000000..a0f4295f92e --- /dev/null +++ b/nsprpub/lib/libc/src/Makefile.in @@ -0,0 +1,197 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +INCLUDES = -I$(dist_includedir) + +CSRCS =\ + plvrsion.c \ + strlen.c \ + strcpy.c \ + strdup.c \ + strcat.c \ + strcmp.c \ + strccmp.c \ + strchr.c \ + strpbrk.c \ + strstr.c \ + strcstr.c \ + strtok.c \ + base64.c \ + plerror.c \ + plgetopt.c \ + $(NULL) + +LIBRARY_NAME = plc +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_LIBS = $(TARGETS) + +ifeq ($(OS_ARCH),WINNT) +RES=$(OBJDIR)/plc.res +RESNAME=plc.rc +endif # WINNT + +ifeq ($(OS_ARCH), AIX) +ifeq ($(CLASSIC_NSPR),1) +OS_LIBS = -lc +else +OS_LIBS = -lc_r +endif +endif + +ifeq ($(OS_ARCH),IRIX) +OS_LIBS = -lc +endif + +ifeq ($(OS_ARCH),SunOS) +OS_LIBS = -lc +MAPFILE = $(OBJDIR)/plcmap.sun +GARBAGE += $(MAPFILE) +ifdef NS_USE_GCC +ifdef GCC_USE_GNU_LD +MKSHLIB += -Wl,--version-script,$(MAPFILE) +else +MKSHLIB += -Wl,-M,$(MAPFILE) +endif +else +MKSHLIB += -M $(MAPFILE) +endif +# The -R '$ORIGIN' linker option instructs this library to search for its +# dependencies in the same directory where it resides. +MKSHLIB += -R '$$ORIGIN' +endif + +ifeq ($(OS_ARCH),OS2) +MAPFILE = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).def +GARBAGE += $(MAPFILE) +MKSHLIB += $(MAPFILE) +endif + +EXTRA_LIBS = $(LIBNSPR) + +# On NCR and SCOOS, we can't link with extra libraries when +# we build a shared library. If we do so, the linker doesn't +# complain, but we would run into weird problems at run-time. +# Therefore on these platforms, we link just the .o files. +ifeq ($(OS_ARCH),NCR) +EXTRA_LIBS = +endif +ifeq ($(OS_ARCH),SCOOS) +EXTRA_LIBS = +endif + +ifdef RESOLVE_LINK_SYMBOLS +EXTRA_LIBS += $(OS_LIBS) +endif + +include $(topsrcdir)/config/rules.mk + +# +# Version information generation (begin) +# +ECHO = echo +TINC = $(OBJDIR)/_pl_bld.h +PROD = $(notdir $(SHARED_LIBRARY)) +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date "+%Y-%m-%d %T") +SH_NOW = $(shell $(NOW)) + +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + SUF = i64 +else + SUF = LL +endif + +GARBAGE += $(TINC) + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) '#define _BUILD_STRING "$(SH_DATE)"' > $(TINC) + @if test ! -z "$(SH_NOW)"; then \ + $(ECHO) '#define _BUILD_TIME $(SH_NOW)$(SUF)' >> $(TINC); \ + else \ + true; \ + fi + @$(ECHO) '#define _PRODUCTION "$(PROD)"' >> $(TINC) + + +$(OBJDIR)/plvrsion.$(OBJ_SUFFIX): plvrsion.c $(TINC) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else +ifeq ($(MOZ_OS2_TOOLS), VACPP) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +endif +endif +# +# Version information generation (end) +# + +# +# The Client build wants the shared libraries in $(dist_bindir), +# so we also install them there. +# + +export:: $(TARGETS) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifdef SHARED_LIBRARY +ifeq ($(OS_ARCH),HP-UX) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_libdir) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_bindir) +else + $(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_bindir) +endif +endif +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin +endif + diff --git a/nsprpub/lib/libc/src/README b/nsprpub/lib/libc/src/README new file mode 100644 index 00000000000..74f246907f9 --- /dev/null +++ b/nsprpub/lib/libc/src/README @@ -0,0 +1,20 @@ +NSPR 2.0 libc functions +----------------------- + +Last edited: AOF 04 March 1997 + +This directory contains various libc-types of functions. All functions in +this directory are platform independent, thread friendly (both safe and +efficient). They are contributed from various sources, though the contri- +butions are monitored by the NSPR group (mailto:freier). + +All API items exported by these functions will contain the same three +character prefix, "PL_" (Portable Library). Internal function names +that are not exported (static) are of little concern, though some caution +must be used on those elements that are 'extern' but not really intended +to be part of the API. Those should all have a prefix of "_PL_" (is that +legal?). + +The responsibility for contributions in this area are distributed among +all interested parties. + diff --git a/nsprpub/lib/libc/src/base64.c b/nsprpub/lib/libc/src/base64.c new file mode 100644 index 00000000000..234d60d8fbf --- /dev/null +++ b/nsprpub/lib/libc/src/base64.c @@ -0,0 +1,428 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plbase64.h" +#include "prlog.h" /* For PR_NOT_REACHED */ +#include "prmem.h" /* for malloc / PR_MALLOC */ +#include "plstr.h" /* for PL_strlen */ + +static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void +encode3to4 +( + const unsigned char *src, + unsigned char *dest +) +{ + PRUint32 b32 = (PRUint32)0; + PRIntn i, j = 18; + + for( i = 0; i < 3; i++ ) + { + b32 <<= 8; + b32 |= (PRUint32)src[i]; + } + + for( i = 0; i < 4; i++ ) + { + dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ]; + j -= 6; + } + + return; +} + +static void +encode2to4 +( + const unsigned char *src, + unsigned char *dest +) +{ + dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ]; + dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ]; + dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ]; + dest[3] = (unsigned char)'='; + return; +} + +static void +encode1to4 +( + const unsigned char *src, + unsigned char *dest +) +{ + dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ]; + dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ]; + dest[2] = (unsigned char)'='; + dest[3] = (unsigned char)'='; + return; +} + +static void +encode +( + const unsigned char *src, + PRUint32 srclen, + unsigned char *dest +) +{ + while( srclen >= 3 ) + { + encode3to4(src, dest); + src += 3; + dest += 4; + srclen -= 3; + } + + switch( srclen ) + { + case 2: + encode2to4(src, dest); + break; + case 1: + encode1to4(src, dest); + break; + case 0: + break; + default: + PR_NOT_REACHED("coding error"); + } + + return; +} + +/* + * PL_Base64Encode + * + * If the destination argument is NULL, a return buffer is + * allocated, and the data therein will be null-terminated. + * If the destination argument is not NULL, it is assumed to + * be of sufficient size, and the contents will not be null- + * terminated by this routine. + * + * Returns null if the allocation fails. + */ + +PR_IMPLEMENT(char *) +PL_Base64Encode +( + const char *src, + PRUint32 srclen, + char *dest +) +{ + if( 0 == srclen ) + { + srclen = PL_strlen(src); + } + + if( (char *)0 == dest ) + { + PRUint32 destlen = ((srclen + 2)/3) * 4; + dest = (char *)PR_MALLOC(destlen + 1); + if( (char *)0 == dest ) + { + return (char *)0; + } + dest[ destlen ] = (char)0; /* null terminate */ + } + + encode((const unsigned char *)src, srclen, (unsigned char *)dest); + return dest; +} + +static PRInt32 +codetovalue +( + unsigned char c +) +{ + if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') ) + { + return (PRInt32)(c - (unsigned char)'A'); + } + else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') ) + { + return ((PRInt32)(c - (unsigned char)'a') +26); + } + else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') ) + { + return ((PRInt32)(c - (unsigned char)'0') +52); + } + else if( (unsigned char)'+' == c ) + { + return (PRInt32)62; + } + else if( (unsigned char)'/' == c ) + { + return (PRInt32)63; + } + else + { + return -1; + } +} + +static PRStatus +decode4to3 +( + const unsigned char *src, + unsigned char *dest +) +{ + PRUint32 b32 = (PRUint32)0; + PRInt32 bits; + PRIntn i; + + for( i = 0; i < 4; i++ ) + { + bits = codetovalue(src[i]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + b32 <<= 6; + b32 |= bits; + } + + dest[0] = (unsigned char)((b32 >> 16) & 0xFF); + dest[1] = (unsigned char)((b32 >> 8) & 0xFF); + dest[2] = (unsigned char)((b32 ) & 0xFF); + + return PR_SUCCESS; +} + +static PRStatus +decode3to2 +( + const unsigned char *src, + unsigned char *dest +) +{ + PRUint32 b32 = (PRUint32)0; + PRInt32 bits; + PRUint32 ubits; + + bits = codetovalue(src[0]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + b32 = (PRUint32)bits; + b32 <<= 6; + + bits = codetovalue(src[1]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + b32 |= (PRUint32)bits; + b32 <<= 4; + + bits = codetovalue(src[2]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + ubits = (PRUint32)bits; + b32 |= (ubits >> 2); + + dest[0] = (unsigned char)((b32 >> 8) & 0xFF); + dest[1] = (unsigned char)((b32 ) & 0xFF); + + return PR_SUCCESS; +} + +static PRStatus +decode2to1 +( + const unsigned char *src, + unsigned char *dest +) +{ + PRUint32 b32; + PRUint32 ubits; + PRInt32 bits; + + bits = codetovalue(src[0]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + ubits = (PRUint32)bits; + b32 = (ubits << 2); + + bits = codetovalue(src[1]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + ubits = (PRUint32)bits; + b32 |= (ubits >> 4); + + dest[0] = (unsigned char)b32; + + return PR_SUCCESS; +} + +static PRStatus +decode +( + const unsigned char *src, + PRUint32 srclen, + unsigned char *dest +) +{ + PRStatus rv; + + while( srclen >= 4 ) + { + rv = decode4to3(src, dest); + if( PR_SUCCESS != rv ) + { + return PR_FAILURE; + } + + src += 4; + dest += 3; + srclen -= 4; + } + + switch( srclen ) + { + case 3: + rv = decode3to2(src, dest); + break; + case 2: + rv = decode2to1(src, dest); + break; + case 1: + rv = PR_FAILURE; + break; + case 0: + rv = PR_SUCCESS; + break; + default: + PR_NOT_REACHED("coding error"); + } + + return rv; +} + +/* + * PL_Base64Decode + * + * If the destination argument is NULL, a return buffer is + * allocated and the data therein will be null-terminated. + * If the destination argument is not null, it is assumed + * to be of sufficient size, and the data will not be null- + * terminated by this routine. + * + * Returns null if the allocation fails, or if the source string is + * not well-formed. + */ + +PR_IMPLEMENT(char *) +PL_Base64Decode +( + const char *src, + PRUint32 srclen, + char *dest +) +{ + PRStatus status; + PRBool allocated = PR_FALSE; + + if( (char *)0 == src ) + { + return (char *)0; + } + + if( 0 == srclen ) + { + srclen = PL_strlen(src); + } + + if( srclen && (0 == (srclen & 3)) ) + { + if( (char)'=' == src[ srclen-1 ] ) + { + if( (char)'=' == src[ srclen-2 ] ) + { + srclen -= 2; + } + else + { + srclen -= 1; + } + } + } + + if( (char *)0 == dest ) + { + PRUint32 destlen = ((srclen * 3) / 4); + dest = (char *)PR_MALLOC(destlen + 1); + if( (char *)0 == dest ) + { + return (char *)0; + } + dest[ destlen ] = (char)0; /* null terminate */ + allocated = PR_TRUE; + } + + status = decode((const unsigned char *)src, srclen, (unsigned char *)dest); + if( PR_SUCCESS != status ) + { + if( PR_TRUE == allocated ) + { + PR_DELETE(dest); + } + + return (char *)0; + } + + return dest; +} diff --git a/nsprpub/lib/libc/src/plc.def b/nsprpub/lib/libc/src/plc.def new file mode 100644 index 00000000000..bb996a13dbd --- /dev/null +++ b/nsprpub/lib/libc/src/plc.def @@ -0,0 +1,104 @@ +;+# +;+# ***** BEGIN LICENSE BLOCK ***** +;+# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +;+# +;+# The contents of this file are subject to the Mozilla Public License Version +;+# 1.1 (the "License"); you may not use this file except in compliance with +;+# the License. You may obtain a copy of the License at +;+# http://www.mozilla.org/MPL/ +;+# +;+# Software distributed under the License is distributed on an "AS IS" basis, +;+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +;+# for the specific language governing rights and limitations under the +;+# License. +;+# +;+# The Original Code is the Netscape Portable Runtime (NSPR). +;+# +;+# The Initial Developer of the Original Code is +;+# Netscape Communications Corporation. +;+# Portions created by the Initial Developer are Copyright (C) 2002-2003 +;+# the Initial Developer. All Rights Reserved. +;+# +;+# Contributor(s): +;+# +;+# Alternatively, the contents of this file may be used under the terms of +;+# either the GNU General Public License Version 2 or later (the "GPL"), or +;+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +;+# in which case the provisions of the GPL or the LGPL are applicable instead +;+# of those above. If you wish to allow use of your version of this file only +;+# under the terms of either the GPL or the LGPL, and not to allow others to +;+# use your version of this file under the terms of the MPL, indicate your +;+# decision by deleting the provisions above and replace them with the notice +;+# and other provisions required by the GPL or the LGPL. If you do not delete +;+# the provisions above, a recipient may use your version of this file under +;+# the terms of any one of the MPL, the GPL or the LGPL. +;+# +;+# ***** END LICENSE BLOCK ***** +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+NSPR_4.0 { +;+ global: +LIBRARY plc4 ;- +EXPORTS ;- +PL_Base64Decode; +PL_Base64Encode; +PL_CreateOptState; +PL_DestroyOptState; +PL_FPrintError; +PL_GetNextOpt; +PL_PrintError; +PL_strcasecmp; +PL_strcaserstr; +PL_strcasestr; +PL_strcat; +PL_strcatn; +PL_strchr; +PL_strcmp; +PL_strcpy; +PL_strdup; +PL_strfree; +PL_strlen; +PL_strncasecmp; +PL_strncaserstr; +PL_strncasestr; +PL_strncat; +PL_strnchr; +PL_strncmp; +PL_strncpy; +PL_strncpyz; +PL_strndup; +PL_strnlen; +PL_strnpbrk; +PL_strnprbrk; +PL_strnrchr; +PL_strnrstr; +PL_strnstr; +PL_strpbrk; +PL_strprbrk; +PL_strrchr; +PL_strrstr; +PL_strstr; +libVersionPoint; +;+ local: *; +;+}; +;+ +;+NSPR_4.2 { +;+ global: +PL_strtok_r; +;+} NSPR_4.0; +;+ +;+NSPR_4.7 { +;+ global: +PL_CreateLongOptState; +;+} NSPR_4.2; diff --git a/nsprpub/lib/libc/src/plc.rc b/nsprpub/lib/libc/src/plc.rc new file mode 100644 index 00000000000..c20df277318 --- /dev/null +++ b/nsprpub/lib/libc/src/plc.rc @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "prinit.h" +#include + +#define MY_LIBNAME "plc" +#define MY_FILEDESCRIPTION "PLC Library" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define PR_VMAJOR_STR STRINGIZE2(PR_VMAJOR) + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if PR_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#define MY_INTERNAL_NAME "lib" MY_LIBNAME PR_VMAJOR_STR +#else +#define MY_FILEOS VOS__WINDOWS32 +#define MY_INTERNAL_NAME MY_LIBNAME PR_VMAJOR_STR +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + PRODUCTVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Mozilla Foundation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", PR_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Netscape Portable Runtime\0" + VALUE "ProductVersion", PR_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/nsprpub/lib/libc/src/plc_symvec.opt b/nsprpub/lib/libc/src/plc_symvec.opt new file mode 100644 index 00000000000..8bc769e0b4c --- /dev/null +++ b/nsprpub/lib/libc/src/plc_symvec.opt @@ -0,0 +1,53 @@ +! Fixed section of symbol vector for LIBPLC4 +! +GSMATCH=LEQUAL,2,2 +case_sensitive=YES +! +! -------------------------------------------------------------------------- +! Ident 2,2 introduced for Mozilla 1.3 +! Previously this was empty. Now we include everything that's specified in +! plc.def. +! -------------------------------------------------------------------------- +! +! NSPR 4.0 +SYMBOL_VECTOR=(PL_Base64Decode=PROCEDURE) +SYMBOL_VECTOR=(PL_Base64Encode=PROCEDURE) +SYMBOL_VECTOR=(PL_CreateOptState=PROCEDURE) +SYMBOL_VECTOR=(PL_DestroyOptState=PROCEDURE) +SYMBOL_VECTOR=(PL_FPrintError=PROCEDURE) +SYMBOL_VECTOR=(PL_GetNextOpt=PROCEDURE) +SYMBOL_VECTOR=(PL_PrintError=PROCEDURE) +SYMBOL_VECTOR=(PL_strcasecmp=PROCEDURE) +SYMBOL_VECTOR=(PL_strcaserstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strcasestr=PROCEDURE) +SYMBOL_VECTOR=(PL_strcat=PROCEDURE) +SYMBOL_VECTOR=(PL_strcatn=PROCEDURE) +SYMBOL_VECTOR=(PL_strchr=PROCEDURE) +SYMBOL_VECTOR=(PL_strcmp=PROCEDURE) +SYMBOL_VECTOR=(PL_strcpy=PROCEDURE) +SYMBOL_VECTOR=(PL_strdup=PROCEDURE) +SYMBOL_VECTOR=(PL_strfree=PROCEDURE) +SYMBOL_VECTOR=(PL_strlen=PROCEDURE) +SYMBOL_VECTOR=(PL_strncasecmp=PROCEDURE) +SYMBOL_VECTOR=(PL_strncaserstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strncasestr=PROCEDURE) +SYMBOL_VECTOR=(PL_strncat=PROCEDURE) +SYMBOL_VECTOR=(PL_strnchr=PROCEDURE) +SYMBOL_VECTOR=(PL_strncmp=PROCEDURE) +SYMBOL_VECTOR=(PL_strncpy=PROCEDURE) +SYMBOL_VECTOR=(PL_strncpyz=PROCEDURE) +SYMBOL_VECTOR=(PL_strndup=PROCEDURE) +SYMBOL_VECTOR=(PL_strnlen=PROCEDURE) +SYMBOL_VECTOR=(PL_strnpbrk=PROCEDURE) +SYMBOL_VECTOR=(PL_strnprbrk=PROCEDURE) +SYMBOL_VECTOR=(PL_strnrchr=PROCEDURE) +SYMBOL_VECTOR=(PL_strnrstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strnstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strpbrk=PROCEDURE) +SYMBOL_VECTOR=(PL_strprbrk=PROCEDURE) +SYMBOL_VECTOR=(PL_strrchr=PROCEDURE) +SYMBOL_VECTOR=(PL_strrstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strstr=PROCEDURE) +SYMBOL_VECTOR=(libVersionPoint=PROCEDURE) +! NSPR 4.2 +SYMBOL_VECTOR=(PL_strtok_r=PROCEDURE) diff --git a/nsprpub/lib/libc/src/plerror.c b/nsprpub/lib/libc/src/plerror.c new file mode 100644 index 00000000000..4941050cc8d --- /dev/null +++ b/nsprpub/lib/libc/src/plerror.c @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File:plerror.c +** Description: Simple routine to print translate the calling thread's +** error numbers and print them to "syserr". +*/ + +#include "plerror.h" + +#include "prprf.h" +#include "prerror.h" + +PR_IMPLEMENT(void) PL_FPrintError(PRFileDesc *fd, const char *msg) +{ +PRErrorCode error = PR_GetError(); +PRInt32 oserror = PR_GetOSError(); +const char *name = PR_ErrorToName(error); + + if (NULL != msg) PR_fprintf(fd, "%s: ", msg); + if (NULL == name) + PR_fprintf( + fd, " (%d)OUT OF RANGE, oserror = %d\n", error, oserror); + else + PR_fprintf( + fd, "%s(%d), oserror = %d\n", + name, error, oserror); +} /* PL_FPrintError */ + +PR_IMPLEMENT(void) PL_PrintError(const char *msg) +{ + static PRFileDesc *fd = NULL; + if (NULL == fd) fd = PR_GetSpecialFD(PR_StandardError); + PL_FPrintError(fd, msg); +} /* PL_PrintError */ + +#if defined(WIN16) +/* +** libmain() is a required function for win16 +** +*/ +int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpszCmdLine ) +{ +return TRUE; +} +#endif /* WIN16 */ + + + + + +/* plerror.c */ diff --git a/nsprpub/lib/libc/src/plgetopt.c b/nsprpub/lib/libc/src/plgetopt.c new file mode 100644 index 00000000000..0fe4fafe5ba --- /dev/null +++ b/nsprpub/lib/libc/src/plgetopt.c @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: plgetopt.c +** Description: utilities to parse argc/argv +*/ + +#include "prmem.h" +#include "prlog.h" +#include "prerror.h" +#include "plstr.h" +#include "plgetopt.h" + +#include + +static char static_Nul = 0; + +struct PLOptionInternal +{ + const char *options; /* client options list specification */ + PRIntn argc; /* original number of arguments */ + char **argv; /* vector of pointers to arguments */ + PRIntn xargc; /* which one we're processing now */ + const char *xargv; /* where within *argv[xargc] */ + PRIntn minus; /* do we already have the '-'? */ + const PLLongOpt *longOpts; /* Caller's array */ + PRBool endOfOpts; /* have reached a "--" argument */ + PRIntn optionsLen; /* is strlen(options) */ +}; + +/* +** Create the state in which to parse the tokens. +** +** argc the sum of the number of options and their values +** argv the options and their values +** options vector of single character options w/ | w/o ': +*/ +PR_IMPLEMENT(PLOptState*) PL_CreateOptState( + PRIntn argc, char **argv, const char *options) +{ + return PL_CreateLongOptState( argc, argv, options, NULL); +} /* PL_CreateOptState */ + +PR_IMPLEMENT(PLOptState*) PL_CreateLongOptState( + PRIntn argc, char **argv, const char *options, + const PLLongOpt *longOpts) +{ + PLOptState *opt = NULL; + PLOptionInternal *internal; + + if (NULL == options) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return opt; + } + + opt = PR_NEWZAP(PLOptState); + if (NULL == opt) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return opt; + } + + internal = PR_NEW(PLOptionInternal); + if (NULL == internal) + { + PR_DELETE(opt); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + opt->option = 0; + opt->value = NULL; + opt->internal = internal; + opt->longOption = 0; + opt->longOptIndex = -1; + + internal->argc = argc; + internal->argv = argv; + internal->xargc = 0; + internal->xargv = &static_Nul; + internal->minus = 0; + internal->options = options; + internal->longOpts = longOpts; + internal->endOfOpts = PR_FALSE; + internal->optionsLen = PL_strlen(options); + + return opt; +} /* PL_CreateLongOptState */ + +/* +** Destroy object created by CreateOptState() +*/ +PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState *opt) +{ + PR_DELETE(opt->internal); + PR_DELETE(opt); +} /* PL_DestroyOptState */ + +PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState *opt) +{ + PLOptionInternal *internal = opt->internal; + + opt->longOption = 0; + opt->longOptIndex = -1; + /* + ** If the current xarg points to nul, advance to the next + ** element of the argv vector. If the vector index is equal + ** to argc, we're out of arguments, so return an EOL. + ** Note whether the first character of the new argument is + ** a '-' and skip by it if it is. + */ + while (0 == *internal->xargv) + { + internal->xargc += 1; + if (internal->xargc >= internal->argc) + { + opt->option = 0; + opt->value = NULL; + return PL_OPT_EOL; + } + internal->xargv = internal->argv[internal->xargc]; + internal->minus = 0; + if (!internal->endOfOpts && ('-' == *internal->xargv)) + { + internal->minus++; + internal->xargv++; /* and consume */ + if ('-' == *internal->xargv && internal->longOpts) + { + internal->minus++; + internal->xargv++; + if (0 == *internal->xargv) + { + internal->endOfOpts = PR_TRUE; + } + } + } + } + + /* + ** If we already have a '-' or '--' in hand, xargv points to the next + ** option. See if we can find a match in the list of possible + ** options supplied. + */ + + if (internal->minus == 2) + { + char * foundEqual = strchr(internal->xargv,'='); + PRIntn optNameLen = foundEqual ? (foundEqual - internal->xargv) : + strlen(internal->xargv); + const PLLongOpt *longOpt = internal->longOpts; + + opt->option = 0; + opt->value = NULL; + + for (; longOpt->longOptName; ++longOpt) + { + if (strncmp(longOpt->longOptName, internal->xargv, optNameLen)) + continue; /* not a possible match */ + if (strlen(longOpt->longOptName) != optNameLen) + continue; /* not a match */ + /* option name match */ + opt->longOptIndex = longOpt - internal->longOpts; + opt->longOption = longOpt->longOption; + if (foundEqual) + { + opt->value = foundEqual[1] ? foundEqual + 1 : NULL; + } + else if (longOpt->valueRequired) + { + opt->value = internal->argv[++(internal->xargc)]; + } + internal->xargv = &static_Nul; /* consume this */ + return PL_OPT_OK; + } + internal->xargv = &static_Nul; /* consume this */ + return PL_OPT_BAD; + } + if (internal->minus) + { + PRIntn cop; + PRIntn eoo = internal->optionsLen; + for (cop = 0; cop < eoo; ++cop) + { + if (internal->options[cop] == *internal->xargv) + { + opt->option = *internal->xargv++; + opt->longOption = opt->option & 0xff; + /* + ** if options indicates that there's an associated + ** value, this argv is finished and the next is the + ** option's value. + */ + if (':' == internal->options[cop + 1]) + { + if (0 != *internal->xargv) + return PL_OPT_BAD; + opt->value = internal->argv[++(internal->xargc)]; + internal->xargv = &static_Nul; + internal->minus = 0; + } + else + opt->value = NULL; + return PL_OPT_OK; + } + } + internal->xargv += 1; /* consume that option */ + return PL_OPT_BAD; + } + /* + ** No '-', so it must be a standalone value. The option is nul. + */ + opt->value = internal->argv[internal->xargc]; + internal->xargv = &static_Nul; + opt->option = 0; + return PL_OPT_OK; +} /* PL_GetNextOpt */ + +/* plgetopt.c */ diff --git a/nsprpub/lib/libc/src/plvrsion.c b/nsprpub/lib/libc/src/plvrsion.c new file mode 100644 index 00000000000..e9903cb7178 --- /dev/null +++ b/nsprpub/lib/libc/src/plvrsion.c @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#include "_pl_bld.h" +#if !defined(_BUILD_TIME) +#ifdef HAVE_LONG_LONG +#define _BUILD_TIME 0 +#else +#define _BUILD_TIME {0, 0} +#endif +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * A trick to expand the PR_VMAJOR macro before concatenation. + */ +#define CONCAT(x, y) x ## y +#define CONCAT2(x, y) CONCAT(x, y) +#define VERSION_DESC_NAME CONCAT2(prVersionDescription_libplc, PR_VMAJOR) + +PRVersionDescription VERSION_DESC_NAME = +{ + /* 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 */ "http://www.mozilla.org/MPL/", + /* specialString */ "" +}; + +#ifdef XP_UNIX + +/* + * Version information for the 'ident' and 'what commands + * + * NOTE: the first component of the concatenated rcsid string + * must not end in a '$' to prevent rcs keyword substitution. + */ +static char rcsid[] = "$Header: NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING " $"; +static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING; + +#endif /* XP_UNIX */ + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint() +{ +#ifdef XP_UNIX + /* + * Add dummy references to rcsid and sccsid to prevent them + * from being optimized away as unused variables. + */ + const char *dummy; + + dummy = rcsid; + dummy = sccsid; +#endif + return &VERSION_DESC_NAME; +} /* versionEntryPointType */ + +/* plvrsion.c */ + diff --git a/nsprpub/lib/libc/src/strcat.c b/nsprpub/lib/libc/src/strcat.c new file mode 100644 index 00000000000..f71b0974f44 --- /dev/null +++ b/nsprpub/lib/libc/src/strcat.c @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strcat(char *dest, const char *src) +{ + if( ((char *)0 == dest) || ((const char *)0 == src) ) + return dest; + + return strcat(dest, src); +} + +PR_IMPLEMENT(char *) +PL_strncat(char *dest, const char *src, PRUint32 max) +{ + char *rv; + + if( ((char *)0 == dest) || ((const char *)0 == src) || (0 == max) ) + return dest; + + for( rv = dest; *dest; dest++ ) + ; + + (void)PL_strncpy(dest, src, max); + return rv; +} + +PR_IMPLEMENT(char *) +PL_strcatn(char *dest, PRUint32 max, const char *src) +{ + char *rv; + PRUint32 dl; + + if( ((char *)0 == dest) || ((const char *)0 == src) ) + return dest; + + for( rv = dest, dl = 0; *dest; dest++, dl++ ) + ; + + if( max <= dl ) return rv; + (void)PL_strncpyz(dest, src, max-dl); + + return rv; +} diff --git a/nsprpub/lib/libc/src/strccmp.c b/nsprpub/lib/libc/src/strccmp.c new file mode 100644 index 00000000000..ec87748443b --- /dev/null +++ b/nsprpub/lib/libc/src/strccmp.c @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" + +static const unsigned char uc[] = +{ + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + ' ', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '{', '|', '}', '~', '\177', + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 +}; + +PR_IMPLEMENT(PRIntn) +PL_strcasecmp(const char *a, const char *b) +{ + const unsigned char *ua = (const unsigned char *)a; + const unsigned char *ub = (const unsigned char *)b; + + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + while( (uc[*ua] == uc[*ub]) && ('\0' != *a) ) + { + a++; + ua++; + ub++; + } + + return (PRIntn)(uc[*ua] - uc[*ub]); +} + +PR_IMPLEMENT(PRIntn) +PL_strncasecmp(const char *a, const char *b, PRUint32 max) +{ + const unsigned char *ua = (const unsigned char *)a; + const unsigned char *ub = (const unsigned char *)b; + + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + while( max && (uc[*ua] == uc[*ub]) && ('\0' != *a) ) + { + a++; + ua++; + ub++; + max--; + } + + if( 0 == max ) return (PRIntn)0; + + return (PRIntn)(uc[*ua] - uc[*ub]); +} diff --git a/nsprpub/lib/libc/src/strchr.c b/nsprpub/lib/libc/src/strchr.c new file mode 100644 index 00000000000..35ccedcc71c --- /dev/null +++ b/nsprpub/lib/libc/src/strchr.c @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strchr(const char *s, char c) +{ + if( (const char *)0 == s ) return (char *)0; + + return strchr(s, c); +} + +PR_IMPLEMENT(char *) +PL_strrchr(const char *s, char c) +{ + if( (const char *)0 == s ) return (char *)0; + + return strrchr(s, c); +} + +PR_IMPLEMENT(char *) +PL_strnchr(const char *s, char c, PRUint32 n) +{ + if( (const char *)0 == s ) return (char *)0; + + for( ; n && *s; s++, n-- ) + if( *s == c ) + return (char *)s; + + if( ((char)0 == c) && (n > 0) && ((char)0 == *s) ) return (char *)s; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnrchr(const char *s, char c, PRUint32 n) +{ + const char *p; + + if( (const char *)0 == s ) return (char *)0; + + for( p = s; n && *p; p++, n-- ) + ; + + if( ((char)0 == c) && (n > 0) && ((char)0 == *p) ) return (char *)p; + + for( p--; p >= s; p-- ) + if( *p == c ) + return (char *)p; + + return (char *)0; +} diff --git a/nsprpub/lib/libc/src/strcmp.c b/nsprpub/lib/libc/src/strcmp.c new file mode 100644 index 00000000000..095e178468b --- /dev/null +++ b/nsprpub/lib/libc/src/strcmp.c @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include + +PR_IMPLEMENT(PRIntn) +PL_strcmp(const char *a, const char *b) +{ + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + return (PRIntn)strcmp(a, b); +} + +PR_IMPLEMENT(PRIntn) +PL_strncmp(const char *a, const char *b, PRUint32 max) +{ + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + return (PRIntn)strncmp(a, b, (size_t)max); +} diff --git a/nsprpub/lib/libc/src/strcpy.c b/nsprpub/lib/libc/src/strcpy.c new file mode 100644 index 00000000000..b576b677799 --- /dev/null +++ b/nsprpub/lib/libc/src/strcpy.c @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strcpy(char *dest, const char *src) +{ + if( ((char *)0 == dest) || ((const char *)0 == src) ) return (char *)0; + + return strcpy(dest, src); +} + +PR_IMPLEMENT(char *) +PL_strncpy(char *dest, const char *src, PRUint32 max) +{ + char *rv; + + if( (char *)0 == dest ) return (char *)0; + if( (const char *)0 == src ) return (char *)0; + + for( rv = dest; max && ((*dest = *src) != 0); dest++, src++, max-- ) + ; + +#ifdef JLRU + /* XXX I (wtc) think the -- and ++ operators should be postfix. */ + while( --max ) + *++dest = '\0'; +#endif /* JLRU */ + + return rv; +} + +PR_IMPLEMENT(char *) +PL_strncpyz(char *dest, const char *src, PRUint32 max) +{ + char *rv; + + if( (char *)0 == dest ) return (char *)0; + if( (const char *)0 == src ) return (char *)0; + if( 0 == max ) return (char *)0; + + for( rv = dest, max--; max && ((*dest = *src) != 0); dest++, src++, max-- ) + ; + + *dest = '\0'; + + return rv; +} diff --git a/nsprpub/lib/libc/src/strcstr.c b/nsprpub/lib/libc/src/strcstr.c new file mode 100644 index 00000000000..33421270051 --- /dev/null +++ b/nsprpub/lib/libc/src/strcstr.c @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" + +PR_IMPLEMENT(char *) +PL_strcasestr(const char *big, const char *little) +{ + PRUint32 ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = PL_strlen(little); + + for( ; *big; big++ ) + /* obvious improvement available here */ + if( 0 == PL_strncasecmp(big, little, ll) ) + return (char *)big; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strcaserstr(const char *big, const char *little) +{ + const char *p; + PRUint32 bl, ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + bl = PL_strlen(big); + ll = PL_strlen(little); + if( bl < ll ) return (char *)0; + p = &big[ bl - ll ]; + + for( ; p >= big; p-- ) + /* obvious improvement available here */ + if( 0 == PL_strncasecmp(p, little, ll) ) + return (char *)p; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strncasestr(const char *big, const char *little, PRUint32 max) +{ + PRUint32 ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = PL_strlen(little); + if( ll > max ) return (char *)0; + max -= ll; + max++; + + for( ; max && *big; big++, max-- ) + /* obvious improvement available here */ + if( 0 == PL_strncasecmp(big, little, ll) ) + return (char *)big; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strncaserstr(const char *big, const char *little, PRUint32 max) +{ + const char *p; + PRUint32 ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = PL_strlen(little); + + for( p = big; max && *p; p++, max-- ) + ; + + p -= ll; + if( p < big ) return (char *)0; + + for( ; p >= big; p-- ) + /* obvious improvement available here */ + if( 0 == PL_strncasecmp(p, little, ll) ) + return (char *)p; + + return (char *)0; +} diff --git a/nsprpub/lib/libc/src/strdup.c b/nsprpub/lib/libc/src/strdup.c new file mode 100644 index 00000000000..27a553c6629 --- /dev/null +++ b/nsprpub/lib/libc/src/strdup.c @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include "prmem.h" +#include + +PR_IMPLEMENT(char *) +PL_strdup(const char *s) +{ + char *rv; + size_t n; + + if( (const char *)0 == s ) + s = ""; + + n = strlen(s) + 1; + + rv = (char *)malloc(n); + if( (char *)0 == rv ) return rv; + + (void)memcpy(rv, s, n); + + return rv; +} + +PR_IMPLEMENT(void) +PL_strfree(char *s) +{ + free(s); +} + +PR_IMPLEMENT(char *) +PL_strndup(const char *s, PRUint32 max) +{ + char *rv; + size_t l; + + if( (const char *)0 == s ) + s = ""; + + l = PL_strnlen(s, max); + + rv = (char *)malloc(l+1); + if( (char *)0 == rv ) return rv; + + (void)memcpy(rv, s, l); + rv[l] = '\0'; + + return rv; +} diff --git a/nsprpub/lib/libc/src/strlen.c b/nsprpub/lib/libc/src/strlen.c new file mode 100644 index 00000000000..6c47677727b --- /dev/null +++ b/nsprpub/lib/libc/src/strlen.c @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include "prtypes.h" +#include "prlog.h" +#include + +PR_IMPLEMENT(PRUint32) +PL_strlen(const char *str) +{ + size_t l; + + if( (const char *)0 == str ) return 0; + + l = strlen(str); + + /* error checking in case we have a 64-bit platform -- make sure + * we don't have ultra long strings that overflow an int32 + */ + if( sizeof(PRUint32) < sizeof(size_t) ) + PR_ASSERT(l < 2147483647); + + return (PRUint32)l; +} + +PR_IMPLEMENT(PRUint32) +PL_strnlen(const char *str, PRUint32 max) +{ + register const char *s; + + if( (const char *)0 == str ) return 0; + for( s = str; max && *s; s++, max-- ) + ; + + return (PRUint32)(s - str); +} diff --git a/nsprpub/lib/libc/src/strpbrk.c b/nsprpub/lib/libc/src/strpbrk.c new file mode 100644 index 00000000000..afcb4f511b2 --- /dev/null +++ b/nsprpub/lib/libc/src/strpbrk.c @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strpbrk(const char *s, const char *list) +{ + if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0; + + return strpbrk(s, list); +} + +PR_IMPLEMENT(char *) +PL_strprbrk(const char *s, const char *list) +{ + const char *p; + const char *r; + + if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0; + + for( r = s; *r; r++ ) + ; + + for( r--; r >= s; r-- ) + for( p = list; *p; p++ ) + if( *r == *p ) + return (char *)r; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnpbrk(const char *s, const char *list, PRUint32 max) +{ + const char *p; + + if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0; + + for( ; max && *s; s++, max-- ) + for( p = list; *p; p++ ) + if( *s == *p ) + return (char *)s; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnprbrk(const char *s, const char *list, PRUint32 max) +{ + const char *p; + const char *r; + + if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0; + + for( r = s; max && *r; r++, max-- ) + ; + + for( r--; r >= s; r-- ) + for( p = list; *p; p++ ) + if( *r == *p ) + return (char *)r; + + return (char *)0; +} diff --git a/nsprpub/lib/libc/src/strstr.c b/nsprpub/lib/libc/src/strstr.c new file mode 100644 index 00000000000..6bc03d37080 --- /dev/null +++ b/nsprpub/lib/libc/src/strstr.c @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strstr(const char *big, const char *little) +{ + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + return strstr(big, little); +} + +PR_IMPLEMENT(char *) +PL_strrstr(const char *big, const char *little) +{ + const char *p; + size_t ll; + size_t bl; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = strlen(little); + bl = strlen(big); + if( bl < ll ) return (char *)0; + p = &big[ bl - ll ]; + + for( ; p >= big; p-- ) + if( *little == *p ) + if( 0 == strncmp(p, little, ll) ) + return (char *)p; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnstr(const char *big, const char *little, PRUint32 max) +{ + size_t ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = strlen(little); + if( ll > (size_t)max ) return (char *)0; + max -= (PRUint32)ll; + max++; + + for( ; max && *big; big++, max-- ) + if( *little == *big ) + if( 0 == strncmp(big, little, ll) ) + return (char *)big; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnrstr(const char *big, const char *little, PRUint32 max) +{ + const char *p; + size_t ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = strlen(little); + + for( p = big; max && *p; p++, max-- ) + ; + + p -= ll; + if( p < big ) return (char *)0; + + for( ; p >= big; p-- ) + if( *little == *p ) + if( 0 == strncmp(p, little, ll) ) + return (char *)p; + + return (char *)0; +} diff --git a/nsprpub/lib/libc/src/strtok.c b/nsprpub/lib/libc/src/strtok.c new file mode 100644 index 00000000000..400e9a4c042 --- /dev/null +++ b/nsprpub/lib/libc/src/strtok.c @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Roland Mainz + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" + +PR_IMPLEMENT(char *) +PL_strtok_r(char *s1, const char *s2, char **lasts) +{ + const char *sepp; + int c, sc; + char *tok; + + if( s1 == NULL ) + { + if( *lasts == NULL ) + return NULL; + + s1 = *lasts; + } + + for( ; (c = *s1) != 0; s1++ ) + { + for( sepp = s2 ; (sc = *sepp) != 0 ; sepp++ ) + { + if( c == sc ) + break; + } + if( sc == 0 ) + break; + } + + if( c == 0 ) + { + *lasts = NULL; + return NULL; + } + + tok = s1++; + + for( ; (c = *s1) != 0; s1++ ) + { + for( sepp = s2; (sc = *sepp) != 0; sepp++ ) + { + if( c == sc ) + { + *s1++ = '\0'; + *lasts = s1; + return tok; + } + } + } + *lasts = NULL; + return tok; +} diff --git a/nsprpub/lib/msgc/.cvsignore b/nsprpub/lib/msgc/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/msgc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/msgc/Makefile.in b/nsprpub/lib/msgc/Makefile.in new file mode 100644 index 00000000000..d7299b2bb56 --- /dev/null +++ b/nsprpub/lib/msgc/Makefile.in @@ -0,0 +1,52 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = include src tests + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/lib/msgc/include/.cvsignore b/nsprpub/lib/msgc/include/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/msgc/include/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/msgc/include/MANIFEST b/nsprpub/lib/msgc/include/MANIFEST new file mode 100644 index 00000000000..a45ec20ec4b --- /dev/null +++ b/nsprpub/lib/msgc/include/MANIFEST @@ -0,0 +1,5 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +prgc.h diff --git a/nsprpub/lib/msgc/include/Makefile.in b/nsprpub/lib/msgc/include/Makefile.in new file mode 100644 index 00000000000..60803a02861 --- /dev/null +++ b/nsprpub/lib/msgc/include/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/config.mk + +EXPORT_HEADERS = prgc.h +HEADERS = $(EXPORT_HEADERS) gcint.h + +RELEASE_HEADERS = $(EXPORT_HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) + +include $(topsrcdir)/config/rules.mk + +export:: $(EXPORT_HEADERS) + $(INSTALL) -m 444 $(EXPORT_HEADERS) $(dist_includedir) +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(EXPORT_HEADERS) $(MOZ_INCL) +endif + diff --git a/nsprpub/lib/msgc/include/gcint.h b/nsprpub/lib/msgc/include/gcint.h new file mode 100644 index 00000000000..10048f06891 --- /dev/null +++ b/nsprpub/lib/msgc/include/gcint.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef gcint_h___ +#define gcint_h___ + +#include "prmon.h" +#include "prgc.h" + +extern PRLogModuleInfo *_pr_msgc_lm; +extern GCInfo _pr_gcData; + +#if defined(_WIN32) && !defined(DEBUG) +#undef INLINE_LOCK +#endif + +#ifdef INLINE_LOCK +#define LOCK_GC() EnterCriticalSection(&_pr_gcData.lock->mutexHandle) +#define UNLOCK_GC() LeaveCriticalSection(&_pr_gcData.lock->mutexHandle) +#else +#define LOCK_GC() PR_EnterMonitor(_pr_gcData.lock) +#define UNLOCK_GC() PR_ExitMonitor (_pr_gcData.lock) +#define GC_IS_LOCKED() (PR_GetMonitorEntryCount(_pr_gcData.lock)!=0) +#endif + +#ifdef DEBUG +#define _GCTRACE(x, y) if (_pr_gcData.flags & x) GCTrace y +#else +#define _GCTRACE(x, y) +#endif + +extern GCBeginGCHook *_pr_beginGCHook; +extern void *_pr_beginGCHookArg; +extern GCBeginGCHook *_pr_endGCHook; +extern void *_pr_endGCHookArg; + +extern GCBeginFinalizeHook *_pr_beginFinalizeHook; +extern void *_pr_beginFinalizeHookArg; +extern GCBeginFinalizeHook *_pr_endFinalizeHook; +extern void *_pr_endFinalizeHookArg; + +extern int _pr_do_a_dump; +extern FILE *_pr_dump_file; + +extern PRLogModuleInfo *_pr_gc_lm; + +/* +** Root finders. Root finders are used by the GC to find pointers into +** the GC heap that are not contained in the GC heap. +*/ +typedef struct RootFinderStr RootFinder; + +struct RootFinderStr { + RootFinder *next; + GCRootFinder *func; + char *name; + void *arg; +}; +extern RootFinder *_pr_rootFinders; + +typedef struct CollectorTypeStr { + GCType gctype; + PRUint32 flags; +} CollectorType; + +#define GC_MAX_TYPES 256 +extern CollectorType *_pr_collectorTypes; + +#define _GC_TYPE_BUSY 0x1 +#define _GC_TYPE_FINAL 0x2 +#define _GC_TYPE_WEAK 0x4 + +/* Slot in _pr_gcTypes used for free memory */ +#define FREE_MEMORY_TYPEIX 255 + +extern void _PR_InitGC(PRWord flags); +extern void _MD_InitGC(void); +extern void PR_CALLBACK _PR_ScanFinalQueue(void *notused); + +/* +** Grow the GC Heap. +*/ +extern void *_MD_GrowGCHeap(PRUint32 *sizep); + +/* +** Extend the GC Heap. +*/ +extern PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize); + +/* +** Free a GC segment. +*/ +extern void _MD_FreeGCSegment(void *base, PRInt32 len); + +#endif /* gcint_h___ */ diff --git a/nsprpub/lib/msgc/include/prgc.h b/nsprpub/lib/msgc/include/prgc.h new file mode 100644 index 00000000000..859f7b1c0dd --- /dev/null +++ b/nsprpub/lib/msgc/include/prgc.h @@ -0,0 +1,419 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prgc_h___ +#define prgc_h___ + +/* +** API to NSPR gc memory system. +*/ +#include "prtypes.h" +#include "prmon.h" +#include "prthread.h" +#include + +#if defined(WIN16) +#define GCPTR __far +#else +#define GCPTR +#endif + + +PR_BEGIN_EXTERN_C + +/* +** Initialize the garbage collector. +** "flags" is the trace flags (see below). +** "initialHeapSize" is the initial size of the heap and may be zero +** if the default is desired. +** "segmentSize" is the size of each segment of memory added to the +** heap when the heap is grown. +*/ +PR_EXTERN(void) PR_InitGC( + PRWord flags, PRInt32 initialHeapSize, PRInt32 segmentSize, PRThreadScope scope); + +/* +** Shuts down gc and frees up all memory associated with it. +*/ +PR_EXTERN(void) PR_ShutdownGC(PRBool finalizeOnExit); + +/* +** This walk function will be called for every gc object in the +** heap as it is walked. If it returns non-zero, the walk is terminated. +*/ +typedef PRInt32 (*PRWalkFun)(void GCPTR* obj, void* data); + +/* +** GC Type record. This defines all of the GC operations used on a +** particular object type. These structures are passed to +** PR_RegisterType. +*/ +typedef struct GCType { + /* + ** Scan an object that is in the GC heap and call GCInfo.livePointer + ** on all of the pointers in it. If this slot is null then the object + ** won't be scanned (i.e. it has no embedded pointers). + */ + void (PR_CALLBACK *scan)(void GCPTR *obj); + + /* + ** Finalize an object that has no references. This is called by the + ** GC after it has determined where the object debris is but before + ** it has moved the debris to the logical "free list". The object is + ** marked alive for this call and removed from the list of objects + ** that need finalization (finalization only happens once for an + ** object). If this slot is null then the object doesn't need + ** finalization. + */ + void (PR_CALLBACK *finalize)(void GCPTR *obj); + + /* + ** Dump out an object during a PR_DumpGCHeap(). This is used as a + ** debugging tool. + */ + void (PR_CALLBACK *dump)(FILE *out, void GCPTR *obj, PRBool detailed, PRIntn indentLevel); + + /* + ** Add object to summary table. + */ + void (PR_CALLBACK *summarize)(void GCPTR *obj, PRUint32 bytes); + + /* + ** Free hook called by GC when the object is being freed. + */ + void (PR_CALLBACK *free)(void *obj); + + /* Weak pointer support: If the object has a weak pointer (Note: + at most one), this function is used to get the weak link's + offset from the start of the body of a gc object */ + PRUint32 (PR_CALLBACK *getWeakLinkOffset)(void *obj); + + /* Descriptive character for dumping this GCType */ + char kindChar; + + /* + ** Walker routine. This routine should apply fun(obj->ptr, data) + ** for every gc pointer within the object. + */ + PRInt32 (PR_CALLBACK *walk)(void GCPTR *obj, PRWalkFun fun, void* data); +} GCType; + +/* +** This data structure must be added as the hash table passed to +** the summarize method of GCType. +*/ +typedef struct PRSummaryEntry { + void* clazz; + PRInt32 instancesCount; + PRInt32 totalSize; +} PRSummaryEntry; + +/* +** This function pointer must be registered by users of nspr +** to produce the finally summary after all object in the +** heap have been visited. +*/ +typedef void (PR_CALLBACK *PRSummaryPrinter)(FILE *out, void* closure); + +PR_EXTERN(void) PR_CALLBACK PR_RegisterSummaryPrinter(PRSummaryPrinter fun, void* closure); + +typedef void PR_CALLBACK GCRootFinder(void *arg); +typedef void PR_CALLBACK GCBeginFinalizeHook(void *arg); +typedef void PR_CALLBACK GCEndFinalizeHook(void *arg); +typedef void PR_CALLBACK GCBeginGCHook(void *arg); +typedef void PR_CALLBACK GCEndGCHook(void *arg); + +typedef enum { PR_GCBEGIN, PR_GCEND } GCLockHookArg; + +typedef void PR_CALLBACK GCLockHookFunc(GCLockHookArg arg1, void *arg2); + +typedef struct GCLockHook GCLockHook; + +struct GCLockHook { + GCLockHookFunc* func; + void* arg; + GCLockHook* next; + GCLockHook* prev; +}; + + +/* +** Hooks which are called at the beginning and end of the GC process. +** The begin hooks are called before the root finding step. The hooks are +** called with threading disabled, so it is now allowed to re-enter the +** kernel. The end hooks are called after the gc has finished but before +** the finalizer has run. +*/ +PR_EXTERN(void) PR_CALLBACK PR_SetBeginGCHook(GCBeginGCHook *hook, void *arg); +PR_EXTERN(void) PR_CALLBACK PR_GetBeginGCHook(GCBeginGCHook **hook, void **arg); +PR_EXTERN(void) PR_CALLBACK PR_SetEndGCHook(GCBeginGCHook *hook, void *arg); +PR_EXTERN(void) PR_CALLBACK PR_GetEndGCHook(GCEndGCHook **hook, void **arg); + +/* +** Called before SuspendAll is called by dogc, so that GC thread can hold +** all the locks before hand to avoid any deadlocks +*/ + +/* +PR_EXTERN(void) PR_SetGCLockHook(GCLockHook *hook, void *arg); +PR_EXTERN(void) PR_GetGCLockHook(GCLockHook **hook, void **arg); +*/ + +PR_EXTERN(int) PR_RegisterGCLockHook(GCLockHookFunc *hook, void *arg); + +/* +** Hooks which are called at the beginning and end of the GC finalization +** process. After the GC has identified all of the dead objects in the +** heap, it looks for objects that need finalization. Before it calls the +** first finalization proc (see the GCType structure above) it calls the +** begin hook. When it has finalized the last object it calls the end +** hook. +*/ +PR_EXTERN(void) PR_SetBeginFinalizeHook(GCBeginFinalizeHook *hook, void *arg); +PR_EXTERN(void) PR_GetBeginFinalizeHook(GCBeginFinalizeHook **hook, void **arg); +PR_EXTERN(void) PR_SetEndFinalizeHook(GCBeginFinalizeHook *hook, void *arg); +PR_EXTERN(void) PR_GetEndFinalizeHook(GCEndFinalizeHook **hook, void **arg); + +/* +** Register a GC type. Return's the index into the GC internal type +** table. The returned value is passed to PR_AllocMemory. After the call, +** the "type" memory belongs to the GC (the caller must not free it or +** change it). +*/ +PR_EXTERN(PRInt32) PR_RegisterType(GCType *type); + +/* +** Register a root finder with the collector. The collector will call +** these functions to identify all of the roots before collection +** proceeds. "arg" is passed to the function when it is called. +*/ +PR_EXTERN(PRStatus) PR_RegisterRootFinder(GCRootFinder func, char *name, void *arg); + +/* +** Allocate some GC'able memory. The object must be at least bytes in +** size. The type index function for the object is specified. "flags" +** specifies some control flags. If PR_ALLOC_CLEAN is set then the memory +** is zero'd before being returned. If PR_ALLOC_DOUBLE is set then the +** allocated memory is double aligned. +** +** Any memory cell that you store a pointer to something allocated by +** this call must be findable by the GC. Use the PR_RegisterRootFinder to +** register new places where the GC will look for pointers into the heap. +** The GC already knows how to scan any NSPR threads or monitors. +*/ +PR_EXTERN(PRWord GCPTR *)PR_AllocMemory( + PRWord bytes, PRInt32 typeIndex, PRWord flags); +PR_EXTERN(PRWord GCPTR *)PR_AllocSimpleMemory( + PRWord bytes, PRInt32 typeIndex); + +/* +** This function can be used to cause PR_AllocMemory to always return +** NULL. This may be useful in low memory situations when we're trying to +** shutdown applets. +*/ +PR_EXTERN(void) PR_EnableAllocation(PRBool yesOrNo); + +/* flags bits */ +#define PR_ALLOC_CLEAN 0x1 +#define PR_ALLOC_DOUBLE 0x2 +#define PR_ALLOC_ZERO_HANDLE 0x4 /* XXX yes, it's a hack */ + +/* +** Force a garbage collection right now. Return when it completes. +*/ +PR_EXTERN(void) PR_GC(void); + +/* +** Force a finalization right now. Return when finalization has +** completed. Finalization completes when there are no more objects +** pending finalization. This does not mean there are no objects in the +** gc heap that will need finalization should a collection be done after +** this call. +*/ +PR_EXTERN(void) PR_ForceFinalize(void); + +/* +** Dump the GC heap out to the given file. This will stop the system dead +** in its tracks while it is occuring. +*/ +PR_EXTERN(void) PR_DumpGCHeap(FILE *out, PRBool detailed); + +/* +** Wrapper for PR_DumpGCHeap +*/ +PR_EXTERN(void) PR_DumpMemory(PRBool detailed); + +/* +** Dump summary of objects allocated. +*/ +PR_EXTERN(void) PR_DumpMemorySummary(void); + +/* +** Dump the application heaps. +*/ +PR_EXTERN(void) PR_DumpApplicationHeaps(void); + +/* +** Helper function used by dump routines to do the indentation in a +** consistent fashion. +*/ +PR_EXTERN(void) PR_DumpIndent(FILE *out, PRIntn indent); + +/* +** The GCInfo structure contains all of the GC state... +** +** busyMemory: +** The amount of GC heap memory that is busy at this instant. Busy +** doesn't mean alive, it just means that it has been +** allocated. Immediately after a collection busy means how much is +** alive. +** +** freeMemory: +** The amount of GC heap memory that is as yet unallocated. +** +** allocMemory: +** The sum of free and busy memory in the GC heap. +** +** maxMemory: +** The maximum size that the GC heap is allowed to grow. +** +** lowSeg: +** The lowest segment currently used in the GC heap. +** +** highSeg: +** The highest segment currently used in the GC heap. +** The lowSeg and highSeg members are used for a "quick test" of whether +** a pointer falls within the GC heap. [ see GC_IN_HEAP(...) ] +** +** lock: +** Monitor used for synchronization within the GC. +** +** finalizer: +** Thread in which the GC finalizer is running. +** +** liveBlock: +** Object scanning functions call through this function pointer to +** register a potential block of pointers with the collector. (This is +** currently not at all different than processRoot.) +** +** livePointer: +** Object scanning functions call through this function pointer to +** register a single pointer with the collector. +** +** processRootBlock: +** When a root finder identifies a root it should call through this +** function pointer so that the GC can process the root. The call takes +** a base address and count which the gc will examine for valid heap +** pointers. +** +** processRootPointer: +** When a root finder identifies a root it should call through this +** function pointer so that the GC can process the root. The call takes +** a single pointer value. +*/ +typedef struct GCInfoStr { + PRWord flags; /* trace flags (see below) */ + PRWord busyMemory; /* memory in use right now */ + PRWord freeMemory; /* memory free right now */ + PRWord allocMemory; /* sum of busy & free memory */ + PRWord maxMemory; /* max memory we are allowed to allocate */ + PRWord *lowSeg; /* lowest segment in the GC heap */ + PRWord *highSeg; /* highest segment in the GC heap */ + + PRMonitor *lock; + PRThread *finalizer; + + void (PR_CALLBACK *liveBlock)(void **base, PRInt32 count); + void (PR_CALLBACK *livePointer)(void *ptr); + void (PR_CALLBACK *processRootBlock)(void **base, PRInt32 count); + void (PR_CALLBACK *processRootPointer)(void *ptr); + FILE* dumpOutput; +#ifdef GCTIMINGHOOK + void (*gcTimingHook)(int32 gcTime); +#endif +} GCInfo; + +PR_EXTERN(GCInfo *) PR_GetGCInfo(void); +PR_EXTERN(PRBool) PR_GC_In_Heap(void GCPTR *object); + +/* +** Simple bounds check to see if a pointer is anywhere near the GC heap. +** Used to avoid calls to PR_ProcessRoot and GCInfo.livePointer by object +** scanning code. +*/ +#if !defined(XP_PC) || defined(_WIN32) +#define GC_IN_HEAP(_info, _p) (((PRWord*)(_p) >= (_info)->lowSeg) && \ + ((PRWord*)(_p) < (_info)->highSeg)) +#else +/* +** The simple bounds check, above, doesn't work in Win16, because we don't +** maintain: lowSeg == MIN(all segments) and highSeg == MAX(all segments). +** So we have to do a little better. +*/ +#define GC_IN_HEAP(_info, _p) PR_GC_In_Heap(_p) +#endif + +PR_EXTERN(PRWord) PR_GetObjectHeader(void *ptr); + +PR_EXTERN(PRWord) PR_SetObjectHeader(void *ptr, PRWord newUserBits); + +/************************************************************************/ + +/* Trace flags (passed to PR_InitGC or in environment GCLOG) */ +#define GC_TRACE 0x0001 +#define GC_ROOTS 0x0002 +#define GC_LIVE 0x0004 +#define GC_ALLOC 0x0008 +#define GC_MARK 0x0010 +#define GC_SWEEP 0x0020 +#define GC_DEBUG 0x0040 +#define GC_FINAL 0x0080 + +#if defined(DEBUG_kipp) || defined(DEBUG_warren) +#define GC_CHECK 0x0100 +#endif + +#ifdef DEBUG +#define GCTRACE(x, y) if (PR_GetGCInfo()->flags & x) GCTrace y +PR_EXTERN(void) GCTrace(char *fmt, ...); +#else +#define GCTRACE(x, y) +#endif + +PR_END_EXTERN_C + +#endif /* prgc_h___ */ diff --git a/nsprpub/lib/msgc/src/.cvsignore b/nsprpub/lib/msgc/src/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/msgc/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/msgc/src/Makefile.in b/nsprpub/lib/msgc/src/Makefile.in new file mode 100644 index 00000000000..5d5a1146264 --- /dev/null +++ b/nsprpub/lib/msgc/src/Makefile.in @@ -0,0 +1,98 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +INCLUDES = -I$(dist_includedir) -I../include + +CSRCS = prgcapi.c prmsgc.c + +ifeq ($(OS_ARCH),WINNT) +CSRCS += win32gc.c +else +ifeq ($(OS_ARCH),OS2) +CSRCS += os2gc.c +else +CSRCS += unixgc.c +endif +endif + +NSPR_VERSION = $(MOD_MAJOR_VERSION) + +EXTRA_LIBS = $(LIBNSPR) + +ifdef RESOLVE_LINK_SYMBOLS +EXTRA_LIBS += $(OS_LIBS) +endif + +ifeq ($(OS_ARCH), WINNT) +#RES=$(OBJDIR)/ds.res +#RESNAME=$(MOD_DEPTH)/pr/src/nspr.rc +#OS_LIBS = user32.lib +endif # WINNT + +LIBRARY_NAME = msgc +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_LIBS = $(TARGETS) + +include $(topsrcdir)/config/rules.mk + +# +# The Client build wants the shared libraries in $(dist_bindir), +# so we also install them there. +# + +export:: $(TARGETS) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifdef SHARED_LIBRARY + $(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_bindir) +endif +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin +endif + diff --git a/nsprpub/lib/msgc/src/macgc.c b/nsprpub/lib/msgc/src/macgc.c new file mode 100644 index 00000000000..eafc28e849a --- /dev/null +++ b/nsprpub/lib/msgc/src/macgc.c @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include "MacMemAllocator.h" + +void _MD_InitGC() {} + +void *_MD_GrowGCHeap(size_t *sizep) +{ + void *heapPtr = NULL; + size_t heapSize = *sizep; + + // In previous versions of this code we tried to allocate GC heaps from the application + // heap. In the 4.0 application, we try to keep our app heap allications to a minimum + // and instead go through our own memory allocation routines. + heapPtr = malloc(heapSize); + + if (heapPtr == NULL) { + FreeMemoryStats stats; + + memtotal(heapSize, &stats); // How much can we allcoate? + + if (stats.maxBlockSize < heapSize) + heapSize = stats.maxBlockSize; + + heapPtr = malloc(heapSize); + + if (heapPtr == NULL) // Now we're hurting + heapSize = 0; + } + + *sizep = heapSize; + return heapPtr; +} + + +void _MD_FreeGCSegment(void *base, int32 /* len */) +{ + free(base); +} diff --git a/nsprpub/lib/msgc/src/os2gc.c b/nsprpub/lib/msgc/src/os2gc.c new file mode 100644 index 00000000000..f99bb678661 --- /dev/null +++ b/nsprpub/lib/msgc/src/os2gc.c @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * GC related routines + * + */ +#include "prlog.h" + +#include + +/* Leave a bit of room for any malloc header bytes... */ +#define MAX_SEGMENT_SIZE (65536L - 4096L) + +/************************************************************************/ +/* +** Machine dependent GC Heap management routines: +** _MD_GrowGCHeap +*/ +/************************************************************************/ +void _MD_InitGC() {} + +void *_MD_GrowGCHeap(PRUint32 *sizep) +{ + void *addr; + + if ( *sizep > MAX_SEGMENT_SIZE ) + { + *sizep = MAX_SEGMENT_SIZE; + } + + addr = malloc((size_t)*sizep); + return addr; +} + + +PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) { + /* Not sure about this. Todd? */ + return PR_FALSE; +} + + +void _MD_FreeGCSegment(void *base, PRInt32 len) +{ + if (base) + { + free(base); + } +} diff --git a/nsprpub/lib/msgc/src/prgcapi.c b/nsprpub/lib/msgc/src/prgcapi.c new file mode 100644 index 00000000000..23f7ea5143b --- /dev/null +++ b/nsprpub/lib/msgc/src/prgcapi.c @@ -0,0 +1,351 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include "prenv.h" +#include "prmem.h" +#include "prmon.h" +#include "prlog.h" +#include "prthread.h" +#if defined(XP_MAC) +#include "pprthred.h" +#else +#include "private/pprthred.h" +#endif +#include "gcint.h" + +/* +** Generic GC implementation independent code for the NSPR GC +*/ + +RootFinder *_pr_rootFinders; + +CollectorType *_pr_collectorTypes; + +/* GC State information */ +GCInfo _pr_gcData; + +GCBeginGCHook *_pr_beginGCHook; +void *_pr_beginGCHookArg; +GCBeginGCHook *_pr_endGCHook; +void *_pr_endGCHookArg; + +GCBeginFinalizeHook *_pr_beginFinalizeHook; +void *_pr_beginFinalizeHookArg; +GCBeginFinalizeHook *_pr_endFinalizeHook; +void *_pr_endFinalizeHookArg; + +FILE *_pr_dump_file; +int _pr_do_a_dump; +GCLockHook *_pr_GCLockHook; + +extern PRLogModuleInfo *_pr_msgc_lm; + +/************************************************************************/ + +static PRStatus PR_CALLBACK +pr_ScanOneThread(PRThread* t, void** addr, PRUword count, void* closure) +{ +#if defined(XP_MAC) +#pragma unused (t, closure) +#endif + + _pr_gcData.processRootBlock(addr, count); + return PR_SUCCESS; +} + +/* +** Scan all of the threads C stack's and registers, looking for "root" +** pointers into the GC heap. These are the objects that the GC cannot +** move and are considered "live" by the GC. Caller has stopped all of +** the threads from running. +*/ +static void PR_CALLBACK ScanThreads(void *arg) +{ + PR_ScanStackPointers(pr_ScanOneThread, arg); +} + +/************************************************************************/ + +PR_IMPLEMENT(GCInfo *) PR_GetGCInfo(void) +{ + return &_pr_gcData; +} + + +PR_IMPLEMENT(PRInt32) PR_RegisterType(GCType *t) +{ + CollectorType *ct, *ect; + int rv = -1; + + LOCK_GC(); + ct = &_pr_collectorTypes[0]; + ect = &_pr_collectorTypes[FREE_MEMORY_TYPEIX]; + for (; ct < ect; ct++) { + if (ct->flags == 0) { + ct->gctype = *t; + ct->flags = _GC_TYPE_BUSY; + if (0 != ct->gctype.finalize) { + ct->flags |= _GC_TYPE_FINAL; + } + if (0 != ct->gctype.getWeakLinkOffset) { + ct->flags |= _GC_TYPE_WEAK; + } + rv = ct - &_pr_collectorTypes[0]; + break; + } + } + UNLOCK_GC(); + return rv; +} + +PR_IMPLEMENT(PRStatus) PR_RegisterRootFinder( + GCRootFinder f, char *name, void *arg) +{ + RootFinder *rf = PR_NEWZAP(RootFinder); + if (rf) { + rf->func = f; + rf->name = name; + rf->arg = arg; + + LOCK_GC(); + rf->next = _pr_rootFinders; + _pr_rootFinders = rf; + UNLOCK_GC(); + return PR_SUCCESS; + } + return PR_FAILURE; +} + + +PR_IMPLEMENT(int) PR_RegisterGCLockHook(GCLockHookFunc* f, void *arg) +{ + + GCLockHook *rf = 0; + + rf = (GCLockHook*) calloc(1, sizeof(GCLockHook)); + if (rf) { + rf->func = f; + rf->arg = arg; + + LOCK_GC(); + /* first dummy node */ + if (! _pr_GCLockHook) { + _pr_GCLockHook = (GCLockHook*) calloc(1, sizeof(GCLockHook)); + _pr_GCLockHook->next = _pr_GCLockHook; + _pr_GCLockHook->prev = _pr_GCLockHook; + } + + rf->next = _pr_GCLockHook; + rf->prev = _pr_GCLockHook->prev; + _pr_GCLockHook->prev->next = rf; + _pr_GCLockHook->prev = rf; + UNLOCK_GC(); + return 0; + } + return -1; +} + +/* +PR_IMPLEMENT(void) PR_SetGCLockHook(GCLockHook *hook, void *arg) +{ + LOCK_GC(); + _pr_GCLockHook = hook; + _pr_GCLockHookArg2 = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetGCLockHook(GCLockHook **hook, void **arg) +{ + LOCK_GC(); + *hook = _pr_GCLockHook; + *arg = _pr_GCLockHookArg2; + UNLOCK_GC(); +} +*/ + + +PR_IMPLEMENT(void) PR_SetBeginGCHook(GCBeginGCHook *hook, void *arg) +{ + LOCK_GC(); + _pr_beginGCHook = hook; + _pr_beginGCHookArg = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetBeginGCHook(GCBeginGCHook **hook, void **arg) +{ + LOCK_GC(); + *hook = _pr_beginGCHook; + *arg = _pr_beginGCHookArg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_SetEndGCHook(GCEndGCHook *hook, void *arg) +{ + LOCK_GC(); + _pr_endGCHook = hook; + _pr_endGCHookArg = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetEndGCHook(GCEndGCHook **hook, void **arg) +{ + LOCK_GC(); + *hook = _pr_endGCHook; + *arg = _pr_endGCHookArg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_SetBeginFinalizeHook(GCBeginFinalizeHook *hook, void *arg) +{ + LOCK_GC(); + _pr_beginFinalizeHook = hook; + _pr_beginFinalizeHookArg = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetBeginFinalizeHook(GCBeginFinalizeHook **hook, + void **arg) +{ + LOCK_GC(); + *hook = _pr_beginFinalizeHook; + *arg = _pr_beginFinalizeHookArg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_SetEndFinalizeHook(GCEndFinalizeHook *hook, void *arg) +{ + LOCK_GC(); + _pr_endFinalizeHook = hook; + _pr_endFinalizeHookArg = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetEndFinalizeHook(GCEndFinalizeHook **hook, void **arg) +{ + LOCK_GC(); + *hook = _pr_endFinalizeHook; + *arg = _pr_endFinalizeHookArg; + UNLOCK_GC(); +} + +#ifdef DEBUG +#include "prprf.h" + +#if defined(WIN16) +static FILE *tracefile = 0; +#endif + +PR_IMPLEMENT(void) GCTrace(char *fmt, ...) +{ + va_list ap; + char buf[400]; + + va_start(ap, fmt); + PR_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); +#if defined(WIN16) + if ( tracefile == 0 ) + { + tracefile = fopen( "xxxGCtr", "w" ); + } + fprintf(tracefile, "%s\n", buf ); + fflush(tracefile); +#else + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("%s", buf)); +#endif +} +#endif + +void _PR_InitGC(PRWord flags) +{ + static char firstTime = 1; + + if (!firstTime) return; + firstTime = 0; + + _MD_InitGC(); + + if (flags == 0) { + char *ev = PR_GetEnv("GCLOG"); + if (ev && ev[0]) { + flags = atoi(ev); + } + } + _pr_gcData.flags = flags; + + _pr_gcData.lock = PR_NewMonitor(); + + _pr_collectorTypes = (CollectorType*) PR_CALLOC(256 * sizeof(CollectorType)); + + PR_RegisterRootFinder(ScanThreads, "scan threads", 0); + PR_RegisterRootFinder(_PR_ScanFinalQueue, "scan final queue", 0); +} + +extern void pr_FinalizeOnExit(void); + +#ifdef DEBUG +#ifdef GC_STATS +PR_PUBLIC_API(void) PR_PrintGCAllocStats(void); +#endif +#endif + +PR_IMPLEMENT(void) +PR_ShutdownGC(PRBool finalizeOnExit) +{ + /* first finalize all the objects in the heap */ + if (finalizeOnExit) { + pr_FinalizeOnExit(); + } + +#ifdef DEBUG +#ifdef GC_STATS + PR_PrintGCAllocStats(); +#endif /* GC_STATS */ +#endif /* DEBUG */ + + /* then the chance for any future allocations */ + + /* finally delete the gc heap */ + + /* write me */ +} + +/******************************************************************************/ diff --git a/nsprpub/lib/msgc/src/prmsgc.c b/nsprpub/lib/msgc/src/prmsgc.c new file mode 100644 index 00000000000..a6fc897ac36 --- /dev/null +++ b/nsprpub/lib/msgc/src/prmsgc.c @@ -0,0 +1,3514 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#include +#endif + +#include "prclist.h" +#include "prbit.h" + +#include "prtypes.h" +#include "prenv.h" +#include "prgc.h" +#include "prthread.h" +#include "prlog.h" +#include "prlong.h" +#include "prinrval.h" +#include "prprf.h" +#include "gcint.h" + +#if defined(XP_MAC) +#include "pprthred.h" +#else +#include "private/pprthred.h" +#endif + +typedef void (*PRFileDumper)(FILE *out, PRBool detailed); + +PR_EXTERN(void) +PR_DumpToFile(char* filename, char* msg, PRFileDumper dump, PRBool detailed); + +/* +** Mark&sweep garbage collector. Supports objects that require +** finalization, objects that can have a single weak link, and special +** objects that require care during sweeping. +*/ + +PRLogModuleInfo *_pr_msgc_lm; +PRLogModuleInfo* GC; + +static PRInt32 _pr_pageShift; +static PRInt32 _pr_pageSize; + +#ifdef DEBUG +#define GCMETER +#endif +#ifdef DEBUG_jwz +# undef GCMETER +#endif /* 1 */ + +#ifdef GCMETER +#define METER(x) x +#else +#define METER(x) +#endif + +/* +** Make this constant bigger to reduce the amount of recursion during +** garbage collection. +*/ +#define MAX_SCAN_Q 100L + +#if defined(XP_PC) && !defined(WIN32) +#define MAX_SEGS 400L +#define MAX_SEGMENT_SIZE (65536L - 4096L) +#define SEGMENT_SIZE (65536L - 4096L) +#define MAX_ALLOC_SIZE (65536L - 4096L) +#else +#define MAX_SEGS 400L +#define MAX_SEGMENT_SIZE (2L * 256L * 1024L) +#define SEGMENT_SIZE (1L * 256L * 1024L) +#define MAX_ALLOC_SIZE (4L * 1024L * 1024L) +#endif + +/* + * The highest value that can fit into a signed integer. This + * is used to prevent overflow of allocation size in alloc routines. + */ + +#define MAX_INT ((1UL << (PR_BITS_PER_INT - 1)) - 1) + +/* + * On 32-bit machines, only 22 bits are used in the cibx integer to + * store size since 8 bits of the integer are used to store type, and + * of the remainder, 2 are user defined. Max allocation size = 2^22 -1 + */ + +#define MAX_ALLOC ( (1L << (PR_BYTES_PER_WORD_LOG2 + WORDS_BITS )) -1) + +/* The minimum percentage of free heap space after a collection. If + the amount of free space doesn't meet this criteria then we will + attempt to grow the heap */ +#ifdef XP_MAC +#define MIN_FREE_THRESHOLD_AFTER_GC 10L +#else +#define MIN_FREE_THRESHOLD_AFTER_GC 20L +#endif + +static PRInt32 segmentSize = SEGMENT_SIZE; + +static PRInt32 collectorCleanupNeeded; + +#ifdef GCMETER +PRUint32 _pr_gcMeter; + +#define _GC_METER_STATS 0x01L +#define _GC_METER_GROWTH 0x02L +#define _GC_METER_FREE_LIST 0x04L +#endif + +/************************************************************************/ + +#define LINEAR_BIN_EXPONENT 5 +#define NUM_LINEAR_BINS ((PRUint32)1 << LINEAR_BIN_EXPONENT) +#define FIRST_LOG_BIN (NUM_LINEAR_BINS - LINEAR_BIN_EXPONENT) + +/* Each free list bin holds a chunk of memory sized from + 2^n to (2^(n+1))-1 inclusive. */ +#define NUM_BINS (FIRST_LOG_BIN + 32) + +/* + * Find the bin number for a given size (in bytes). This does not round up as + * values from 2^n to (2^(n+1))-1 share the same bin. + */ +#define InlineBinNumber(_bin,_bytes) \ +{ \ + PRUint32 _t, _n = (PRUint32) _bytes / 4; \ + if (_n < NUM_LINEAR_BINS) { \ + _bin = _n; \ + } else { \ + _bin = FIRST_LOG_BIN; \ + if ((_t = (_n >> 16)) != 0) { _bin += 16; _n = _t; } \ + if ((_t = (_n >> 8)) != 0) { _bin += 8; _n = _t; } \ + if ((_t = (_n >> 4)) != 0) { _bin += 4; _n = _t; } \ + if ((_t = (_n >> 2)) != 0) { _bin += 2; _n = _t; } \ + if ((_n >> 1) != 0) _bin++; \ + } \ +} + +#define BIG_ALLOC 16384L + +#define MIN_FREE_CHUNK_BYTES ((PRInt32)sizeof(GCFreeChunk)) + +/* Note: fix code in PR_AllocMemory if you change the size of GCFreeChunk + so that it zeros the right number of words */ +typedef struct GCFreeChunk { + struct GCFreeChunk *next; + struct GCSeg *segment; + PRInt32 chunkSize; +} GCFreeChunk; + +typedef struct GCSegInfo { + struct GCSegInfo *next; + char *base; + char *limit; + PRWord *hbits; + int fromMalloc; +} GCSegInfo; + +typedef struct GCSeg { + char *base; + char *limit; + PRWord *hbits; + GCSegInfo *info; +} GCSeg; + +#ifdef GCMETER +typedef struct GCMeter { + PRInt32 allocBytes; + PRInt32 wastedBytes; + PRInt32 numFreeChunks; + PRInt32 skippedFreeChunks; +} GCMeter; +static GCMeter meter; +#endif + +/* +** There is one of these for each segment of GC'able memory. +*/ +static GCSeg segs[MAX_SEGS]; +static GCSegInfo *freeSegs; +static GCSeg* lastInHeap; +static int nsegs; + +static GCFreeChunk *bins[NUM_BINS]; +static PRInt32 minBin; +static PRInt32 maxBin; + +/* +** Scan Q used to avoid deep recursion when scanning live objects for +** heap pointers +*/ +typedef struct GCScanQStr { + PRWord *q[MAX_SCAN_Q]; + int queued; +} GCScanQ; + +static GCScanQ *pScanQ; + +#ifdef GCMETER +PRInt32 _pr_maxScanDepth; +PRInt32 _pr_scanDepth; +#endif + +/* +** Keeps track of the number of bytes allocated via the BigAlloc() +** allocator. When the number of bytes allocated, exceeds the +** BIG_ALLOC_GC_SIZE, then a GC will occur before the next allocation +** is done... +*/ +#define BIG_ALLOC_GC_SIZE (4*SEGMENT_SIZE) +static PRWord bigAllocBytes = 0; + +/* +** There is one GC header word in front of each GC allocated object. We +** use it to contain information about the object (what TYPEIX to use for +** scanning it, how big it is, it's mark status, and if it's a root). +*/ +#define TYPEIX_BITS 8L +#define WORDS_BITS 20L +#define MAX_CBS (1L << GC_TYPEIX_BITS) +#define MAX_WORDS (1L << GC_WORDS_BITS) +#define TYPEIX_SHIFT 24L +#define MAX_TYPEIX ((1L << TYPEIX_BITS) - 1L) +#define TYPEIX_MASK PR_BITMASK(TYPEIX_BITS) +#define WORDS_SHIFT 2L +#define WORDS_MASK PR_BITMASK(WORDS_BITS) +#define MARK_BIT 1L +#define FINAL_BIT 2L + +/* Two bits per object header are reserved for the user of the memory + system to store information into. */ +#define GC_USER_BITS_SHIFT 22L +#define GC_USER_BITS 0x00c00000L + +#define MAKE_HEADER(_cbix,_words) \ + ((PRWord) (((unsigned long)(_cbix) << TYPEIX_SHIFT) \ + | ((unsigned long)(_words) << WORDS_SHIFT))) + +#define GET_TYPEIX(_h) \ + (((PRUword)(_h) >> TYPEIX_SHIFT) & 0xff) + +#define MARK(_sp,_p) \ + (((PRWord *)(_p))[0] |= MARK_BIT) +#define IS_MARKED(_sp,_p) \ + (((PRWord *)(_p))[0] & MARK_BIT) +#define OBJ_BYTES(_h) \ + (((PRInt32) (_h) & 0x003ffffcL) << (PR_BYTES_PER_WORD_LOG2-2L)) + +#define GC_GET_USER_BITS(_h) (((_h) & GC_USER_BITS) >> GC_USER_BITS_SHIFT) + +/************************************************************************/ + +/* +** Mark the start of an object in a segment. Note that we mark the header +** word (which we always have), not the data word (which we may not have +** for empty objects). +** XXX tune: put subtract of _sp->base into _sp->hbits pointer? +*/ +#if !defined(WIN16) +#define SET_HBIT(_sp,_ph) \ + SET_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base))) + +#define CLEAR_HBIT(_sp,_ph) \ + CLEAR_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base))) + +#define IS_HBIT(_sp,_ph) \ + TEST_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base))) +#else + +#define SET_HBIT(_sp,_ph) set_hbit(_sp,_ph) + +#define CLEAR_HBIT(_sp,_ph) clear_hbit(_sp,_ph) + +#define IS_HBIT(_sp,_ph) is_hbit(_sp,_ph) + +static void +set_hbit(GCSeg *sp, PRWord *p) +{ + unsigned int distance; + unsigned int index; + PRWord mask; + + PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) ); + PR_ASSERT( OFFSETOF(p) >= OFFSETOF(sp->base) ); + + distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2; + index = distance >> PR_BITS_PER_WORD_LOG2; + mask = 1L << (distance&(PR_BITS_PER_WORD-1)); + + sp->hbits[index] |= mask; +} + +static void +clear_hbit(GCSeg *sp, PRWord *p) +{ + unsigned int distance; + unsigned int index; + PRWord mask; + + PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) ); + PR_ASSERT( OFFSETOF(p) >= OFFSETOF(sp->base) ); + + distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2; + index = distance >> PR_BITS_PER_WORD_LOG2; + mask = 1L << (distance&(PR_BITS_PER_WORD-1)); + + sp->hbits[index] &= ~mask; +} + +static int +is_hbit(GCSeg *sp, PRWord *p) +{ + unsigned int distance; + unsigned int index; + PRWord mask; + + PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) ); + PR_ASSERT( OFFSETOF(p) >= OFFSETOF(sp->base) ); + + distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2; + index = distance >> PR_BITS_PER_WORD_LOG2; + mask = 1L << (distance&(PR_BITS_PER_WORD-1)); + + return ((sp->hbits[index] & mask) != 0); +} + + +#endif /* WIN16 */ + +/* +** Given a pointer into this segment, back it up until we are at the +** start of the object the pointer points into. Each heap segment has a +** bitmap that has one bit for each word of the objects it contains. The +** bit's are set for the firstword of an object, and clear for it's other +** words. +*/ +static PRWord *FindObject(GCSeg *sp, PRWord *p) +{ + PRWord *base; + + /* Align p to it's proper boundary before we start fiddling with it */ + p = (PRWord*) ((PRWord)p & ~(PR_BYTES_PER_WORD-1L)); + + base = (PRWord *) sp->base; +#if defined(WIN16) + PR_ASSERT( SELECTOROF(p) == SELECTOROF(base)); +#endif + do { + if (IS_HBIT(sp, p)) { + return (p); + } + p--; + } while ( p >= base ); + + /* Heap is corrupted! */ + _GCTRACE(GC_TRACE, ("ERROR: The heap is corrupted!!! aborting now!")); + abort(); + return NULL; +} + +/************************************************************************/ +#if !defined(XP_PC) || defined(XP_OS2) +#define OutputDebugString(msg) +#endif + +#if !defined(WIN16) +#define IN_SEGMENT(_sp, _p) \ + ((((char *)(_p)) >= (_sp)->base) && \ + (((char *)(_p)) < (_sp)->limit)) +#else +#define IN_SEGMENT(_sp, _p) \ + ((((PRWord)(_p)) >= ((PRWord)(_sp)->base)) && \ + (((PRWord)(_p)) < ((PRWord)(_sp)->limit))) +#endif + +static GCSeg *InHeap(void *p) +{ + GCSeg *sp, *esp; + + if (lastInHeap && IN_SEGMENT(lastInHeap, p)) { + return lastInHeap; + } + + sp = segs; + esp = segs + nsegs; + for (; sp < esp; sp++) { + if (IN_SEGMENT(sp, p)) { + lastInHeap = sp; + return sp; + } + } + return 0; +} + +/* +** Grow the heap by allocating another segment. Fudge the requestedSize +** value to try to pre-account for the HBITS. +*/ +static GCSeg* DoGrowHeap(PRInt32 requestedSize, PRBool exactly) +{ + GCSeg *sp; + GCSegInfo *segInfo; + GCFreeChunk *cp; + char *base; + PRWord *hbits; + PRInt32 nhbytes, nhbits; + PRUint32 allocSize; + + if (nsegs == MAX_SEGS) { + /* No room for more segments */ + return 0; + } + + segInfo = (GCSegInfo*) PR_MALLOC(sizeof(GCSegInfo)); +#ifdef DEBUG + { + char str[256]; + sprintf(str, "[1] Allocated %ld bytes at %p\n", + (long) sizeof(GCSegInfo), segInfo); + OutputDebugString(str); + } +#endif + if (!segInfo) { + return 0; + } + +#if defined(WIN16) + if (requestedSize > segmentSize) { + PR_DELETE(segInfo); + return 0; + } +#endif + + /* Get more memory from the OS */ + if (exactly) { + allocSize = requestedSize; + base = (char *) PR_MALLOC(requestedSize); + } else { + allocSize = requestedSize; + allocSize = (allocSize + _pr_pageSize - 1L) >> _pr_pageShift; + allocSize <<= _pr_pageShift; + base = (char*)_MD_GrowGCHeap(&allocSize); + } + if (!base) { + PR_DELETE(segInfo); + return 0; + } + + nhbits = (PRInt32)( + (allocSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2); + nhbytes = ((nhbits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) + * sizeof(PRWord); + + /* Get bitmap memory from malloc heap */ +#if defined(WIN16) + PR_ASSERT( nhbytes < MAX_ALLOC_SIZE ); +#endif + hbits = (PRWord *) PR_CALLOC((PRUint32)nhbytes); + if (!hbits) { + /* Loser! */ + PR_DELETE(segInfo); + if (exactly) { + PR_DELETE(base); + } else { + /* XXX do something about this */ + /* _MD_FreeGCSegment(base, allocSize); */ + } + return 0; + } + + /* + ** Setup new segment. + */ + sp = &segs[nsegs++]; + segInfo->base = sp->base = base; + segInfo->limit = sp->limit = base + allocSize; + segInfo->hbits = sp->hbits = hbits; + sp->info = segInfo; + segInfo->fromMalloc = exactly; + memset(base, 0, allocSize); + +#ifdef GCMETER + if (_pr_gcMeter & _GC_METER_GROWTH) { + fprintf(stderr, "[GC: new segment base=%p size=%ld]\n", + sp->base, (long) allocSize); + } +#endif + + _pr_gcData.allocMemory += allocSize; + _pr_gcData.freeMemory += allocSize; + + if (!exactly) { + PRInt32 bin; + + /* Put free memory into a freelist bin */ + cp = (GCFreeChunk *) base; + cp->segment = sp; + cp->chunkSize = allocSize; + InlineBinNumber(bin, allocSize) + cp->next = bins[bin]; + bins[bin] = cp; + if (bin < minBin) minBin = bin; + if (bin > maxBin) maxBin = bin; + } else { + /* + ** When exactly allocating the entire segment is given over to a + ** single object to prevent fragmentation + */ + } + + if (!_pr_gcData.lowSeg) { + _pr_gcData.lowSeg = (PRWord*) sp->base; + _pr_gcData.highSeg = (PRWord*) sp->limit; + } else { + if ((PRWord*)sp->base < _pr_gcData.lowSeg) { + _pr_gcData.lowSeg = (PRWord*) sp->base; + } + if ((PRWord*)sp->limit > _pr_gcData.highSeg) { + _pr_gcData.highSeg = (PRWord*) sp->limit; + } + } + + /* + ** Get rid of the GC pointer in case it shows up in some uninitialized + ** local stack variable later (while scanning the C stack looking for + ** roots). + */ + memset(&base, 0, sizeof(base)); /* optimizers beware */ + + PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, ("grow heap: total gc memory now %d", + _pr_gcData.allocMemory)); + + return sp; +} + +#ifdef USE_EXTEND_HEAP +static PRBool ExtendHeap(PRInt32 requestedSize) { + GCSeg* sp; + PRUint32 allocSize; + PRInt32 oldSize, newSize; + PRInt32 newHBits, newHBytes; + PRInt32 oldHBits, oldHBytes; + PRWord* hbits; + GCFreeChunk* cp; + PRInt32 bin; + + /* Can't extend nothing */ + if (nsegs == 0) return PR_FALSE; + + /* Round up requested size to the size of a page */ + allocSize = (PRUint32) requestedSize; + allocSize = (allocSize + _pr_pageSize - 1L) >> _pr_pageShift; + allocSize <<= _pr_pageShift; + + /* Malloc some memory for the new hbits array */ + sp = segs; + oldSize = sp->limit - sp->base; + newSize = oldSize + allocSize; + newHBits = (newSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2; + newHBytes = ((newHBits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) + * sizeof(PRWord); + hbits = (PRWord*) PR_MALLOC(newHBytes); + if (0 == hbits) return PR_FALSE; + + /* Attempt to extend the last segment by the desired amount */ + if (_MD_ExtendGCHeap(sp->base, oldSize, newSize)) { + oldHBits = (oldSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2; + oldHBytes = ((oldHBits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) + * sizeof(PRWord); + + /* Copy hbits from old memory into new memory */ + memset(hbits, 0, newHBytes); + memcpy(hbits, sp->hbits, oldHBytes); + PR_DELETE(sp->hbits); + memset(sp->base + oldSize, 0, allocSize); + + /* Adjust segment state */ + sp->limit += allocSize; + sp->hbits = hbits; + sp->info->limit = sp->limit; + sp->info->hbits = hbits; + + /* Put free memory into a freelist bin */ + cp = (GCFreeChunk *) (sp->base + oldSize); + cp->segment = sp; + cp->chunkSize = allocSize; + InlineBinNumber(bin, allocSize) + cp->next = bins[bin]; + bins[bin] = cp; + if (bin < minBin) minBin = bin; + if (bin > maxBin) maxBin = bin; + + /* Prevent a pointer that points to the free memory from showing + up on the call stack later on */ + memset(&cp, 0, sizeof(cp)); + + /* Update heap brackets and counters */ + if ((PRWord*)sp->limit > _pr_gcData.highSeg) { + _pr_gcData.highSeg = (PRWord*) sp->limit; + } + _pr_gcData.allocMemory += allocSize; + _pr_gcData.freeMemory += allocSize; + + return PR_TRUE; + } + PR_DELETE(hbits); + return PR_FALSE; +} +#endif /* USE_EXTEND_HEAP */ + +static GCSeg *GrowHeapExactly(PRInt32 requestedSize) +{ + GCSeg *sp = DoGrowHeap(requestedSize, PR_TRUE); + return sp; +} + +static PRBool GrowHeap(PRInt32 requestedSize) +{ + void *p; +#ifdef USE_EXTEND_HEAP + if (ExtendHeap(requestedSize)) { + return PR_TRUE; + } +#endif + p = DoGrowHeap(requestedSize, PR_FALSE); + return (p != NULL ? PR_TRUE : PR_FALSE); +} + +/* +** Release a segment when it is entirely free. +*/ +static void ShrinkGCHeap(GCSeg *sp) +{ +#ifdef GCMETER + if (_pr_gcMeter & _GC_METER_GROWTH) { + fprintf(stderr, "[GC: free segment base=%p size=%ld]\n", + sp->base, (long) (sp->limit - sp->base)); + } +#endif + + /* + * Put segment onto free seginfo list (we can't call free right now + * because we have the GC lock and all of the other threads are + * suspended; if one of them has the malloc lock we would deadlock) + */ + sp->info->next = freeSegs; + freeSegs = sp->info; + collectorCleanupNeeded = 1; + _pr_gcData.allocMemory -= sp->limit - sp->base; + if (sp == lastInHeap) lastInHeap = 0; + + /* Squish out disappearing segment from segment table */ + --nsegs; + if ((sp - segs) != nsegs) { + *sp = segs[nsegs]; + } else { + sp->base = 0; + sp->limit = 0; + sp->hbits = 0; + sp->info = 0; + } + + /* Recalculate the lowSeg and highSeg values */ + _pr_gcData.lowSeg = (PRWord*) segs[0].base; + _pr_gcData.highSeg = (PRWord*) segs[0].limit; + for (sp = segs; sp < &segs[nsegs]; sp++) { + if ((PRWord*)sp->base < _pr_gcData.lowSeg) { + _pr_gcData.lowSeg = (PRWord*) sp->base; + } + if ((PRWord*)sp->limit > _pr_gcData.highSeg) { + _pr_gcData.highSeg = (PRWord*) sp->limit; + } + } +} + +static void FreeSegments(void) +{ + GCSegInfo *si; + + while (0 != freeSegs) { + LOCK_GC(); + si = freeSegs; + if (si) { + freeSegs = si->next; + } + UNLOCK_GC(); + + if (!si) { + break; + } + PR_DELETE(si->base); + PR_DELETE(si->hbits); + PR_DELETE(si); + } +} + +/************************************************************************/ + +void ScanScanQ(GCScanQ *iscan) +{ + PRWord *p; + PRWord **pp; + PRWord **epp; + GCScanQ nextQ, *scan, *next, *temp; + CollectorType *ct; + + if (!iscan->queued) return; + + _GCTRACE(GC_MARK, ("begin scanQ @ 0x%x (%d)", iscan, iscan->queued)); + scan = iscan; + next = &nextQ; + while (scan->queued) { + _GCTRACE(GC_MARK, ("continue scanQ @ 0x%x (%d)", scan, scan->queued)); + /* + * Set pointer to current scanQ so that _pr_gcData.livePointer + * can find it. + */ + pScanQ = next; + next->queued = 0; + + /* Now scan the scan Q */ + pp = scan->q; + epp = &scan->q[scan->queued]; + scan->queued = 0; + while (pp < epp) { + p = *pp++; + ct = &_pr_collectorTypes[GET_TYPEIX(p[0])]; + PR_ASSERT(0 != ct->gctype.scan); + /* Scan object ... */ + (*ct->gctype.scan)(p + 1); + } + + /* Exchange pointers so that we scan next */ + temp = scan; + scan = next; + next = temp; + } + + pScanQ = iscan; + PR_ASSERT(nextQ.queued == 0); + PR_ASSERT(iscan->queued == 0); +} + +/* +** Called during root finding step to identify "root" pointers into the +** GC heap. First validate if it is a real heap pointer and then mark the +** object being pointed to and add it to the scan Q for eventual +** scanning. +*/ +static void PR_CALLBACK ProcessRootBlock(void **base, PRInt32 count) +{ + GCSeg *sp; + PRWord *p0, *p, h, tix, *low, *high, *segBase; + CollectorType *ct; +#ifdef DEBUG + void **base0 = base; +#endif + + low = _pr_gcData.lowSeg; + high = _pr_gcData.highSeg; + while (--count >= 0) { + p0 = (PRWord*) *base++; + /* + ** XXX: + ** Until Win16 maintains lowSeg and highSeg correctly, + ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs)) + ** Allways scan through the segment list + */ +#if !defined(WIN16) + if (p0 < low) continue; /* below gc heap */ + if (p0 >= high) continue; /* above gc heap */ +#endif + /* NOTE: inline expansion of InHeap */ + /* Find segment */ + sp = lastInHeap; + if (!sp || !IN_SEGMENT(sp,p0)) { + GCSeg *esp; + sp = segs; + esp = segs + nsegs; + for (; sp < esp; sp++) { + if (IN_SEGMENT(sp, p0)) { + lastInHeap = sp; + goto find_object; + } + } + continue; + } + + find_object: + /* NOTE: Inline expansion of FindObject */ + /* Align p to it's proper boundary before we start fiddling with it */ + p = (PRWord*) ((PRWord)p0 & ~(PR_BYTES_PER_WORD-1L)); + segBase = (PRWord *) sp->base; + do { + if (IS_HBIT(sp, p)) { + goto winner; + } + p--; + } while (p >= segBase); + + /* + ** We have a pointer into the heap, but it has no header + ** bit. This means that somehow the very first object in the heap + ** doesn't have a header. This is impossible so when debugging + ** lets abort. + */ +#ifdef DEBUG + PR_Abort(); +#endif + + winner: + h = p[0]; + if ((h & MARK_BIT) == 0) { +#ifdef DEBUG + _GCTRACE(GC_ROOTS, + ("root 0x%p (%d) base0=%p off=%d", + p, OBJ_BYTES(h), base0, (base-1) - base0)); +#endif + + /* Mark the root we just found */ + p[0] = h | MARK_BIT; + + /* + * See if object we just found needs scanning. It must + * have a scan function to be placed on the scanQ. + */ + tix = (PRWord)GET_TYPEIX(h); + ct = &_pr_collectorTypes[tix]; + if (0 == ct->gctype.scan) { + continue; + } + + /* + ** Put a pointer onto the scan Q. We use the scan Q to avoid + ** deep recursion on the C call stack. Objects are added to + ** the scan Q until the scan Q fills up. At that point we + ** make a call to ScanScanQ which proceeds to scan each of + ** the objects in the Q. This limits the recursion level by a + ** large amount though the stack frames get larger to hold + ** the GCScanQ's. + */ + pScanQ->q[pScanQ->queued++] = p; + if (pScanQ->queued == MAX_SCAN_Q) { + METER(_pr_scanDepth++); + ScanScanQ(pScanQ); + } + } + } +} + +static void PR_CALLBACK ProcessRootPointer(void *ptr) +{ + PRWord *p0, *p, h, tix, *segBase; + GCSeg* sp; + CollectorType *ct; + + p0 = (PRWord*) ptr; + + /* + ** XXX: + ** Until Win16 maintains lowSeg and highSeg correctly, + ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs)) + ** Allways scan through the segment list + */ +#if !defined(WIN16) + if (p0 < _pr_gcData.lowSeg) return; /* below gc heap */ + if (p0 >= _pr_gcData.highSeg) return; /* above gc heap */ +#endif + + /* NOTE: inline expansion of InHeap */ + /* Find segment */ + sp = lastInHeap; + if (!sp || !IN_SEGMENT(sp,p0)) { + GCSeg *esp; + sp = segs; + esp = segs + nsegs; + for (; sp < esp; sp++) { + if (IN_SEGMENT(sp, p0)) { + lastInHeap = sp; + goto find_object; + } + } + return; + } + + find_object: + /* NOTE: Inline expansion of FindObject */ + /* Align p to it's proper boundary before we start fiddling with it */ + p = (PRWord*) ((PRWord)p0 & ~(BYTES_PER_WORD-1L)); + segBase = (PRWord *) sp->base; + do { + if (IS_HBIT(sp, p)) { + goto winner; + } + p--; + } while (p >= segBase); + + /* + ** We have a pointer into the heap, but it has no header + ** bit. This means that somehow the very first object in the heap + ** doesn't have a header. This is impossible so when debugging + ** lets abort. + */ +#ifdef DEBUG + PR_Abort(); +#endif + + winner: + h = p[0]; + if ((h & MARK_BIT) == 0) { +#ifdef DEBUG + _GCTRACE(GC_ROOTS, ("root 0x%p (%d)", p, OBJ_BYTES(h))); +#endif + + /* Mark the root we just found */ + p[0] = h | MARK_BIT; + + /* + * See if object we just found needs scanning. It must + * have a scan function to be placed on the scanQ. + */ + tix = (PRWord)GET_TYPEIX(h); + ct = &_pr_collectorTypes[tix]; + if (0 == ct->gctype.scan) { + return; + } + + /* + ** Put a pointer onto the scan Q. We use the scan Q to avoid + ** deep recursion on the C call stack. Objects are added to + ** the scan Q until the scan Q fills up. At that point we + ** make a call to ScanScanQ which proceeds to scan each of + ** the objects in the Q. This limits the recursion level by a + ** large amount though the stack frames get larger to hold + ** the GCScanQ's. + */ + pScanQ->q[pScanQ->queued++] = p; + if (pScanQ->queued == MAX_SCAN_Q) { + METER(_pr_scanDepth++); + ScanScanQ(pScanQ); + } + } +} + +/************************************************************************/ + +/* +** Empty the freelist for each segment. This is done to make sure that +** the root finding step works properly (otherwise, if we had a pointer +** into a free section, we might not find its header word and abort in +** FindObject) +*/ +static void EmptyFreelists(void) +{ + GCFreeChunk *cp; + GCFreeChunk *next; + GCSeg *sp; + PRWord *p; + PRInt32 chunkSize; + PRInt32 bin; + + /* + ** Run over the freelist and make all of the free chunks look like + ** object debris. + */ + for (bin = 0; bin <= NUM_BINS-1; bin++) { + cp = bins[bin]; + while (cp) { + next = cp->next; + sp = cp->segment; + chunkSize = cp->chunkSize >> BYTES_PER_WORD_LOG2; + p = (PRWord*) cp; + PR_ASSERT(chunkSize != 0); + p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, chunkSize); + SET_HBIT(sp, p); + cp = next; + } + bins[bin] = 0; + } + minBin = NUM_BINS - 1; + maxBin = 0; +} + +typedef struct GCBlockEnd { + PRInt32 check; +#ifdef GC_CHECK + PRInt32 requestedBytes; +#endif +#ifdef GC_STATS + PRInt32 bin; + PRInt64 allocTime; +#endif +#ifdef GC_TRACEROOTS + PRInt32 traceGeneration; +#endif +} GCBlockEnd; + +#define PR_BLOCK_END 0xDEADBEEF + +/************************************************************************/ + +#ifdef GC_STATS + +typedef struct GCStat { + PRInt32 nallocs; + double allocTime; + double allocTimeVariance; + PRInt32 nfrees; + double lifetime; + double lifetimeVariance; +} GCStat; + +#define GCSTAT_BINS NUM_BINS + +GCStat gcstats[GCSTAT_BINS]; + +#define GCLTFREQ_BINS NUM_BINS + +PRInt32 gcltfreq[GCSTAT_BINS][GCLTFREQ_BINS]; + +#include + +static char* +pr_GetSizeString(PRUint32 size) +{ + char* sizeStr; + if (size < 1024) + sizeStr = PR_smprintf("<= %ld", size); + else if (size < 1024 * 1024) + sizeStr = PR_smprintf("<= %ldk", size / 1024); + else + sizeStr = PR_smprintf("<= %ldM", size / (1024 * 1024)); + return sizeStr; +} + +static void +pr_FreeSizeString(char *sizestr) +{ + PR_smprintf_free(sizestr); +} + + +static void +pr_PrintGCAllocStats(FILE* out) +{ + PRInt32 i, j; + _PR_DebugPrint(out, "\n--Allocation-Stats-----------------------------------------------------------"); + _PR_DebugPrint(out, "\n--Obj-Size----Count-----Avg-Alloc-Time-----------Avg-Lifetime---------%%Freed-\n"); + for (i = 0; i < GCSTAT_BINS; i++) { + GCStat stat = gcstats[i]; + double allocTimeMean = 0.0, allocTimeVariance = 0.0, lifetimeMean = 0.0, lifetimeVariance = 0.0; + PRUint32 maxSize = (1 << i); + char* sizeStr; + if (stat.nallocs != 0.0) { + allocTimeMean = stat.allocTime / stat.nallocs; + allocTimeVariance = fabs(stat.allocTimeVariance / stat.nallocs - allocTimeMean * allocTimeMean); + } + if (stat.nfrees != 0.0) { + lifetimeMean = stat.lifetime / stat.nfrees; + lifetimeVariance = fabs(stat.lifetimeVariance / stat.nfrees - lifetimeMean * lifetimeMean); + } + sizeStr = pr_GetSizeString(maxSize); + _PR_DebugPrint(out, "%10s %8lu %10.3f +- %10.3f %10.3f +- %10.3f (%2ld%%)\n", + sizeStr, stat.nallocs, + allocTimeMean, sqrt(allocTimeVariance), + lifetimeMean, sqrt(lifetimeVariance), + (stat.nallocs ? (stat.nfrees * 100 / stat.nallocs) : 0)); + pr_FreeSizeString(sizeStr); + } + _PR_DebugPrint(out, "--Lifetime-Frequency-Counts----------------------------------------------------\n"); + _PR_DebugPrint(out, "size\\cnt"); + for (j = 0; j < GCLTFREQ_BINS; j++) { + _PR_DebugPrint(out, "\t%lu", j); + } + _PR_DebugPrint(out, "\n"); + for (i = 0; i < GCSTAT_BINS; i++) { + PRInt32* freqs = gcltfreq[i]; + _PR_DebugPrint(out, "%lu", (1 << i)); + for (j = 0; j < GCLTFREQ_BINS; j++) { + _PR_DebugPrint(out, "\t%lu", freqs[j]); + } + _PR_DebugPrint(out, "\n"); + } + _PR_DebugPrint(out, "-------------------------------------------------------------------------------\n"); +} + +PR_PUBLIC_API(void) +PR_PrintGCAllocStats(void) +{ + pr_PrintGCAllocStats(stderr); +} + +#endif /* GC_STATS */ + +/************************************************************************/ + +/* +** Sweep a segment, cleaning up all of the debris. Coallese the debris +** into GCFreeChunk's which are added to the freelist bins. +*/ +static PRBool SweepSegment(GCSeg *sp) +{ + PRWord h, tix; + PRWord *p; + PRWord *np; + PRWord *limit; + GCFreeChunk *cp; + PRInt32 bytes, chunkSize, segmentSize, totalFree; + CollectorType *ct; + PRInt32 bin; + + /* + ** Now scan over the segment's memory in memory order, coallescing + ** all of the debris into a FreeChunk list. + */ + totalFree = 0; + segmentSize = sp->limit - sp->base; + p = (PRWord *) sp->base; + limit = (PRWord *) sp->limit; + PR_ASSERT(segmentSize > 0); + while (p < limit) { + chunkSize = 0; + cp = (GCFreeChunk *) p; + + /* Attempt to coallesce any neighboring free objects */ + for (;;) { + PR_ASSERT(IS_HBIT(sp, p) != 0); + h = p[0]; + bytes = OBJ_BYTES(h); + PR_ASSERT(bytes != 0); + np = (PRWord *) ((char *)p + bytes); + tix = (PRWord)GET_TYPEIX(h); + if ((h & MARK_BIT) && (tix != FREE_MEMORY_TYPEIX)) { +#ifdef DEBUG + if (tix != FREE_MEMORY_TYPEIX) { + PR_ASSERT(_pr_collectorTypes[tix].flags != 0); + } +#endif + p[0] = h & ~(MARK_BIT|FINAL_BIT); + _GCTRACE(GC_SWEEP, ("busy 0x%x (%d)", p, bytes)); + break; + } + _GCTRACE(GC_SWEEP, ("free 0x%x (%d)", p, bytes)); + + /* Found a free object */ +#ifdef GC_STATS + { + PRInt32 userSize = bytes - sizeof(GCBlockEnd); + GCBlockEnd* end = (GCBlockEnd*)((char*)p + userSize); + if (userSize >= 0 && end->check == PR_BLOCK_END) { + PRInt64 now = PR_Now(); + double nowd, delta; + PRInt32 freq; + LL_L2D(nowd, now); + delta = nowd - end->allocTime; + gcstats[end->bin].nfrees++; + gcstats[end->bin].lifetime += delta; + gcstats[end->bin].lifetimeVariance += delta * delta; + + InlineBinNumber(freq, delta); + gcltfreq[end->bin][freq]++; + + end->check = 0; + } + } +#endif + CLEAR_HBIT(sp, p); + ct = &_pr_collectorTypes[tix]; + if (0 != ct->gctype.free) { + (*ct->gctype.free)(p + 1); + } + chunkSize = chunkSize + bytes; + if (np == limit) { + /* Found the end of heap */ + break; + } + PR_ASSERT(np < limit); + p = np; + } + + if (chunkSize) { + _GCTRACE(GC_SWEEP, ("free chunk 0x%p to 0x%p (%d)", + cp, (char*)cp + chunkSize - 1, chunkSize)); + if (chunkSize < MIN_FREE_CHUNK_BYTES) { + /* Lost a tiny fragment until (maybe) next time */ + METER(meter.wastedBytes += chunkSize); + p = (PRWord *) cp; + chunkSize >>= BYTES_PER_WORD_LOG2; + PR_ASSERT(chunkSize != 0); + p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, chunkSize); + SET_HBIT(sp, p); + } else { + /* See if the chunk constitutes the entire segment */ + if (chunkSize == segmentSize) { + /* Free up the segment right now */ + if (sp->info->fromMalloc) { + ShrinkGCHeap(sp); + return PR_TRUE; + } + } + + /* Put free chunk into the appropriate bin */ + cp->segment = sp; + cp->chunkSize = chunkSize; + InlineBinNumber(bin, chunkSize) + cp->next = bins[bin]; + bins[bin] = cp; + if (bin < minBin) minBin = bin; + if (bin > maxBin) maxBin = bin; + + /* Zero swept memory now */ + memset(cp+1, 0, chunkSize - sizeof(*cp)); + METER(meter.numFreeChunks++); + totalFree += chunkSize; + } + } + + /* Advance to next object */ + p = np; + } + + PR_ASSERT(totalFree <= segmentSize); + + _pr_gcData.freeMemory += totalFree; + _pr_gcData.busyMemory += (sp->limit - sp->base) - totalFree; + return PR_FALSE; +} + +/************************************************************************/ + +/* This is a list of all the objects that are finalizable. This is not + the list of objects that are awaiting finalization because they + have been collected. */ +PRCList _pr_finalizeableObjects; + +/* This is the list of objects that are awaiting finalization because + they have been collected. */ +PRCList _pr_finalQueue; + +/* Each object that requires finalization has one of these objects + allocated as well. The GCFinal objects are put on the + _pr_finalizeableObjects list until the object is collected at which + point the GCFinal object is moved to the _pr_finalQueue */ +typedef struct GCFinalStr { + PRCList links; + PRWord *object; +} GCFinal; + +/* Find pointer to GCFinal struct from the list linkaged embedded in it */ +#define FinalPtr(_qp) \ + ((GCFinal*) ((char*) (_qp) - offsetof(GCFinal,links))) + +static GCFinal *AllocFinalNode(void) +{ + return PR_NEWZAP(GCFinal); +} + +static void FreeFinalNode(GCFinal *node) +{ + PR_DELETE(node); +} + +/* +** Prepare for finalization. At this point in the GC cycle we have +** identified all of the live objects. For each object on the +** _pr_finalizeableObjects list see if the object is alive or dead. If +** it's dead, resurrect it and move it from the _pr_finalizeableObjects +** list to the _pr_finalQueue (object's only get finalized once). +** +** Once _pr_finalizeableObjects has been processed we can finish the +** GC and free up memory and release the threading lock. After that we +** can invoke the finalization procs for each object that is on the +** _pr_finalQueue. +*/ +static void PrepareFinalize(void) +{ + PRCList *qp; + GCFinal *fp; + PRWord h; + PRWord *p; + void (PR_CALLBACK *livePointer)(void *ptr); +#ifdef DEBUG + CollectorType *ct; +#endif + + /* This must be done under the same lock that the finalizer uses */ + PR_ASSERT( GC_IS_LOCKED() ); + + /* cache this ptr */ + livePointer = _pr_gcData.livePointer; + + /* + * Pass #1: Identify objects that are to be finalized, set their + * FINAL_BIT. + */ + qp = _pr_finalizeableObjects.next; + while (qp != &_pr_finalizeableObjects) { + fp = FinalPtr(qp); + qp = qp->next; + h = fp->object[0]; /* Grab header word */ + if (h & MARK_BIT) { + /* Object is already alive */ + continue; + } + +#ifdef DEBUG + ct = &_pr_collectorTypes[GET_TYPEIX(h)]; + PR_ASSERT((0 != ct->flags) && (0 != ct->gctype.finalize)); +#endif + fp->object[0] |= FINAL_BIT; + _GCTRACE(GC_FINAL, ("moving %p (%d) to finalQueue", + fp->object, OBJ_BYTES(h))); + } + + /* + * Pass #2: For each object that is going to be finalized, move it to + * the finalization queue and resurrect it + */ + qp = _pr_finalizeableObjects.next; + while (qp != &_pr_finalizeableObjects) { + fp = FinalPtr(qp); + qp = qp->next; + h = fp->object[0]; /* Grab header word */ + if ((h & FINAL_BIT) == 0) { + continue; + } + + /* Resurrect the object and any objects it refers to */ + p = &fp->object[1]; + (*livePointer)(p); + PR_REMOVE_LINK(&fp->links); + PR_APPEND_LINK(&fp->links, &_pr_finalQueue); + } +} + +/* +** Scan the finalQ, marking each and every object on it live. This is +** necessary because we might do a GC before objects that are on the +** final queue get finalized. Since there are no other references +** (otherwise they would be on the final queue), we have to scan them. +** This really only does work if we call the GC before the finalizer +** has a chance to do its job. +*/ +extern void PR_CALLBACK _PR_ScanFinalQueue(void *notused) +{ +#ifdef XP_MAC +#pragma unused (notused) +#endif + PRCList *qp; + GCFinal *fp; + PRWord *p; + void ( PR_CALLBACK *livePointer)(void *ptr); + + livePointer = _pr_gcData.livePointer; + qp = _pr_finalQueue.next; + while (qp != &_pr_finalQueue) { + fp = FinalPtr(qp); + _GCTRACE(GC_FINAL, ("marking 0x%x (on final queue)", fp->object)); + p = &fp->object[1]; + (*livePointer)(p); + qp = qp->next; + } +} + +void PR_CALLBACK FinalizerLoop(void* unused) +{ +#ifdef XP_MAC +#pragma unused (unused) +#endif + GCFinal *fp; + PRWord *p; + PRWord h, tix; + CollectorType *ct; + + LOCK_GC(); + for (;;) { + p = 0; h = 0; /* don't let the gc find these pointers */ + while (PR_CLIST_IS_EMPTY(&_pr_finalQueue)) + PR_Wait(_pr_gcData.lock, PR_INTERVAL_NO_TIMEOUT); + + _GCTRACE(GC_FINAL, ("begin finalization")); + while (_pr_finalQueue.next != &_pr_finalQueue) { + fp = FinalPtr(_pr_finalQueue.next); + PR_REMOVE_LINK(&fp->links); + p = fp->object; + + h = p[0]; /* Grab header word */ + tix = (PRWord)GET_TYPEIX(h); + ct = &_pr_collectorTypes[tix]; + _GCTRACE(GC_FINAL, ("finalize 0x%x (%d)", p, OBJ_BYTES(h))); + + /* + ** Give up the GC lock so that other threads can allocate memory + ** while this finalization method is running. Get it back + ** afterwards so that the list remains thread safe. + */ + UNLOCK_GC(); + FreeFinalNode(fp); + PR_ASSERT(ct->gctype.finalize != 0); + (*ct->gctype.finalize)(p + 1); + LOCK_GC(); + } + _GCTRACE(GC_FINAL, ("end finalization")); + PR_Notify(_pr_gcData.lock); + } +} + +static void NotifyFinalizer(void) +{ + if (!PR_CLIST_IS_EMPTY(&_pr_finalQueue)) { + PR_ASSERT( GC_IS_LOCKED() ); + PR_Notify(_pr_gcData.lock); + } +} + +void _PR_CreateFinalizer(PRThreadScope scope) +{ + if (!_pr_gcData.finalizer) { + _pr_gcData.finalizer = PR_CreateThreadGCAble(PR_SYSTEM_THREAD, + FinalizerLoop, 0, + PR_PRIORITY_LOW, scope, + PR_UNJOINABLE_THREAD, 0); + + if (_pr_gcData.finalizer == NULL) + /* We are doomed if we can't start the finalizer */ + PR_Abort(); + + } +} + +void pr_FinalizeOnExit(void) +{ +#ifdef DEBUG_warren + OutputDebugString("### Doing finalize-on-exit pass\n"); +#endif + PR_ForceFinalize(); +#ifdef DEBUG_warren + OutputDebugString("### Finalize-on-exit complete. Dumping object left to memory.out\n"); + PR_DumpMemorySummary(); + PR_DumpMemory(PR_TRUE); +#endif +} + +PR_IMPLEMENT(void) PR_ForceFinalize() +{ + LOCK_GC(); + NotifyFinalizer(); + while (!PR_CLIST_IS_EMPTY(&_pr_finalQueue)) { + PR_ASSERT( GC_IS_LOCKED() ); + (void) PR_Wait(_pr_gcData.lock, PR_INTERVAL_NO_TIMEOUT); + } + UNLOCK_GC(); + + /* XXX I don't know how to make it wait (yet) */ +} + +/************************************************************************/ + +typedef struct GCWeakStr { + PRCList links; + PRWord *object; +} GCWeak; + +/* +** Find pointer to GCWeak struct from the list linkaged embedded in it +*/ +#define WeakPtr(_qp) \ + ((GCWeak*) ((char*) (_qp) - offsetof(GCWeak,links))) + +PRCList _pr_weakLinks = PR_INIT_STATIC_CLIST(&_pr_weakLinks); +PRCList _pr_freeWeakLinks = PR_INIT_STATIC_CLIST(&_pr_freeWeakLinks); + +#define WEAK_FREELIST_ISEMPTY() (_pr_freeWeakLinks.next == &_pr_freeWeakLinks) + +/* + * Keep objects referred to by weak free list alive until they can be + * freed + */ +static void PR_CALLBACK ScanWeakFreeList(void *notused) { +#ifdef XP_MAC +#pragma unused (notused) +#endif + PRCList *qp = _pr_freeWeakLinks.next; + while (qp != &_pr_freeWeakLinks) { + GCWeak *wp = WeakPtr(qp); + qp = qp->next; + ProcessRootPointer(wp->object); + } +} + +/* + * Empty the list of weak objects. Note that we can't call malloc/free + * under the cover of the GC's lock (we might deadlock), so transfer the + * list of free objects to a local list under the cover of the lock, then + * release the lock and free up the memory. + */ +static void EmptyWeakFreeList(void) { + if (!WEAK_FREELIST_ISEMPTY()) { + PRCList *qp, freeLinks; + + PR_INIT_CLIST(&freeLinks); + + /* + * Transfer list of free weak links from the global list to a + * local list. + */ + LOCK_GC(); + qp = _pr_freeWeakLinks.next; + while (qp != &_pr_freeWeakLinks) { + GCWeak *wp = WeakPtr(qp); + qp = qp->next; + PR_REMOVE_LINK(&wp->links); + PR_APPEND_LINK(&wp->links, &freeLinks); + } + UNLOCK_GC(); + + /* Free up storage now */ + qp = freeLinks.next; + while (qp != &freeLinks) { + GCWeak *wp = WeakPtr(qp); + qp = qp->next; + PR_DELETE(wp); + } + } +} + +/* + * Allocate a new weak node in the weak objects list + */ +static GCWeak *AllocWeakNode(void) +{ + EmptyWeakFreeList(); + return PR_NEWZAP(GCWeak); +} + +static void FreeWeakNode(GCWeak *node) +{ + PR_DELETE(node); +} + +/* + * Check the weak links for validity. Note that the list of weak links is + * itself weak (otherwise we would keep the objects with weak links in + * them alive forever). As we scan the list check the weak link object + * itself and if it's not marked then remove it from the weak link list + */ +static void CheckWeakLinks(void) { + PRCList *qp; + GCWeak *wp; + PRWord *p, h, tix, **weakPtrAddress; + CollectorType *ct; + PRUint32 offset; + + qp = _pr_weakLinks.next; + while (qp != &_pr_weakLinks) { + wp = WeakPtr(qp); + qp = qp->next; + if ((p = wp->object) != 0) { + h = p[0]; /* Grab header word */ + if ((h & MARK_BIT) == 0) { + /* + * The object that has a weak link is no longer being + * referenced; remove it from the chain and let it get + * swept away by the GC. Transfer it to the list of + * free weak links for later freeing. + */ + PR_REMOVE_LINK(&wp->links); + PR_APPEND_LINK(&wp->links, &_pr_freeWeakLinks); + collectorCleanupNeeded = 1; + continue; + } + + /* Examine a live object that contains weak links */ + tix = GET_TYPEIX(h); + ct = &_pr_collectorTypes[tix]; + PR_ASSERT((ct->flags != 0) && (ct->gctype.getWeakLinkOffset != 0)); + if (0 == ct->gctype.getWeakLinkOffset) { + /* Heap is probably corrupted */ + continue; + } + + /* Get offset into the object of where the weak pointer is */ + offset = (*ct->gctype.getWeakLinkOffset)(p + 1); + + /* Check the weak pointer */ + weakPtrAddress = (PRWord**)((char*)(p + 1) + offset); + p = *weakPtrAddress; + if (p != 0) { + h = p[-1]; /* Grab header word for pointed to object */ + if (h & MARK_BIT) { + /* Object can't be dead */ + continue; + } + /* Break weak link to an object that is about to be swept */ + *weakPtrAddress = 0; + } + } + } +} + +/************************************************************************/ + +/* +** Perform a complete garbage collection +*/ + +extern GCLockHook *_pr_GCLockHook; + +static void dogc(void) +{ + RootFinder *rf; + GCLockHook* lhook; + + GCScanQ scanQ; + GCSeg *sp, *esp; + PRInt64 start, end, diff; + +#if defined(GCMETER) || defined(GCTIMINGHOOK) + start = PR_Now(); +#endif + + /* + ** Stop all of the other threads. This also promises to capture the + ** register state of each and every thread + */ + + /* + ** Get all the locks that will be need during GC after SuspendAll. We + ** cannot make any locking/library calls after SuspendAll. + */ + if (_pr_GCLockHook) { + for (lhook = _pr_GCLockHook->next; lhook != _pr_GCLockHook; + lhook = lhook->next) { + (*lhook->func)(PR_GCBEGIN, lhook->arg); + } + } + + PR_SuspendAll(); + +#ifdef GCMETER + /* Reset meter info */ + if (_pr_gcMeter & _GC_METER_STATS) { + fprintf(stderr, + "[GCSTATS: busy:%ld skipped:%ld, alloced:%ld+wasted:%ld+free:%ld = total:%ld]\n", + (long) _pr_gcData.busyMemory, + (long) meter.skippedFreeChunks, + (long) meter.allocBytes, + (long) meter.wastedBytes, + (long) _pr_gcData.freeMemory, + (long) _pr_gcData.allocMemory); + } + memset(&meter, 0, sizeof(meter)); +#endif + + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("begin mark phase; busy=%d free=%d total=%d", + _pr_gcData.busyMemory, _pr_gcData.freeMemory, + _pr_gcData.allocMemory)); + + if (_pr_beginGCHook) { + (*_pr_beginGCHook)(_pr_beginGCHookArg); + } + + /* + ** Initialize scanQ to all zero's so that root finder doesn't walk + ** over it... + */ + memset(&scanQ, 0, sizeof(scanQ)); + pScanQ = &scanQ; + + /******************************************/ + /* MARK PHASE */ + + EmptyFreelists(); + + /* Find root's */ + PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, + ("begin mark phase; busy=%d free=%d total=%d", + _pr_gcData.busyMemory, _pr_gcData.freeMemory, + _pr_gcData.allocMemory)); + METER(_pr_scanDepth = 0); + rf = _pr_rootFinders; + while (rf) { + _GCTRACE(GC_ROOTS, ("finding roots in %s", rf->name)); + (*rf->func)(rf->arg); + rf = rf->next; + } + _GCTRACE(GC_ROOTS, ("done finding roots")); + + /* Scan remaining object's that need scanning */ + ScanScanQ(&scanQ); + PR_ASSERT(pScanQ == &scanQ); + PR_ASSERT(scanQ.queued == 0); + METER({ + if (_pr_scanDepth > _pr_maxScanDepth) { + _pr_maxScanDepth = _pr_scanDepth; + } + }); + + /******************************************/ + /* FINALIZATION PHASE */ + + METER(_pr_scanDepth = 0); + PrepareFinalize(); + + /* Scan any resurrected objects found during finalization */ + ScanScanQ(&scanQ); + PR_ASSERT(pScanQ == &scanQ); + PR_ASSERT(scanQ.queued == 0); + METER({ + if (_pr_scanDepth > _pr_maxScanDepth) { + _pr_maxScanDepth = _pr_scanDepth; + } + }); + pScanQ = 0; + + /******************************************/ + /* SWEEP PHASE */ + + /* + ** Sweep each segment clean. While we are at it, figure out which + ** segment has the most free space and make that the current segment. + */ + CheckWeakLinks(); + _GCTRACE(GC_SWEEP, ("begin sweep phase")); + _pr_gcData.freeMemory = 0; + _pr_gcData.busyMemory = 0; + sp = segs; + esp = sp + nsegs; + while (sp < esp) { + if (SweepSegment(sp)) { + /* + ** Segment is now free and has been replaced with a different + ** segment object. + */ + esp--; + continue; + } + sp++; + } + +#if defined(GCMETER) || defined(GCTIMINGHOOK) + end = PR_Now(); +#endif +#ifdef GCMETER + LL_SUB(diff, end, start); + PR_LOG(GC, PR_LOG_ALWAYS, + ("done; busy=%d free=%d chunks=%d total=%d time=%lldms", + _pr_gcData.busyMemory, _pr_gcData.freeMemory, + meter.numFreeChunks, _pr_gcData.allocMemory, diff)); + if (_pr_gcMeter & _GC_METER_FREE_LIST) { + PRIntn bin; + fprintf(stderr, "Freelist bins:\n"); + for (bin = 0; bin < NUM_BINS; bin++) { + GCFreeChunk *cp = bins[bin]; + while (cp != NULL) { + fprintf(stderr, "%3d: %p %8ld\n", + bin, cp, (long) cp->chunkSize); + cp = cp->next; + } + } + } +#endif + + if (_pr_endGCHook) { + (*_pr_endGCHook)(_pr_endGCHookArg); + } + + /* clear the running total of the bytes allocated via BigAlloc() */ + bigAllocBytes = 0; + + /* And resume multi-threading */ + PR_ResumeAll(); + + if (_pr_GCLockHook) { + for (lhook = _pr_GCLockHook->prev; lhook != _pr_GCLockHook; + lhook = lhook->prev) { + (*lhook->func)(PR_GCEND, lhook->arg); + } + } + + /* Kick finalizer */ + NotifyFinalizer(); +#ifdef GCTIMINGHOOK + if (_pr_gcData.gcTimingHook) { + PRInt32 time; + LL_SUB(diff, end, start); + LL_L2I(time, diff); + _pr_gcData.gcTimingHook(time); + } +#endif +} + +PR_IMPLEMENT(void) PR_GC(void) +{ + LOCK_GC(); + dogc(); + UNLOCK_GC(); + + EmptyWeakFreeList(); +} + +/******************************************************************************* + * Heap Walker + ******************************************************************************/ + +/* +** This is yet another disgusting copy of the body of ProcessRootPointer +** (the other being ProcessRootBlock), but we're not leveraging a single +** function in their cases in interest of performance (avoiding the function +** call). +*/ +static PRInt32 PR_CALLBACK +pr_ConservativeWalkPointer(void* ptr, PRWalkFun walkRootPointer, void* data) +{ + PRWord *p0, *p, *segBase; + GCSeg* sp; + + p0 = (PRWord*) ptr; + + /* + ** XXX: + ** Until Win16 maintains lowSeg and highSeg correctly, + ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs)) + ** Allways scan through the segment list + */ +#if !defined(WIN16) + if (p0 < _pr_gcData.lowSeg) return 0; /* below gc heap */ + if (p0 >= _pr_gcData.highSeg) return 0; /* above gc heap */ +#endif + + /* NOTE: inline expansion of InHeap */ + /* Find segment */ + sp = lastInHeap; + if (!sp || !IN_SEGMENT(sp,p0)) { + GCSeg *esp; + sp = segs; + esp = segs + nsegs; + for (; sp < esp; sp++) { + if (IN_SEGMENT(sp, p0)) { + lastInHeap = sp; + goto find_object; + } + } + return 0; + } + + find_object: + /* NOTE: Inline expansion of FindObject */ + /* Align p to it's proper boundary before we start fiddling with it */ + p = (PRWord*) ((PRWord)p0 & ~(BYTES_PER_WORD-1L)); + segBase = (PRWord *) sp->base; + do { + if (IS_HBIT(sp, p)) { + goto winner; + } + p--; + } while (p >= segBase); + + /* + ** We have a pointer into the heap, but it has no header + ** bit. This means that somehow the very first object in the heap + ** doesn't have a header. This is impossible so when debugging + ** lets abort. + */ +#ifdef DEBUG + PR_Abort(); +#endif + return 0; + + winner: + return walkRootPointer(p, data); +} + +static PRInt32 PR_CALLBACK +pr_ConservativeWalkBlock(void **base, PRInt32 count, + PRWalkFun walkRootPointer, void* data) +{ + PRWord *p0; + while (--count >= 0) { + PRInt32 status; + p0 = (PRWord*) *base++; + status = pr_ConservativeWalkPointer(p0, walkRootPointer, data); + if (status) return status; + } + return 0; +} + +/******************************************************************************/ + +typedef void (*WalkObject_t)(FILE *out, GCType* tp, PRWord *obj, + size_t bytes, PRBool detailed); +typedef void (*WalkUnknown_t)(FILE *out, GCType* tp, PRWord tix, PRWord *p, + size_t bytes, PRBool detailed); +typedef void (*WalkFree_t)(FILE *out, PRWord *p, size_t size, PRBool detailed); +typedef void (*WalkSegment_t)(FILE *out, GCSeg* sp, PRBool detailed); + +static void +pr_WalkSegment(FILE* out, GCSeg* sp, PRBool detailed, + char* enterMsg, char* exitMsg, + WalkObject_t walkObject, WalkUnknown_t walkUnknown, WalkFree_t walkFree) +{ + PRWord *p, *limit; + + p = (PRWord *) sp->base; + limit = (PRWord *) sp->limit; + if (enterMsg) + fprintf(out, enterMsg, p); + while (p < limit) + { + if (IS_HBIT(sp, p)) /* Is this an object header? */ + { + PRWord h = p[0]; + PRWord tix = GET_TYPEIX(h); + size_t bytes = OBJ_BYTES(h); + PRWord* np = (PRWord*) ((char*)p + bytes); + + GCType* tp = &_pr_collectorTypes[tix].gctype; + if ((0 != tp) && walkObject) + walkObject(out, tp, p, bytes, detailed); + else if (walkUnknown) + walkUnknown(out, tp, tix, p, bytes, detailed); + p = np; + } + else + { + /* Must be a freelist item */ + size_t size = ((GCFreeChunk*)p)->chunkSize; + if (walkFree) + walkFree(out, p, size, detailed); + p = (PRWord*)((char*)p + size); + } + } + if (p != limit) + fprintf(out, "SEGMENT OVERRUN (end should be at 0x%p)\n", limit); + if (exitMsg) + fprintf(out, exitMsg, p); +} + +static void +pr_WalkSegments(FILE *out, WalkSegment_t walkSegment, PRBool detailed) +{ + GCSeg *sp = segs; + GCSeg *esp; + + LOCK_GC(); + esp = sp + nsegs; + while (sp < esp) + { + walkSegment(out, sp, detailed); + sp++; + } + fprintf(out, "End of heap\n"); + UNLOCK_GC(); +} + +/******************************************************************************* + * Heap Dumper + ******************************************************************************/ + +PR_IMPLEMENT(void) +PR_DumpIndent(FILE *out, int indent) +{ + while (--indent >= 0) + fprintf(out, " "); +} + +static void +PR_DumpHexWords(FILE *out, PRWord *p, int nWords, + int indent, int nWordsPerLine) +{ + while (nWords > 0) + { + int i; + + PR_DumpIndent(out, indent); + i = nWordsPerLine; + if (i > nWords) + i = nWords; + nWords -= i; + while (i--) + { + fprintf(out, "0x%.8lX", (long) *p++); + if (i) + fputc(' ', out); + } + fputc('\n', out); + } +} + +static void PR_CALLBACK +pr_DumpObject(FILE *out, GCType* tp, PRWord *p, + size_t bytes, PRBool detailed) +{ + char kindChar = tp->kindChar; + fprintf(out, "0x%p: 0x%.6lX %c ", + p, (long) bytes, kindChar ? kindChar : '?'); + if (tp->dump) + (*tp->dump)(out, (void*) (p + 1), detailed, 0); + if (detailed) + PR_DumpHexWords(out, p, bytes>>2, 22, 4); +} + +static void PR_CALLBACK +pr_DumpUnknown(FILE *out, GCType* tp, PRWord tix, PRWord *p, + size_t bytes, PRBool detailed) +{ + char kindChar = tp->kindChar; + fprintf(out, "0x%p: 0x%.6lX %c ", + p, (long) bytes, kindChar ? kindChar : '?'); + fprintf(out, "UNKNOWN KIND %ld\n", (long) tix); + if (detailed) + PR_DumpHexWords(out, p, bytes>>2, 22, 4); +} + +static void PR_CALLBACK +pr_DumpFree(FILE *out, PRWord *p, size_t size, PRBool detailed) +{ +#if defined(XP_MAC) && XP_MAC +# pragma unused( detailed ) +#endif + + fprintf(out, "0x%p: 0x%.6lX - FREE\n", p, (long) size); +} + +static void PR_CALLBACK +pr_DumpSegment(FILE* out, GCSeg* sp, PRBool detailed) +{ + pr_WalkSegment(out, sp, detailed, + "\n Address: Length\n0x%p: Beginning of segment\n", + "0x%p: End of segment\n\n", + pr_DumpObject, pr_DumpUnknown, pr_DumpFree); +} + +static void pr_DumpRoots(FILE *out); + +/* +** Dump out the GC heap. +*/ +PR_IMPLEMENT(void) +PR_DumpGCHeap(FILE *out, PRBool detailed) +{ + fprintf(out, "\n" + "The kinds are:\n" + " U unscanned block\n" + " W weak link block\n" + " S scanned block\n" + " F scanned and final block\n" + " C class record\n" + " X context record\n" + " - free list item\n" + " ? other\n"); + LOCK_GC(); + pr_WalkSegments(out, pr_DumpSegment, detailed); + if (detailed) + pr_DumpRoots(out); + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) +PR_DumpMemory(PRBool detailed) +{ + PR_DumpToFile("memory.out", "Dumping memory", PR_DumpGCHeap, detailed); +} + +/******************************************************************************/ + +static PRInt32 PR_CALLBACK +pr_DumpRootPointer(PRWord* p, void* data) +{ +#ifdef XP_MAC +#pragma unused(data) +#endif + PRWord h = p[0]; + PRWord tix = GET_TYPEIX(h); + size_t bytes = OBJ_BYTES(h); + + GCType* tp = &_pr_collectorTypes[tix].gctype; + if (0 != tp) + pr_DumpObject(_pr_gcData.dumpOutput, tp, p, bytes, PR_FALSE); + else + pr_DumpUnknown(_pr_gcData.dumpOutput, tp, tix, p, bytes, PR_FALSE); + return 0; +} + +static void PR_CALLBACK +pr_ConservativeDumpRootPointer(void* ptr) +{ + (void)pr_ConservativeWalkPointer(ptr, (PRWalkFun) pr_DumpRootPointer, NULL); +} + +static void PR_CALLBACK +pr_ConservativeDumpRootBlock(void **base, PRInt32 count) +{ + (void)pr_ConservativeWalkBlock(base, count, (PRWalkFun) pr_DumpRootPointer, NULL); +} + +extern int +DumpThreadRoots(PRThread *t, int i, void *notused); + +static void +pr_DumpRoots(FILE *out) +{ + RootFinder *rf; + void (*liveBlock)(void **base, PRInt32 count); + void (*livePointer)(void *ptr); + void (*processRootBlock)(void **base, PRInt32 count); + void (*processRootPointer)(void *ptr); + + LOCK_GC(); + + liveBlock = _pr_gcData.liveBlock; + livePointer = _pr_gcData.livePointer; + processRootBlock = _pr_gcData.processRootBlock; + processRootPointer = _pr_gcData.processRootPointer; + + _pr_gcData.liveBlock = pr_ConservativeDumpRootBlock; + _pr_gcData.livePointer = pr_ConservativeDumpRootPointer; + _pr_gcData.processRootBlock = pr_ConservativeDumpRootBlock; + _pr_gcData.processRootPointer = pr_ConservativeDumpRootPointer; + _pr_gcData.dumpOutput = out; + + rf = _pr_rootFinders; + while (rf) { + fprintf(out, "\n===== Roots for %s\n", rf->name); + (*rf->func)(rf->arg); + rf = rf->next; + } + + _pr_gcData.liveBlock = liveBlock; + _pr_gcData.livePointer = livePointer; + _pr_gcData.processRootBlock = processRootBlock; + _pr_gcData.processRootPointer = processRootPointer; + _pr_gcData.dumpOutput = NULL; + + UNLOCK_GC(); +} + +/******************************************************************************* + * Heap Summary Dumper + ******************************************************************************/ + +PRSummaryPrinter summaryPrinter = NULL; +void* summaryPrinterClosure = NULL; + +PR_IMPLEMENT(void) +PR_RegisterSummaryPrinter(PRSummaryPrinter fun, void* closure) +{ + summaryPrinter = fun; + summaryPrinterClosure = closure; +} + +static void PR_CALLBACK +pr_SummarizeObject(FILE *out, GCType* tp, PRWord *p, + size_t bytes, PRBool detailed) +{ +#if defined(XP_MAC) && XP_MAC +# pragma unused( out, detailed ) +#endif + + if (tp->summarize) + (*tp->summarize)((void GCPTR*)(p + 1), bytes); +} + +static void PR_CALLBACK +pr_DumpSummary(FILE* out, GCSeg* sp, PRBool detailed) +{ + pr_WalkSegment(out, sp, detailed, NULL, NULL, + pr_SummarizeObject, NULL, NULL); +} + +PR_IMPLEMENT(void) +PR_DumpGCSummary(FILE *out, PRBool detailed) +{ + if (summaryPrinter) { + pr_WalkSegments(out, pr_DumpSummary, detailed); + summaryPrinter(out, summaryPrinterClosure); + } +#if 0 + fprintf(out, "\nFinalizable objects:\n"); + { + PRCList *qp; + qp = _pr_pendingFinalQueue.next; + while (qp != &_pr_pendingFinalQueue) { + GCFinal* fp = FinalPtr(qp); + PRWord h = fp->object[0]; /* Grab header word */ + PRWord tix = GET_TYPEIX(h); + GCType* tp = _pr_gcTypes[tix]; + size_t bytes = OBJ_BYTES(h); + pr_DumpObject(out, tp, fp->object, bytes, PR_FALSE); + qp = qp->next; + } + } +#endif +} + +PR_IMPLEMENT(void) +PR_DumpMemorySummary(void) +{ + PR_DumpToFile("memory.out", "Memory Summary", PR_DumpGCSummary, PR_FALSE); +} + +/******************************************************************************* + * End Of Heap Walker + ******************************************************************************/ + +#ifdef GC_TRACEROOTS + +PRInt32 pr_traceGen = 0; + +static PRBool +pr_IsMarked(PRWord* p) +{ + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + PR_ASSERT(end->check == PR_BLOCK_END); + return end->traceGeneration == pr_traceGen; +} + +static void +pr_Mark(PRWord* p) +{ + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + PR_ASSERT(end->check == PR_BLOCK_END); + end->traceGeneration = pr_traceGen; +} + +PRWord* pr_traceObj; /* set this in the debugger, then execute PR_TraceRoot() */ + +static PRInt32 PR_CALLBACK +pr_TraceRootObject(void* obj, void* data); + +static PRInt32 PR_CALLBACK +pr_TraceRootPointer(PRWord *p, void* data) +{ + PRInt32 printTrace = 0; + PRWord h = p[0]; + PRWord tix = GET_TYPEIX(h); + GCType* tp = &_pr_collectorTypes[tix].gctype; + FILE* out = _pr_gcData.dumpOutput; + + PR_ASSERT(tp); + if (pr_IsMarked(p)) + return printTrace; + + pr_Mark(p); + if (p == pr_traceObj) { + fprintf(out, "\n### Found path to:\n"); + printTrace = 1; + } + else { + if (PR_StackSpaceLeft(PR_GetCurrentThread()) < 512) { + fprintf(out, "\n### Path too deep (giving up):\n"); + printTrace = 1; + } + else if (tp->walk) { + printTrace = tp->walk((void*)(p + 1), pr_TraceRootObject, data); + } + /* else there's no way to walk this object, so we + haven't found what we're looking for */ + } + + if (printTrace == 1) { + PR_ASSERT(tp->dump); + fprintf(out, "0x%p: ", p); + tp->dump(out, (void*)(p + 1), PR_FALSE, 1); + } + return printTrace; +} + +static PRInt32 PR_CALLBACK +pr_TraceRootObject(void* obj, void* data) +{ + /* This version of pr_TraceRootPointer takes object + pointers, instead of gc header pointers. */ + return pr_TraceRootPointer((PRWord*)obj - 1, data); +} + +static void PR_CALLBACK +pr_ConservativeTraceRootPointer(PRWord *p) +{ + PRInt32 status; + ++pr_traceGen; + status = pr_ConservativeWalkPointer(p, pr_TraceRootPointer, NULL); + if (status) { + FILE* out = _pr_gcData.dumpOutput; + fprintf(out, "### from root at 0x%p\n\n", p); + } +} + +static void PR_CALLBACK +pr_ConservativeTraceRootBlock(void **base, PRInt32 count) +{ + PRInt32 status; + ++pr_traceGen; + status = pr_ConservativeWalkBlock(base, count, pr_TraceRootPointer, NULL); + if (status) { + FILE* out = _pr_gcData.dumpOutput; + fprintf(out, "### from root in range 0x%p + 0x%lx\n\n", + base, (long) count); + } +} + +static void +PR_TraceRoot1(FILE* out, PRBool detailed) +{ + RootFinder *rf; + void (*liveBlock)(void **base, PRInt32 count); + void (*livePointer)(void *ptr); + void (*processRootBlock)(void **base, PRInt32 count); + void (*processRootPointer)(void *ptr); + + LOCK_GC(); + + liveBlock = _pr_gcData.liveBlock; + livePointer = _pr_gcData.livePointer; + processRootBlock = _pr_gcData.processRootBlock; + processRootPointer = _pr_gcData.processRootPointer; + + _pr_gcData.liveBlock = pr_ConservativeTraceRootBlock; + _pr_gcData.livePointer = pr_ConservativeTraceRootPointer; + _pr_gcData.processRootBlock = pr_ConservativeTraceRootBlock; + _pr_gcData.processRootPointer = pr_ConservativeTraceRootPointer; + _pr_gcData.dumpOutput = out; + + fprintf(out, "### Looking for paths to 0x%p\n\n", pr_traceObj); + + rf = _pr_rootFinders; + while (rf) { + fprintf(out, "\n===== Roots for %s\n", rf->name); + (*rf->func)(rf->arg); + rf = rf->next; + } + + _pr_gcData.liveBlock = liveBlock; + _pr_gcData.livePointer = livePointer; + _pr_gcData.processRootBlock = processRootBlock; + _pr_gcData.processRootPointer = processRootPointer; + _pr_gcData.dumpOutput = NULL; + + UNLOCK_GC(); +} + +PR_PUBLIC_API(void) +PR_TraceRoot() +{ + /* + ** How this works: + ** Once you find the object you want to trace the roots of, set the + ** global variable pr_traceObj to point to it (the header, not the + ** java handle), and then call this routine (on Windows, you can set + ** a breakpoint at the end of a function that returns void (e.g. dogc) + ** and then do a "set next statement" to point to this routine and go. + ** This will dump a list of the paths from the roots to the object in + ** question to your memory.out file. + */ + PR_DumpToFile("memory.out", "Tracing Roots", PR_TraceRoot1, PR_FALSE); +} + +#endif /* GC_TRACEROOTS */ + +/******************************************************************************/ + +#if defined(DEBUG) && defined(WIN32) +static void DumpApplicationHeap(FILE *out, HANDLE heap) +{ + PROCESS_HEAP_ENTRY entry; + DWORD err; + + if (!HeapLock(heap)) + OutputDebugString("Can't lock the heap.\n"); + entry.lpData = 0; + fprintf(out, " address: size ovhd region\n"); + while (HeapWalk(heap, &entry)) + { + WORD flags = entry.wFlags; + + fprintf(out, "0x%.8X: 0x%.8X 0x%.2X 0x%.2X ", entry.lpData, entry.cbData, + entry.cbOverhead, entry.iRegionIndex); + if (flags & PROCESS_HEAP_REGION) + fprintf(out, "REGION committedSize=0x%.8X uncommittedSize=0x%.8X firstBlock=0x%.8X lastBlock=0x%.8X", + entry.Region.dwCommittedSize, entry.Region.dwUnCommittedSize, + entry.Region.lpFirstBlock, entry.Region.lpLastBlock); + else if (flags & PROCESS_HEAP_UNCOMMITTED_RANGE) + fprintf(out, "UNCOMMITTED"); + else if (flags & PROCESS_HEAP_ENTRY_BUSY) + { + if (flags & PROCESS_HEAP_ENTRY_DDESHARE) + fprintf(out, "DDEShare "); + if (flags & PROCESS_HEAP_ENTRY_MOVEABLE) + fprintf(out, "Moveable Block handle=0x%.8X", entry.Block.hMem); + else + fprintf(out, "Block"); + } + fprintf(out, "\n"); + } + if ((err = GetLastError()) != ERROR_NO_MORE_ITEMS) + fprintf(out, "ERROR %d iterating through the heap\n", err); + if (!HeapUnlock(heap)) + OutputDebugString("Can't unlock the heap.\n"); +} +#endif + +#if defined(DEBUG) && defined(WIN32) +static void DumpApplicationHeaps(FILE *out) +{ + HANDLE mainHeap; + HANDLE heaps[100]; + DWORD nHeaps; + PRInt32 i; + + mainHeap = GetProcessHeap(); + nHeaps = GetProcessHeaps(100, heaps); + if (nHeaps > 100) + nHeaps = 0; + fprintf(out, "%ld heaps:\n", (long) nHeaps); + for (i = 0; ichunkSize; + if (chunkSize < bytes) { + /* Too small; skip it */ + METER(meter.skippedFreeChunks++); + cpp = &cp->next; + continue; + } + + /* We have found a hunk of memory large enough to use */ + p = (PRWord*) cp; + sp = cp->segment; + cpNext = cp->next; +#ifndef IS_64 + if (dub && (((PRWord)p & (PR_BYTES_PER_DWORD-1)) == 0)) { + /* + * We are double aligning the memory and the current free + * chunk is aligned on an even boundary. Because header + * words are one word long we need to discard the first + * word of memory. + */ + p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, 1); + SET_HBIT(sp, p); + p++; + chunkSize -= PR_BYTES_PER_WORD; + bytes -= PR_BYTES_PER_WORD; + PR_ASSERT(((PRWord)p & (PR_BYTES_PER_DWORD-1)) != 0); + _pr_gcData.freeMemory -= PR_BYTES_PER_WORD; + _pr_gcData.busyMemory += PR_BYTES_PER_WORD; + } +#endif + np = (PRWord*) ((char*) p + bytes); + remainder = chunkSize - bytes; + if (remainder >= MIN_FREE_CHUNK_BYTES) { + /* The left over memory is large enough to be freed. */ + cp = (GCFreeChunk*) np; + cp->segment = sp; + cp->chunkSize = remainder; + InlineBinNumber(newbin, remainder) + if (newbin != bin) { + *cpp = (GCFreeChunk*) cpNext; /* remove */ + cp->next = bins[newbin]; /* insert */ + bins[newbin] = cp; + if (newbin < minBin) minBin = newbin; + if (newbin > maxBin) maxBin = newbin; + } else { + /* Leave it on the same list */ + cp->next = cpNext; + *cpp = (GCFreeChunk*) np; + } + } else { + /* + * The left over memory is too small to be released. Just + * leave it attached to the chunk of memory being + * returned. + */ + *cpp = cpNext; + bytes = chunkSize; + } + p[0] = MAKE_HEADER(cbix, (bytes >> PR_BYTES_PER_WORD_LOG2)); + SET_HBIT(sp, p); + _pr_gcData.freeMemory -= bytes; + _pr_gcData.busyMemory += bytes; + return p; + } + } + return 0; +} + +/* +** Allocate a piece of memory that is "big" in it's own segment. Make +** the object consume the entire segment to avoid fragmentation. When +** the object is no longer referenced, the segment is freed. +*/ +static PRWord *BigAlloc(int cbix, PRInt32 bytes, int dub) +{ + GCSeg *sp; + PRWord *p, h; + PRInt32 chunkSize; + + /* + ** If the number of bytes allocated via BigAlloc() since the last GC + ** exceeds BIG_ALLOC_GC_SIZE then do a GC Now... + */ + if (bigAllocBytes >= BIG_ALLOC_GC_SIZE) { + dogc(); + } + bigAllocBytes += bytes; + + /* Get a segment to hold this allocation */ + sp = GrowHeapExactly(bytes); + + if (sp) { + p = (PRWord*) sp->base; + chunkSize = sp->limit - sp->base; + + /* All memory is double aligned on 64 bit machines... */ +#ifndef IS_64 + if (dub && (((PRWord)p & (PR_BYTES_PER_DWORD-1)) == 0)) { + /* + ** Consume the first word of the chunk with a dummy + ** unreferenced object. + */ + p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, 1); + SET_HBIT(sp, p); + p++; + chunkSize -= PR_BYTES_PER_WORD; + _pr_gcData.freeMemory -= PR_BYTES_PER_WORD; + _pr_gcData.busyMemory += PR_BYTES_PER_WORD; + PR_ASSERT(((PRWord)p & (PR_BYTES_PER_DWORD-1)) != 0); + } +#endif + +#if defined(WIN16) + /* All memory MUST be aligned on 32bit boundaries */ + PR_ASSERT( (((PRWord)p) & (PR_BYTES_PER_WORD-1)) == 0 ); +#endif + + /* Consume the *entire* segment with a single allocation */ + h = MAKE_HEADER(cbix, (chunkSize >> PR_BYTES_PER_WORD_LOG2)); + p[0] = h; + SET_HBIT(sp, p); + _pr_gcData.freeMemory -= chunkSize; + _pr_gcData.busyMemory += chunkSize; + return p; + } + return 0; +} + +/* we disable gc allocation during low memory conditions */ +static PRBool allocationEnabled = PR_TRUE; + +PR_IMPLEMENT(void) PR_EnableAllocation(PRBool yesOrNo) +{ + allocationEnabled = yesOrNo; +} + +static void CollectorCleanup(void) { + while (collectorCleanupNeeded) { + LOCK_GC(); + collectorCleanupNeeded = 0; + UNLOCK_GC(); + if (freeSegs) { + FreeSegments(); + } + if (!WEAK_FREELIST_ISEMPTY()) { + EmptyWeakFreeList(); + } + } +} + +/******************************************************************************/ + +#ifdef GC_CHECK +static PRInt32 allocationCount; + +static void EarthShatteringKaBoom(PRInt32 whichOne) { + long* p = 0; + *p = 0; +} + +/* Check a segment of heap memory. Verify that the object memory + hasn't been overwritten (past the end at least) */ +static void CheckSegment(GCSeg* sp) { + PRWord h, tix; + PRWord *p, *lastp, *np, *limit; + + lastp = p = (PRWord *) sp->base; + limit = (PRWord *) sp->limit; + while (p < limit) { + if (IS_HBIT(sp, p)) { + char *cp, i; + GCBlockEnd* end; + PRWord bytes, requestedBytes; + + h = p[0]; + tix = GET_TYPEIX(h); + bytes = OBJ_BYTES(h); + np = (PRWord *) ((char *)p + bytes); + if (tix != FREE_MEMORY_TYPEIX) { + PRInt32 test; /* msdev get's fooled without this local */ + /* A live object is here. The last word in the object will + contain the objects requestedSize */ + end = (GCBlockEnd*)((char*)(p) + bytes - sizeof(GCBlockEnd)); + test = end->check; + if (test != PR_BLOCK_END) { + PR_ASSERT(test == PR_BLOCK_END); + } + requestedBytes = end->requestedBytes; + if (requestedBytes >= bytes) EarthShatteringKaBoom(0); + cp = (char*)(p + 1) + requestedBytes; + i = (char) 0xff; + while (cp < (char*)end) { + if (*cp != i) EarthShatteringKaBoom(1); + cp++; + i--; + } + } + lastp = p; + p = np; + } else { + /* Must be a freelist item */ + GCFreeChunk *cp = (GCFreeChunk*) p; + if ((PRInt32)cp->chunkSize < (PRInt32)sizeof(GCFreeChunk)) { + EarthShatteringKaBoom(3); + } + lastp = p; + p = (PRWord*) ((char*)p + cp->chunkSize); + } + } +} + +static void CheckHeap(void) { + GCSeg *sp = segs; + GCSeg *esp = sp + nsegs; + while (sp < esp) { + CheckSegment(sp); + sp++; + } +} + +#endif /* GC_CHECK */ + +/******************************************************************************/ + +#ifdef DEBUG +long gc_thrash = -1L; +#endif + +/* +** Allocate memory from the GC Heap. Performs garbage collections if +** memory gets tight and grows the heap as needed. May return NULL if +** memory cannot be found. +*/ +PR_IMPLEMENT(PRWord GCPTR *)PR_AllocMemory( + PRWord requestedBytes, PRInt32 tix, PRWord flags) +{ + PRWord *p; + CollectorType *ct; + PRInt32 bytes; + GCFinal *final = 0; + GCWeak *weak = 0; + int dub = flags & PR_ALLOC_DOUBLE; + PRInt32 objBytes; +#ifdef GC_STATS + PRInt64 allocTime, ldelta; +#endif + + if (!allocationEnabled) return NULL; + + PR_ASSERT(requestedBytes >= 0); + PR_ASSERT(_pr_collectorTypes[tix].flags != 0); + +#ifdef DEBUG + if (_pr_do_a_dump) { + /* + ** Collect, pause for a second (lets finalizer run), and then GC + ** again. + */ + PR_GC(); + PR_Sleep(PR_MicrosecondsToInterval(1000000L)); + PR_GC(); + PR_DumpGCHeap(_pr_dump_file, PR_TRUE); + _pr_do_a_dump = 0; + } +#endif + +#ifdef GC_STATS + allocTime = PR_Now(); +#endif + bytes = (PRInt32) requestedBytes; + + /* + ** Align bytes to a multiple of a PRWord, then add in enough space + ** to hold the header word. + ** + ** MSVC 1.52 crashed on the ff. code because of the "complex" shifting :-( + */ +#if !defined(WIN16) + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL; + bytes = (bytes + PR_BYTES_PER_WORD - 1) >> PR_BYTES_PER_WORD_LOG2; + bytes <<= PR_BYTES_PER_WORD_LOG2; + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - sizeof(PRWord)) < bytes ) return NULL; + bytes += sizeof(PRWord); +#else + /* + ** For WIN16 the shifts have been broken out into separate statements + ** to prevent the compiler from crashing... + */ + { + PRWord shiftVal; + + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL; + bytes += PR_BYTES_PER_WORD - 1L; + shiftVal = PR_BYTES_PER_WORD_LOG2; + bytes >>= shiftVal; + bytes <<= shiftVal; + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - sizeof(PRWord)) < bytes ) return NULL; + bytes += sizeof(PRWord); + } +#endif + /* + * Add in an extra word of memory for double-aligned memory. Some + * percentage of the time this will waste a word of memory (too + * bad). Howver, it makes the allocation logic much simpler and + * faster. + */ +#ifndef IS_64 + if (dub) { + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL; + bytes += PR_BYTES_PER_WORD; + } +#endif + +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + /* Bloat the allocation a bit so that we can lay down + a check pattern that we will validate */ + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - PR_BYTES_PER_WORD * 3) < bytes ) return NULL; + bytes += PR_BYTES_PER_WORD * 3; + } +#endif + +#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS) + if ((MAX_INT - sizeof(GCBlockEnd)) < bytes ) return NULL; + bytes += sizeof(GCBlockEnd); +#endif + + PR_ASSERT( bytes < MAX_ALLOC_SIZE ); + /* + ** Java can ask for objects bigger than MAX_ALLOC_SIZE, + ** but it won't get them. + */ + if (bytes >= MAX_ALLOC_SIZE) return NULL; + +#ifdef DEBUG + if (gc_thrash == -1L ? (gc_thrash = (long)PR_GetEnv("GC_THRASH")):gc_thrash) PR_GC(); +#endif + + ct = &_pr_collectorTypes[tix]; + if (ct->flags & (_GC_TYPE_FINAL|_GC_TYPE_WEAK)) { + if (0 != ct->gctype.finalize) { + /* + ** Allocate a GCFinal struct for this object in advance. Don't put + ** it on the pending list until we have allocated the object + */ + final = AllocFinalNode(); + if (!final) { + /* XXX THIS IS NOT ACCEPTABLE*/ + PR_ASSERT(0); + return 0; + } + } + if (0 != ct->gctype.getWeakLinkOffset) { + /* + ** Allocate a GCWeak struct for this object in advance. Don't put + ** it on the weak links list until we have allocated the object + */ + weak = AllocWeakNode(); + if (!weak) { + /* XXX THIS IS NOT ACCEPTABLE*/ + if (0 != final) { + FreeFinalNode(final); + } + PR_ASSERT(0); + return 0; + } + } + } + + LOCK_GC(); +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) CheckHeap(); + allocationCount++; +#endif + + /* Check for overflow of maximum size we can handle */ + if (bytes > MAX_ALLOC) goto lost; + + /* Try default allocation */ + p = ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) ? + BigAlloc(tix, bytes, dub) : BinAlloc(tix, bytes, dub); + if (0 == p) { +#ifdef GC_STATS + LL_SUB(ldelta, PR_Now(), allocTime); +#endif + /* Collect some memory */ + _GCTRACE(GC_ALLOC, ("force GC: want %d", bytes)); + dogc(); + PR_ASSERT( GC_IS_LOCKED() ); + + /* After a collection we check and see if we should grow the + ** heap. We grow the heap when the amount of memory free is less + ** than a certain percentage of the heap size. We don't check to + ** see if the grow succeeded because our fallback strategy in + ** either case is to try one more time to allocate. */ + if ((_pr_gcData.allocMemory < _pr_gcData.maxMemory) + && ((_pr_gcData.freeMemory < + ((_pr_gcData.allocMemory * MIN_FREE_THRESHOLD_AFTER_GC) / 100L)) + || (_pr_gcData.freeMemory < bytes))) { + GrowHeap(PR_MAX(bytes, segmentSize)); + } +#ifdef GC_STATS + LL_ADD(allocTime, PR_Now(), ldelta); +#endif + + /* Try again */ + p = ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) ? + BigAlloc(tix, bytes, dub) : BinAlloc(tix, bytes, dub); + if (0 == p) { + /* Well that lost big time. Memory must be pretty well fragmented */ + if (!GrowHeap(PR_MAX(bytes, segmentSize))) goto lost; + p = BinAlloc(tix, bytes, dub); + if (0 == p) goto lost; + } + } + + /* Zero out the portion of the object memory that was used by + the GCFreeChunk structure (skip the first word because it + was already overwritten by the gc header word) */ + objBytes = OBJ_BYTES(p[0]); + if (objBytes > sizeof(PRWord)) p[1] = 0; + if (objBytes > sizeof(PRWord)*2) p[2] = 0; + + if (final) { + _GCTRACE(GC_ALLOC, ("alloc 0x%x (%d) final=0x%x", + p, bytes, final)); + final->object = p; + PR_APPEND_LINK(&final->links, &_pr_finalizeableObjects); + } else { + _GCTRACE(GC_ALLOC, ("alloc 0x%x (%d)", p, bytes)); + } + if (weak) { + weak->object = p; + PR_APPEND_LINK(&weak->links, &_pr_weakLinks); + } + METER(meter.allocBytes += bytes); + METER(meter.wastedBytes += (bytes - requestedBytes)); + UNLOCK_GC(); + + if (collectorCleanupNeeded) { + CollectorCleanup(); + } + +#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS) + { + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + end->check = PR_BLOCK_END; + } +#endif +#ifdef GC_STATS + { + PRInt64 now = PR_Now(); + double delta; + PRInt32 bin; + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + + end->allocTime = allocTime; + LL_SUB(ldelta, now, allocTime); + LL_L2D(delta, ldelta); + InlineBinNumber(bin, requestedBytes); + end->bin = bin; + gcstats[bin].nallocs++; + gcstats[bin].allocTime += delta; + gcstats[bin].allocTimeVariance += delta * delta; + } +#endif +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + /* Place a pattern in the memory that was allocated that was not + requested. We will check the pattern later. */ + char* cp = (char*)(p + 1) + requestedBytes; + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + char i = (char) 0xff; + while (cp < (char*)end) { + *cp++ = i--; + } + end->requestedBytes = requestedBytes; + CheckHeap(); + } +#endif + return p + 1; + + lost: + /* Out of memory */ + UNLOCK_GC(); + if (final) { + FreeFinalNode(final); + } + if (weak) { + FreeWeakNode(weak); + } + if (collectorCleanupNeeded) { + CollectorCleanup(); + } + return 0; +} + +/* Shortcut allocator for objects that do not require finalization or + are weak objects */ +PR_IMPLEMENT(PRWord GCPTR *) +PR_AllocSimpleMemory(PRWord requestedBytes, PRInt32 tix) +{ + PRWord *p; + PRInt32 bytes; + PRInt32 objBytes; +#ifdef GC_STATS + PRInt64 allocTime, ldelta; +#endif + + if (!allocationEnabled) return NULL; + + PR_ASSERT(requestedBytes >= 0); + PR_ASSERT(_pr_collectorTypes[tix].flags != 0); + +#ifdef DEBUG + if (_pr_do_a_dump) { + /* + ** Collect, pause for a second (lets finalizer run), and then GC + ** again. + */ + PR_GC(); + PR_Sleep(PR_MicrosecondsToInterval(1000000L)); + PR_GC(); + PR_DumpGCHeap(_pr_dump_file, PR_TRUE); + _pr_do_a_dump = 0; + } +#endif + +#ifdef GC_STATS + allocTime = PR_NowMS(); +#endif + bytes = (PRInt32) requestedBytes; + + /* + ** Align bytes to a multiple of a PRWord, then add in enough space + ** to hold the header word. + ** + ** MSVC 1.52 crashed on the ff. code because of the "complex" shifting :-( + */ +#if !defined(WIN16) + bytes = (bytes + PR_BYTES_PER_WORD - 1) >> PR_BYTES_PER_WORD_LOG2; + bytes <<= PR_BYTES_PER_WORD_LOG2; + bytes += sizeof(PRWord); +#else + /* + ** For WIN16 the shifts have been broken out into separate statements + ** to prevent the compiler from crashing... + */ + { + PRWord shiftVal; + + bytes += PR_BYTES_PER_WORD - 1L; + shiftVal = PR_BYTES_PER_WORD_LOG2; + bytes >>= shiftVal; + bytes <<= shiftVal; + bytes += sizeof(PRWord); + } +#endif + + /* + * Add in an extra word of memory for double-aligned memory. Some + * percentage of the time this will waste a word of memory (too + * bad). Howver, it makes the allocation logic much simpler and + * faster. + */ +#ifndef IS_64 + bytes += PR_BYTES_PER_WORD; +#endif + +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + /* Bloat the allocation a bit so that we can lay down + a check pattern that we will validate */ + bytes += PR_BYTES_PER_WORD * 2; + } +#endif + +#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS) + bytes += sizeof(GCBlockEnd); +#endif + +#if defined(WIN16) + PR_ASSERT( bytes < MAX_ALLOC_SIZE ); +#endif + /* Java can ask for objects bigger than 4M, but it won't get them */ + /* + * This check was added because there is a fundamental limit of + * the size field maintained by the gc code. Going over the 4M + * limit caused some bits to roll over into another bit field, + * violating the max segment size and causing a bug. + */ + if (bytes >= MAX_ALLOC_SIZE) { + return NULL; + } +#ifdef DEBUG + if (gc_thrash == -1L + ? (gc_thrash = (long)PR_GetEnv("GC_THRASH")) + : gc_thrash) { + PR_GC(); + } +#endif + + LOCK_GC(); +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + CheckHeap(); + } + allocationCount++; +#endif + + /* Try default allocation */ + if ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) { + p = BigAlloc(tix, bytes, 1); + } else { + p = BinAlloc(tix, bytes, 1); + } + if (0 == p) { +#ifdef GC_STATS + LL_SUB(ldelta, PR_Now(), allocTime); +#endif + /* Collect some memory */ + _GCTRACE(GC_ALLOC, ("force GC: want %d", bytes)); + dogc(); + PR_ASSERT( GC_IS_LOCKED() ); + + /* After a collection we check and see if we should grow the + heap. We grow the heap when the amount of memory free is less + than a certain percentage of the heap size. We don't check to + see if the grow succeeded because our fallback strategy in + either case is to try one more time to allocate. */ + if ((_pr_gcData.allocMemory < _pr_gcData.maxMemory) && + (_pr_gcData.freeMemory < + ((_pr_gcData.allocMemory * MIN_FREE_THRESHOLD_AFTER_GC) / 100L))) { + GrowHeap(PR_MAX(bytes, segmentSize)); + } +#ifdef GC_STATS + LL_ADD(allocTime, PR_Now(), ldelta); +#endif + + /* Try one last time */ + if ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) { + p = BigAlloc(tix, bytes, 1); + } else { + p = BinAlloc(tix, bytes, 1); + } + if (0 == p) { + /* Well that lost big time. Memory must be pretty well fragmented */ + if (!GrowHeap(PR_MAX(bytes, segmentSize))) { + goto lost; + } + p = BinAlloc(tix, bytes, 1); + if (0 == p) goto lost; + } + } + + /* Zero out the portion of the object memory that was used by + the GCFreeChunk structure (skip the first word because it + was already overwritten by the gc header word) */ + objBytes = OBJ_BYTES(p[0]); + if (objBytes > sizeof(PRWord)) p[1] = 0; + if (objBytes > sizeof(PRWord)*2) p[2] = 0; + + METER(meter.allocBytes += bytes); + METER(meter.wastedBytes += (bytes - requestedBytes)); + UNLOCK_GC(); + + if (collectorCleanupNeeded) { + CollectorCleanup(); + } + +#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS) + { + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + end->check = PR_BLOCK_END; + } +#endif +#ifdef GC_STATS + { + PRInt64 now = PR_Now(); + double delta; + PRInt32 bin; + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + + end->allocTime = allocTime; + LL_SUB(ldelta, now, allocTime); + LL_L2D(delta, ldelta); + InlineBinNumber(bin, requestedBytes); + end->bin = bin; + gcstats[bin].nallocs++; + gcstats[bin].allocTime += delta; + gcstats[bin].allocTimeVariance += delta * delta; + } +#endif +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + /* Place a pattern in the memory that was allocated that was not + requested. We will check the pattern later. */ + char* cp = (char*)(p + 1) + requestedBytes; + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + char i = (char) 0xff; + while (cp < (char*)end) { + *cp++ = i--; + } + end->requestedBytes = requestedBytes; + CheckHeap(); + } +#endif + return p + 1; + + lost: + /* Out of memory */ + UNLOCK_GC(); + if (collectorCleanupNeeded) { + CollectorCleanup(); + } + return 0; +} + +/************************************************************************/ + +PR_IMPLEMENT(PRWord) PR_GetObjectHeader(void *ptr) { + GCSeg *sp; + PRWord *h; + + if (ptr == 0) return 0; + sp = InHeap(ptr); + if (sp == 0) return 0; + h = (PRWord*)FindObject(sp, (PRWord*)ptr); + return GC_GET_USER_BITS(h[0]); +} + +PR_IMPLEMENT(PRWord) PR_SetObjectHeader(void *ptr, PRWord newUserBits) { + GCSeg *sp; + PRWord *h, rv; + + if (ptr == 0) return 0; + sp = InHeap(ptr); + if (sp == 0) return 0; + h = (PRWord*)FindObject(sp, (PRWord*)ptr); + rv = GC_GET_USER_BITS(h[0]); + h[0] = (h[0] & ~GC_USER_BITS) | + ((newUserBits << GC_USER_BITS_SHIFT) & GC_USER_BITS); + return rv; +} + +PR_IMPLEMENT(void) PR_InitGC( + PRWord flags, PRInt32 initialHeapSize, PRInt32 segSize, PRThreadScope scope) +{ + static char firstTime = 1; + + if (!firstTime) return; + firstTime = 0; + + _pr_msgc_lm = PR_NewLogModule("msgc"); + _pr_pageShift = PR_GetPageShift(); + _pr_pageSize = PR_GetPageSize(); + +#if defined(WIN16) + PR_ASSERT( initialHeapSize < MAX_ALLOC_SIZE ); +#endif + + /* Setup initial heap size and initial segment size */ + if (0 != segSize) segmentSize = segSize; +#ifdef DEBUG + GC = PR_NewLogModule("GC"); + { + char *ev = PR_GetEnv("GC_SEGMENT_SIZE"); + if (ev && ev[0]) { + PRInt32 newSegmentSize = atoi(ev); + if (0 != newSegmentSize) segmentSize = newSegmentSize; + } + ev = PR_GetEnv("GC_INITIAL_HEAP_SIZE"); + if (ev && ev[0]) { + PRInt32 newInitialHeapSize = atoi(ev); + if (0 != newInitialHeapSize) initialHeapSize = newInitialHeapSize; + } + ev = PR_GetEnv("GC_FLAGS"); + if (ev && ev[0]) { + flags |= atoi(ev); + } +#ifdef GCMETER + ev = PR_GetEnv("GC_METER"); + if (ev && ev[0]) { + _pr_gcMeter = atoi(ev); + } +#endif + } +#endif + if (0 == initialHeapSize) initialHeapSize = segmentSize; + if (initialHeapSize < segmentSize) initialHeapSize = segmentSize; + + _pr_gcData.maxMemory = MAX_SEGS * segmentSize; + _pr_gcData.liveBlock = ProcessRootBlock; + _pr_gcData.livePointer = ProcessRootPointer; + _pr_gcData.processRootBlock = ProcessRootBlock; + _pr_gcData.processRootPointer = ProcessRootPointer; + _pr_gcData.dumpOutput = NULL; + + PR_INIT_CLIST(&_pr_finalizeableObjects); + PR_INIT_CLIST(&_pr_finalQueue); + _PR_InitGC(flags); + + /* Create finalizer thread */ + _PR_CreateFinalizer(scope); + + /* Allocate the initial segment for the heap */ + minBin = 31; + maxBin = 0; + GrowHeap(initialHeapSize); + PR_RegisterRootFinder(ScanWeakFreeList, "scan weak free list", 0); +} + +#if defined(WIN16) +/* +** For WIN16 the GC_IN_HEAP() macro must call the private InHeap function. +** This public wrapper function makes this possible... +*/ +PR_IMPLEMENT(PRBool) +PR_GC_In_Heap(void *object) +{ + return InHeap( object ) != NULL; +} +#endif + + +/** Added by Vishy for sanity checking a few GC structures **/ +/** Can use SanityCheckGC to debug corrupted GC Heap situations **/ + +#ifdef DEBUG + +static int SegmentOverlaps(int i, int j) +{ + return + (((segs[i].limit > segs[j].base) && (segs[i].base < segs[j].base)) || + ((segs[j].limit > segs[i].base) && (segs[j].base < segs[i].base))); +} + +static void NoSegmentOverlaps(void) +{ + int i,j; + + for (i = 0; i < nsegs; i++) + for (j = i+1 ; j < nsegs ; j++) + PR_ASSERT(!SegmentOverlaps(i,j)); +} + +static void SegInfoCheck(void) +{ + int i; + for (i = 0 ; i < nsegs ; i++) + PR_ASSERT((segs[i].info->hbits) && + (segs[i].info->hbits == segs[i].hbits) && + (segs[i].info->base == segs[i].base) && + (segs[i].info->limit == segs[i].limit)); +} + +static void SanityCheckGC() +{ + NoSegmentOverlaps(); + SegInfoCheck(); +} + +#endif + +#if defined(DEBUG) && defined(WIN32) + +extern void *baseaddr; +extern void *lastaddr; + +PR_IMPLEMENT(void) +PR_PrintGCStats(void) +{ + long reportedSegSpace = _pr_gcData.busyMemory + _pr_gcData.freeMemory; + char* msg; + long largeCount = 0, largeSize = 0; + long segCount = 0, segSize = 0; + long freeCount = 0, freeSize = 0; + GCSeg *sp, *esp; + GCSegInfo* si; + + LOCK_GC(); + + sp = segs; + esp = sp + nsegs; + while (sp < esp) { + long size = sp->info->limit - sp->info->base; + segCount++; + segSize += size; + if (sp->info->fromMalloc) { + largeCount++; + largeSize += size; + } + sp++; + } + + si = freeSegs; + while (si != NULL) { + long size = si->limit - si->base; + freeCount++; + freeSize += size; + si = si->next; + } + + msg = PR_smprintf("\ +# GC Stats:\n\ +# vm space:\n\ +# range: %ld - %ld\n\ +# size: %ld\n\ +# segments:\n\ +# range: %ld - %ld\n\ +# count: %ld (reported: %ld)\n\ +# size: %ld (reported: %ld)\n\ +# free count: %ld\n\ +# free size: %ld\n\ +# busy objs: %ld (%ld%%)\n\ +# free objs: %ld (%ld%%)\n\ +# large blocks:\n\ +# count: %ld\n\ +# total size: %ld (%ld%%)\n\ +# avg size: %ld\n\ +", + /* vm space */ + (long)baseaddr, (long)lastaddr, + (long)lastaddr - (long)baseaddr, + /* segments */ + _pr_gcData.lowSeg, _pr_gcData.highSeg, + segCount, nsegs, + segSize, reportedSegSpace, + freeCount, + freeSize, + _pr_gcData.busyMemory, + (_pr_gcData.busyMemory * 100 / reportedSegSpace), + _pr_gcData.freeMemory, + (_pr_gcData.freeMemory * 100 / reportedSegSpace), + /* large blocks */ + largeCount, + largeSize, (largeSize * 100 / reportedSegSpace), + (largeCount ? largeSize / largeCount : 0) + ); + UNLOCK_GC(); + fprintf(stderr, msg); + OutputDebugString(msg); + PR_smprintf_free(msg); +#ifdef GC_STATS + PR_PrintGCAllocStats(); +#endif +} +#endif + +PR_IMPLEMENT(void) +PR_DumpToFile(char* filename, char* msg, PRFileDumper dump, PRBool detailed) +{ + FILE *out; + OutputDebugString(msg); + out = fopen(filename, "a"); + if (!out) { + char buf[64]; + PR_ASSERT(strlen(filename) < sizeof(buf) - 16); + PR_snprintf(buf, sizeof(buf), "Can't open \"%s\"\n", + filename); + OutputDebugString(buf); + } + else + { + struct tm *newtime; + time_t aclock; + int i; + + time(&aclock); + newtime = localtime(&aclock); + fprintf(out, "%s on %s\n", msg, asctime(newtime)); /* Print current time */ + dump(out, detailed); + fprintf(out, "\n\n"); + for (i = 0; i < 80; i++) + fprintf(out, "="); + fprintf(out, "\n\n"); + fclose(out); + } + OutputDebugString(" done\n"); +} + diff --git a/nsprpub/lib/msgc/src/unixgc.c b/nsprpub/lib/msgc/src/unixgc.c new file mode 100644 index 00000000000..cea4225ebee --- /dev/null +++ b/nsprpub/lib/msgc/src/unixgc.c @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" +#include "gcint.h" + +#include +#include +#include +#include +#include + +#define _PR_GC_VMBASE 0x40000000 + +#if defined(SOLARIS) +#define _MD_MMAP_FLAGS MAP_SHARED +#elif defined(RELIANTUNIX) +#define _MD_MMAP_FLAGS MAP_PRIVATE|MAP_FIXED +#else +#define _MD_MMAP_FLAGS MAP_PRIVATE +#endif + +static PRInt32 zero_fd = -1; +static PRLock *zero_fd_lock = NULL; + +void _MD_InitGC(void) +{ +#ifdef DEBUG + /* + * Disable using mmap(2) if NSPR_NO_MMAP is set + */ + if (getenv("NSPR_NO_MMAP")) { + zero_fd = -2; + return; + } +#endif + zero_fd = open("/dev/zero",O_RDWR , 0); + zero_fd_lock = PR_NewLock(); +} + +/* This static variable is used by _MD_GrowGCHeap and _MD_ExtendGCHeap */ +static void *lastaddr = (void*) _PR_GC_VMBASE; + +void *_MD_GrowGCHeap(PRUint32 *sizep) +{ + void *addr; + PRUint32 size; + + size = *sizep; + + PR_Lock(zero_fd_lock); + if (zero_fd < 0) { + goto mmap_loses; + } + + /* Extend the mapping */ + addr = mmap(lastaddr, size, PROT_READ|PROT_WRITE|PROT_EXEC, + _MD_MMAP_FLAGS, + zero_fd, 0); + if (addr == (void*)-1) { + zero_fd = -1; + goto mmap_loses; + } + lastaddr = ((char*)addr + size); +#ifdef DEBUG + PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, + ("GC: heap extends from %08x to %08x\n", + _PR_GC_VMBASE, + _PR_GC_VMBASE + (char*)lastaddr - (char*)_PR_GC_VMBASE)); +#endif + PR_Unlock(zero_fd_lock); + return addr; + +mmap_loses: + PR_Unlock(zero_fd_lock); + return PR_MALLOC(size); +} + +/* XXX - This is disabled. MAP_FIXED just does not work. */ +#if 0 +PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) { + PRBool rv = PR_FALSE; + void* addr; + PRInt32 allocSize = newSize - oldSize; + + PR_Lock(zero_fd_lock); + addr = mmap(base + oldSize, allocSize, PROT_READ|PROT_WRITE|PROT_EXEC, + _MD_MMAP_FLAGS | MAP_FIXED, zero_fd, 0); + if (addr == (void*)-1) { + goto loser; + } + if (addr != (void*) (base + oldSize)) { + munmap(base + oldSize, allocSize); + goto loser; + } + lastaddr = ((char*)base + newSize); + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, + ("GC: heap now extends from %p to %p", + base, base + newSize)); + rv = PR_TRUE; + +loser: + PR_Unlock(zero_fd_lock); + return rv; +} +#else +PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) { + return PR_FALSE; +} +#endif + +void _MD_FreeGCSegment(void *base, PRInt32 len) +{ + if (zero_fd < 0) { + PR_DELETE(base); + } else { + (void) munmap(base, len); + } +} diff --git a/nsprpub/lib/msgc/src/win16gc.c b/nsprpub/lib/msgc/src/win16gc.c new file mode 100644 index 00000000000..0af0079b317 --- /dev/null +++ b/nsprpub/lib/msgc/src/win16gc.c @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#if defined(WIN16) +#include +#endif +#include "prtypes.h" +#include + +#define MAX_SEGMENT_SIZE (65536l - 4096l) + +/************************************************************************/ +/* +** Machine dependent GC Heap management routines: +** _MD_GrowGCHeap +*/ +/************************************************************************/ + +void _MD_InitGC(void) {} + +extern void * +_MD_GrowGCHeap(PRUint32 *sizep) +{ + void *addr; + + if( *sizep > MAX_SEGMENT_SIZE ) { + *sizep = MAX_SEGMENT_SIZE; + } + + addr = malloc((size_t)*sizep); + return addr; +} + +HINSTANCE _pr_hInstance; + +int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpszCmdLine ) +{ + _pr_hInstance = hInst; + return TRUE; +} + + diff --git a/nsprpub/lib/msgc/src/win32gc.c b/nsprpub/lib/msgc/src/win32gc.c new file mode 100644 index 00000000000..eec83774eb1 --- /dev/null +++ b/nsprpub/lib/msgc/src/win32gc.c @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * GC related routines + * + */ +#include +#include "prlog.h" + +extern PRLogModuleInfo* _pr_msgc_lm; + +#define GC_VMBASE 0x40000000 +#define GC_VMLIMIT 0x00FFFFFF + +/************************************************************************/ +/* +** Machine dependent GC Heap management routines: +** _MD_GrowGCHeap +*/ +/************************************************************************/ + +void *baseaddr = (void*) GC_VMBASE; +void *lastaddr = (void*) GC_VMBASE; + +void _MD_InitGC() {} + +void *_MD_GrowGCHeap(PRUint32 *sizep) +{ + void *addr; + size_t size; + + /* Reserve a block of memory for the GC */ + if( lastaddr == baseaddr ) { + addr = VirtualAlloc( (void *)GC_VMBASE, GC_VMLIMIT, MEM_RESERVE, PAGE_READWRITE ); + + /* + ** If the GC_VMBASE address is already mapped, then let the OS choose a + ** base address that is available... + */ + if (addr == NULL) { + addr = VirtualAlloc( NULL, GC_VMLIMIT, MEM_RESERVE, PAGE_READWRITE ); + + baseaddr = lastaddr = addr; + if (addr == NULL) { + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: unable to allocate heap: LastError=%ld", + GetLastError())); + return 0; + } + } + } + size = *sizep; + + /* Extend the mapping */ + addr = VirtualAlloc( lastaddr, size, MEM_COMMIT, PAGE_READWRITE ); + if (addr == NULL) { + return 0; + } + + lastaddr = ((char*)addr + size); + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, + ("GC: heap extends from %08x to %08x", + baseaddr, (long)baseaddr + (char*)lastaddr - (char*)baseaddr)); + + return addr; +} + +PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) { + void* addr; + + addr = VirtualAlloc( base + oldSize, newSize - oldSize, + MEM_COMMIT, PAGE_READWRITE ); + if (NULL == addr) { + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: unable to extend heap: LastError=%ld", + GetLastError())); + return PR_FALSE; + } + if (base + oldSize != (char*)addr) { + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: segment extension returned %x instead of %x", + addr, base + oldSize)); + VirtualFree(addr, newSize - oldSize, MEM_DECOMMIT); + return PR_FALSE; + } + lastaddr = base + newSize; + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, + ("GC: heap now extends from %p to %p", + base, base + newSize)); + return PR_TRUE; +} + + +void _MD_FreeGCSegment(void *base, PRInt32 len) +{ + (void)VirtualFree(base, 0, MEM_RELEASE); +} diff --git a/nsprpub/lib/msgc/tests/.cvsignore b/nsprpub/lib/msgc/tests/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/msgc/tests/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/msgc/tests/Makefile.in b/nsprpub/lib/msgc/tests/Makefile.in new file mode 100644 index 00000000000..b447f76826d --- /dev/null +++ b/nsprpub/lib/msgc/tests/Makefile.in @@ -0,0 +1,314 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +W16STDIO = $(MOD_DEPTH)/pr/src/md/windows/$(OBJDIR)/w16stdio.$(OBJ_SUFFIX) +endif + +ifeq ($(OS_TARGET), OS2) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CSRCS = gc1.c thrashgc.c + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +NSPR_VERSION = $(MOD_MAJOR_VERSION) +GC_VERSION = $(MOD_MAJOR_VERSION) +LIBPR = -lnspr$(NSPR_VERSION) +LIBPLC = -lplc$(NSPR_VERSION) +LIBGC = -lmsgc$(GC_VERSION) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(NSPR_VERSION).lib + LIBPLC = $(dist_libdir)/plc$(NSPR_VERSION).lib + LIBGC= $(dist_libdir)/msgc$(GC_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -INCREMENTAL:NO + LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).$(LIB_SUFFIX) + LIBPLC = $(dist_libdir)/libplc$(NSPR_VERSION).$(LIB_SUFFIX) + LIBGC= $(dist_libdir)/libmsgc$(GC_VERSION).$(LIB_SUFFIX) +endif +endif + +ifeq ($(OS_ARCH),OS2) +ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO + LIBPR = $(dist_libdir)/nspr$(NSPR_VERSION).lib + LIBPLC = $(dist_libdir)/plc$(NSPR_VERSION).lib + LIBGC= $(dist_libdir)/msgc$(GC_VERSION).lib +else + LDOPTS += -Zomf -Zlinker /PM:VIO +endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), IRIX) +LDOPTS += -rpath $(PWD)/$(dist_libdir) -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 + +endif + +ifeq ($(OS_ARCH), OSF1) +# 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_libdir)/libnspr$(NSPR_VERSION).a + LIBPLC = $(dist_libdir)/libplc$(NSPR_VERSION).a + LIBGC = $(dist_libdir)/libmsgc$(GC_VERSION).a + EXTRA_LIBS = -lc_r +else + LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif +endif + +ifeq ($(OS_ARCH), HP-UX) +LDOPTS += -z -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) +LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib +ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) +LIBPR = -lnspr$(NSPR_VERSION)_shr +LIBPLC = -lplc$(NSPR_VERSION)_shr +LIBGC = -lmsgc$(GC_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_libdir) +else +LDOPTS += -R $(PWD)/$(dist_libdir) +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 +endif # SunOS + +ifeq ($(OS_ARCH),NEC) +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_libdir) +endif + +ifeq ($(OS_ARCH), NCR) +# XXX: We see some strange problems when we link with libnspr.so. +# So for now we use static libraries on NCR. The shared library +# stuff below is commented out. +LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).a +LIBPLC = $(dist_libdir)/libplc$(NSPR_VERSION).a +LIBGC = $(dist_libdir)/libmsgc$(GC_VERSION).a +EXTRA_LIBS = -lsocket -lnsl -ldl + +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +#EXTRA_LIBS = -lsocket -lnsl +# 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_libdir) +endif + +ifeq ($(OS_ARCH), Linux) +ifeq ($(OS_RELEASE), 1.2) +EXTRA_LIBS = -ldl +endif +endif + +ifeq ($(OS_ARCH), SCOOS) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# 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_libdir) +endif + +ifeq ($(OS_ARCH),SINIX) +EXTRA_LIBS = -lsocket -lnsl -lresolv -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_libdir) +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH),BSD_OS) +EXTRA_LIBS = -ldl +endif + +ifeq ($(OS_ARCH),DGUX) +EXTRA_LIBS = -lsocket -lnsl -ldl +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(NSPR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo name $@ >>w16link + echo option map >>w16link +# echo option CASEEXACT >>w16link + echo option stack=16K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo file >>w16link + echo $< , >>w16link + echo $(W16STDIO) >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPLC), >>w16link + echo $(LIBGC), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) wsock32.lib -out:$@ +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) $(OS_LIBS) $(EXTRA_LIBS) -o $@ +else + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBGC) $(LIBPLC) $(LIBPR) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) diff --git a/nsprpub/lib/msgc/tests/gc1.c b/nsprpub/lib/msgc/tests/gc1.c new file mode 100644 index 00000000000..d6846235ba4 --- /dev/null +++ b/nsprpub/lib/msgc/tests/gc1.c @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prgc.h" +#include "prinit.h" +#include "prmon.h" +#include "prinrval.h" +#ifndef XP_MAC +#include "private/pprthred.h" +#else +#include "pprthred.h" +#endif + +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static PRMonitor *mon; +static PRInt32 threads, waiting, iterations; +static PRInt32 scanCount, finalizeCount, freeCount; + +PRIntn failed_already=0; +PRIntn debug_mode; + + +typedef struct Array { + PRUintn size; + void *body[1]; +} Array; + +int arrayTypeIndex; + +static void PR_CALLBACK ScanArray(void *a) +{ +/* printf ("In ScanArray a = %X size = %d \n", a, a->size); */ + scanCount++; +} + +static void PR_CALLBACK FinalizeArray(void *a) +{ +/* printf ("In FinalizeArray a = %X size = %d \n", a, a->size); */ + finalizeCount++; +} + +static void PR_CALLBACK FreeArray(void *a) +{ +/* printf ("In FreeArray\n"); */ + freeCount++; +} + +static Array *NewArray(PRUintn size) +{ + Array *a; + + a = (Array *)PR_AllocMemory(sizeof(Array) + size*sizeof(void*) - 1*sizeof(void*), + arrayTypeIndex, PR_ALLOC_CLEAN); + +/* printf ("In NewArray a = %X \n", a); */ + + if (a) + a->size = size; + return a; +} + +GCType arrayType = { + ScanArray, + FinalizeArray, + 0, + 0, + FreeArray, + 0 +}; + +static void Initialize(void) +{ + PR_InitGC(0, 0, 0, PR_GLOBAL_THREAD); + arrayTypeIndex = PR_RegisterType(&arrayType); +} + +static void PR_CALLBACK AllocateLikeMad(void *arg) +{ + Array *prev; + PRInt32 i; + PRInt32 count; + + count = (PRInt32)arg; + prev = 0; + for (i = 0; i < count; i++) { + Array *leak = NewArray(i & 511); + if ((i & 1023) == 0) { + prev = 0; /* forget */ + } else { + if (i & 1) { + prev = leak; /* remember */ + } + } + } + PR_EnterMonitor(mon); + waiting++; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +int main(int argc, char **argv) +{ + PRIntervalTime start, stop, usec; + double d; + PRIntn i, totalIterations; + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:"); + + threads = 10; + iterations = 100; + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) { + fprintf(stderr, "Invalid command-line option\n"); + exit(1); + } + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 't': /* number of threads */ + threads = atoi(opt->value); + break; + case 'c': /* iteration count */ + iterations = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + fprintf(stderr, "t is %ld, i is %ld\n", (long) threads, (long) iterations); + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 5); + PR_STDIO_INIT(); + Initialize(); + +#ifdef XP_MAC + SetupMacPrintfLog("gc1.log"); + debug_mode = 1; +#endif + + /* Spin all of the allocator threads and then wait for them to exit */ + start = PR_IntervalNow(); + mon = PR_NewMonitor(); + PR_EnterMonitor(mon); + waiting = 0; + for (i = 0; i < threads; i++) { + (void) PR_CreateThreadGCAble(PR_USER_THREAD, + AllocateLikeMad, (void*)iterations, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + } + while (waiting != threads) { + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon); + + PR_GC(); + PR_ForceFinalize(); + + totalIterations = iterations * threads; +/* + if (scanCount != totalIterations) + printf ("scanCount discrepancy scanCount = %d totalIterations = %d \n", + scanCount, totalIterations); + if (freeCount != totalIterations) + printf ("freeCount discrepancy freeCount = %d totalIterations = %d \n", + freeCount, totalIterations); + if ((finalizeCount != totalIterations) && (finalizeCount != (totalIterations-1))) + printf ("finalizeCount discrepancy finalizeCount = %d totalIterations = %d \n", + finalizeCount,totalIterations); +*/ + + stop = PR_IntervalNow(); + + usec = stop = stop - start; + d = (double)usec; + + if (debug_mode) printf("%40s: %6.2f usec\n", "GC allocation", d / (iterations * threads)); + else { + if (d == 0.0) failed_already = PR_TRUE; + + } + + PR_Cleanup(); + if(failed_already) + { + printf("FAIL\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } +} diff --git a/nsprpub/lib/msgc/tests/thrashgc.c b/nsprpub/lib/msgc/tests/thrashgc.c new file mode 100644 index 00000000000..9d49ec19f30 --- /dev/null +++ b/nsprpub/lib/msgc/tests/thrashgc.c @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** Name: thrashgc +** +** Description: test garbace collection functions. +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +#include "prthread.h" +#include "prgc.h" +#include "prprf.h" +#include "prinrval.h" +#include "prlock.h" +#include "prinit.h" +#include "prcvar.h" + +#ifndef XP_MAC +#include "private/pprthred.h" +#else +#include "pprthred.h" +#endif + +#include +#include +#include + + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + +static char* progname; +static PRInt32 loops = 1000; +static int tix1, tix2, tix3; +static GCInfo* gcInfo; +static PRLock* stderrLock; + +typedef struct Type1 Type1; +typedef struct Type2 Type2; + +struct Type1 { + Type2* atwo; + Type1* next; +}; + +struct Type2 { + void* buf; +}; + +static void PR_CALLBACK ScanType1(void *obj) { + gcInfo->livePointer(((Type1 *)obj)->atwo); + gcInfo->livePointer(((Type1 *)obj)->next); +} + +static void PR_CALLBACK ScanType2(void *obj) { + gcInfo->livePointer(((Type2 *)obj)->buf); +} + +static GCType type1 = { + ScanType1 +}; + +static GCType type2 = { + ScanType2 +/* (void (*)(void*)) ScanType2 */ +}; + +static GCType type3 = { + 0 +}; + +Type1* NewType1(void) { + Type1* p = (Type1*) PR_AllocMemory(sizeof(Type1), tix1, PR_ALLOC_DOUBLE); + PR_ASSERT(p != NULL); + return p; +} + +Type2* NewType2(void) { + Type2* p = (Type2*) PR_AllocMemory(sizeof(Type2), tix2, PR_ALLOC_DOUBLE); + PR_ASSERT(p != NULL); + return p; +} + +void* NewBuffer(PRInt32 size) { + void* p = PR_AllocMemory(size, tix3, PR_ALLOC_DOUBLE); + PR_ASSERT(p != NULL); + return p; +} + +/* Allocate alot of garbage */ +static void PR_CALLBACK AllocStuff(void *unused) { + PRInt32 i; + void* danglingRefs[50]; + PRIntervalTime start, end; + char msg[100]; + + start = PR_IntervalNow(); + for (i = 0; i < loops; i++) { + void* p; + if (i & 1) { + Type1* t1 = NewType1(); + t1->atwo = NewType2(); + t1->next = NewType1(); + t1->atwo->buf = NewBuffer(100); + p = t1; + } else { + Type2* t2 = NewType2(); + t2->buf = NewBuffer(i & 16383); + p = t2; + } + if ((i % 10) == 0) { + memmove(&danglingRefs[0], &danglingRefs[1], 49*sizeof(void*)); + danglingRefs[49] = p; + } + } + end = PR_IntervalNow(); + if (debug_mode) PR_snprintf(msg, sizeof(msg), "Thread %p: %ld allocations took %ld ms", + PR_GetCurrentThread(), loops, + PR_IntervalToMilliseconds((PRIntervalTime) (end - start))); + PR_Lock(stderrLock); +#ifndef XP_MAC + fprintf(stderr, "%s\n", msg); +#else + if (debug_mode) printf("%s\n", msg); +#endif + PR_Unlock(stderrLock); + } + +static void usage(char *progname) { +#ifndef XP_MAC + fprintf(stderr, "Usage: %s [-t threads] [-l loops]\n", progname); +#else + printf("Usage: %s [-t threads] [-l loops]\n", progname); +#endif + exit(-1); +} + +static int realMain(int argc, char **argv, char *notused) { + int i; + int threads = 0; + +#ifndef XP_MAC + progname = strrchr(argv[0], '/'); + if (progname == 0) progname = argv[0]; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-t") == 0) { + if (i == argc - 1) { + usage(progname); + } + threads = atoi(argv[++i]); + if (threads < 0) threads = 0; + if (threads > 10000) threads = 10000; + continue; + } + if (strcmp(argv[i], "-l") == 0) { + if (i == argc - 1) { + usage(progname); + } + loops = atoi(argv[++i]); + continue; + } + usage(progname); + } +#else + threads = 50; +#endif + + for (i = 0; i < threads; i++) { + PRThread* thread; + + /* XXXXX */ + thread = PR_CreateThreadGCAble(PR_USER_THREAD, /* thread type */ + AllocStuff, /* start function */ + NULL, /* arg */ + PR_PRIORITY_NORMAL, /* priority */ + PR_LOCAL_THREAD, /* thread scope */ + PR_UNJOINABLE_THREAD, /* thread state */ + 0); /* stack size */ + if (thread == 0) { +#ifndef XP_MAC + fprintf(stderr, "%s: no more threads (only %d were created)\n", + progname, i); +#else + printf("%s: no more threads (only %d were created)\n", + progname, i); +#endif + break; + } + } + AllocStuff(NULL); + return 0; +} + +static int padMain(int argc, char **argv) { + char pad[512]; + return realMain(argc, argv, pad); +} + +int main(int argc, char **argv) { + int rv; + + debug_mode = 1; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_SetThreadGCAble(); + +#ifdef XP_MAC + SetupMacPrintfLog("thrashgc.log"); + debug_mode = 1; +#endif + + PR_InitGC(0, 0, 0, PR_GLOBAL_THREAD); + PR_STDIO_INIT(); + stderrLock = PR_NewLock(); + tix1 = PR_RegisterType(&type1); + tix2 = PR_RegisterType(&type2); + tix3 = PR_RegisterType(&type3); + gcInfo = PR_GetGCInfo(); + rv = padMain(argc, argv); + printf("PASS\n"); + PR_Cleanup(); + return rv; +} diff --git a/nsprpub/lib/prstreams/.cvsignore b/nsprpub/lib/prstreams/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/prstreams/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/prstreams/Makefile.in b/nsprpub/lib/prstreams/Makefile.in new file mode 100644 index 00000000000..a29af95d709 --- /dev/null +++ b/nsprpub/lib/prstreams/Makefile.in @@ -0,0 +1,206 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) + ifeq ($(OS_RELEASE),4.1.3_U1) + OPTIMIZER = + else + # The C++ compiler in Workshop 5.0 uses standard + # iostreams as default. -library=iostream will + # allow Workshop 5.0 to work with classic iostreams. + ifndef NS_USE_GCC + CCC_VERSION := $(shell $(CCC) -V 2>&1) + ifneq (,$(findstring 5.0,$(CCC_VERSION))) + CCC_ONLY_FLAGS += -library=iostream + endif + endif + endif +endif + +ifeq ($(OS_ARCH), IRIX) + ifneq ($(OS_RELEASE),5.3) + CCC_ONLY_FLAGS += -exceptions + endif +endif + +ifeq ($(OS_ARCH), BeOS) + CFLAGS += -frtti -fexceptions +endif + +INCLUDES = -I$(dist_includedir) + +HEADERS = $(wildcard $(srcdir)/*.h) + +CSRCS = \ + plvrsion.c \ + $(NULL) + +CXXSRCS = \ + prstrms.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX)) $(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +ifeq ($(OS_ARCH), WINNT) + RES=$(OBJDIR)/prstrms.res + RESNAME=prstrms.rc + OS_LIBS = user32.lib +else + ifeq ($(OS_ARCH),OS2) + ifneq ($(MOZ_OS2_TOOLS),VACPP) + OS_LIBS = -lstdcpp + endif + else + ifeq ($(OS_ARCH), AIX) + ifeq ($(OS_RELEASE), 4.1) + ifeq ($(CLASSIC_NSPR),1) + OS_LIBS += -lC -lc + else + OS_LIBS += -lC_r -lc_r + endif + else + # makeC++SharedLib(_r) is in either /usr/lpp/xlC/bin + # or /usr/ibmcxx/bin. + ifeq ($(CLASSIC_NSPR),1) + MKSHLIB = makeC++SharedLib -p 0 + else + MKSHLIB = makeC++SharedLib_r -p 0 + endif + OS_LIBS += -ldl + endif + endif + endif +endif + +ifeq ($(OS_ARCH),BeOS) + OS_LIBS = -lstdc++.r4 +endif + +ifeq ($(OS_ARCH), UNIXWARE) + OS_LIBS += -lC +endif + +EXTRA_LIBS = $(LIBNSPR) + +# On NCR and SCOOS, we can't link with extra libraries when +# we build a shared library. If we do so, the linker doesn't +# complain, but we would run into weird problems at run-time. +# Therefore on these platforms, we link just the object files. +ifeq ($(OS_ARCH),NCR) + EXTRA_LIBS = +endif +ifeq ($(OS_ARCH),SCOOS) + EXTRA_LIBS = +endif + +ifdef RESOLVE_LINK_SYMBOLS +EXTRA_LIBS += $(OS_LIBS) +endif + +LIBRARY_NAME = prstrms +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) +RELEASE_LIBS = $(TARGETS) + +include $(topsrcdir)/config/rules.mk + +# +# Version information generation (begin) +# +ECHO = echo +TINC = $(OBJDIR)/_pl_bld.h +PROD = $(notdir $(SHARED_LIBRARY)) +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date "+%Y-%m-%d %T") +SH_NOW = $(shell $(NOW)) + +ifeq ($(OS_ARCH), WINNT) + SUF = i64 +else + SUF = LL +endif + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) '#define _BUILD_STRING "$(SH_DATE)"' > $(TINC) + @if test ! -z "$(SH_NOW)"; then \ + $(ECHO) '#define _BUILD_TIME $(SH_NOW)$(SUF)' >> $(TINC); \ + else \ + true; \ + fi + @$(ECHO) '#define _PRODUCTION "$(PROD)"' >> $(TINC) + + +$(OBJDIR)/plvrsion.$(OBJ_SUFFIX): plvrsion.c $(TINC) +ifeq ($(OS_ARCH), WINNT) + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +else +ifeq ($(MOZ_OS2_TOOLS), VACPP) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +endif +endif +# +# Version information generation (end) +# + +export:: $(TARGETS) $(HEADERS) + $(INSTALL) -m 444 $(HEADERS) $(dist_includedir) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifeq ($(OS_ARCH),OS2) + $(INSTALL) -m 444 $(TARGETS) $(dist_bindir) +endif +ifeq ($(OS_ARCH),HP-UX) +ifdef SHARED_LIBRARY + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_libdir) +endif +endif diff --git a/nsprpub/lib/prstreams/plvrsion.c b/nsprpub/lib/prstreams/plvrsion.c new file mode 100644 index 00000000000..87b62e7a9df --- /dev/null +++ b/nsprpub/lib/prstreams/plvrsion.c @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#include "_pl_bld.h" +#if !defined(_BUILD_TIME) +#ifdef HAVE_LONG_LONG +#define _BUILD_TIME 0 +#else +#define _BUILD_TIME {0, 0} +#endif +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * A trick to expand the PR_VMAJOR macro before concatenation. + */ +#define CONCAT(x, y) x ## y +#define CONCAT2(x, y) CONCAT(x, y) +#define VERSION_DESC_NAME CONCAT2(prVersionDescription_libprstrms, PR_VMAJOR) + +PRVersionDescription VERSION_DESC_NAME = +{ + /* 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 */ "http://www.mozilla.org/MPL/", + /* specialString */ "" +}; + +#ifdef XP_UNIX + +/* + * Version information for the 'ident' and 'what commands + * + * NOTE: the first component of the concatenated rcsid string + * must not end in a '$' to prevent rcs keyword substitution. + */ +static char rcsid[] = "$Header: NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING " $"; +static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING; + +#endif /* XP_UNIX */ + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint() +{ +#ifdef XP_UNIX + /* + * Add dummy references to rcsid and sccsid to prevent them + * from being optimized away as unused variables. + */ + const char *dummy; + + dummy = rcsid; + dummy = sccsid; +#endif + return &VERSION_DESC_NAME; +} /* versionEntryPointType */ + +/* plvrsion.c */ + diff --git a/nsprpub/lib/prstreams/prstrms.cpp b/nsprpub/lib/prstreams/prstrms.cpp new file mode 100644 index 00000000000..17b280ea1f1 --- /dev/null +++ b/nsprpub/lib/prstreams/prstrms.cpp @@ -0,0 +1,550 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Robin J. Maxwell 11-22-96 + */ + +#include "prstrms.h" +#include // memmove + +// +// Definition of macros _PRSTR_BP, _PRSTR_DELBUF, and _PRSTR_DELBUF_C. +// +// _PRSTR_BP is the protected member of class ios that is returned +// by the public method rdbuf(). +// +// _PRSTR_DELBUF is the method or data member of class ios, if available, +// with which we can ensure that the ios destructor does not delete +// the associated streambuf. If such a method or data member does not +// exist, define _PRSTR_DELBUF to be empty. +// +// _PRSTR_DELBUF_C is just _PRSTR_DELBUF qualified by a base class. +// + +#if defined(__GNUC__) +#define _PRSTR_BP _strbuf +#define _PRSTR_DELBUF(x) /* as nothing */ +#define _PRSTR_DELBUF_C(c, x) /* as nothing */ +#elif defined(WIN32) +#define _PRSTR_BP bp +#define _PRSTR_DELBUF(x) delbuf(x) +#define _PRSTR_DELBUF_C(c, x) c::_PRSTR_DELBUF(x) +#elif defined(VMS) +#undef _PRSTR_BP +#define _PRSTR_DELBUF(x) /* as nothing */ +#define _PRSTR_DELBUF_C(c, x) /* as nothing */ +#elif defined(OSF1) +#define _PRSTR_BP m_psb +#define _PRSTR_DELBUF(x) /* as nothing */ +#define _PRSTR_DELBUF_C(c, x) /* as nothing */ +#elif defined(QNX) +#define PRFSTREAMS_BROKEN +#else +#define _PRSTR_BP bp +// Unix compilers don't believe in encapsulation +// At least on Solaris this is also ignored +#define _PRSTR_DELBUF(x) delbuf = x +#define _PRSTR_DELBUF_C(c, x) c::_PRSTR_DELBUF(x) +#endif + +const PRIntn STRM_BUFSIZ = 8192; + +#if !defined (PRFSTREAMS_BROKEN) + +PRfilebuf::PRfilebuf(): +_fd(0), +_opened(PR_FALSE), +_allocated(PR_FALSE) +{ +} + +PRfilebuf::PRfilebuf(PRFileDesc *fd): +streambuf(), +_fd(fd), +_opened(PR_FALSE), +_allocated(PR_FALSE) +{ +} + +PRfilebuf::PRfilebuf(PRFileDesc *fd, char * buffptr, int bufflen): +_fd(fd), +_opened(PR_FALSE), +_allocated(PR_FALSE) +{ + PRfilebuf::setbuf(buffptr, bufflen); +} + +PRfilebuf::~PRfilebuf() +{ + if (_opened){ + close(); + }else + sync(); + if (_allocated) + delete base(); +} + +PRfilebuf* +PRfilebuf::open(const char *name, int mode, int flags) +{ + if (_fd != 0) + return 0; // error if already open + PRIntn PRmode = 0; + // translate mode argument + if (!(mode & ios::nocreate)) + PRmode |= PR_CREATE_FILE; + //if (mode & ios::noreplace) + // PRmode |= O_EXCL; + if (mode & ios::app){ + mode |= ios::out; + PRmode |= PR_APPEND; + } + if (mode & ios::trunc){ + mode |= ios::out; // IMPLIED + PRmode |= PR_TRUNCATE; + } + if (mode & ios::out){ + if (mode & ios::in) + PRmode |= PR_RDWR; + else + PRmode |= PR_WRONLY; + if (!(mode & (ios::in|ios::app|ios::ate|ios::noreplace))){ + mode |= ios::trunc; // IMPLIED + PRmode |= PR_TRUNCATE; + } + }else if (mode & ios::in) + PRmode |= PR_RDONLY; + else + return 0; // error if not ios:in or ios::out + + + // + // The usual portable across unix crap... + // NT gets a hokey piece of junk layer that prevents + // access to the API. +#ifdef WIN32 + _fd = PR_Open(name, PRmode, PRmode); +#else + _fd = PR_Open(name, PRmode, flags); +#endif + if (_fd == 0) + return 0; + _opened = PR_TRUE; + if ((!unbuffered()) && (!ebuf())){ + char * sbuf = new char[STRM_BUFSIZ]; + if (!sbuf) + unbuffered(1); + else{ + _allocated = PR_TRUE; + streambuf::setb(sbuf,sbuf+STRM_BUFSIZ,0); + } + } + if (mode & ios::ate){ + if (seekoff(0,ios::end,mode)==EOF){ + close(); + return 0; + } + } + return this; +} + +PRfilebuf* +PRfilebuf::attach(PRFileDesc *fd) +{ + _opened = PR_FALSE; + _fd = fd; + return this; +} + +int +PRfilebuf::overflow(int c) +{ + if (allocate()==EOF) // make sure there is a reserve area + return EOF; + if (PRfilebuf::sync()==EOF) // sync before new buffer created below + return EOF; + + if (!unbuffered()) + setp(base(),ebuf()); + + if (c!=EOF){ + if ((!unbuffered()) && (pptr() < epptr())) // guard against recursion + sputc(c); + else{ + if (PR_Write(_fd, &c, 1)!=1) + return(EOF); + } + } + return(1); // return something other than EOF if successful +} + +int +PRfilebuf::underflow() +{ + int count; + unsigned char tbuf; + + if (in_avail()) + return (int)(unsigned char) *gptr(); + + if (allocate()==EOF) // make sure there is a reserve area + return EOF; + if (PRfilebuf::sync()==EOF) + return EOF; + + if (unbuffered()) + { + if (PR_Read(_fd,(void *)&tbuf,1)<=0) + return EOF; + return (int)tbuf; + } + + if ((count=PR_Read(_fd,(void *)base(),blen())) <= 0) + return EOF; // reached EOF + setg(base(),base(),base()+count); + return (int)(unsigned char) *gptr(); +} + +streambuf* +PRfilebuf::setbuf(char *buffptr, PRstreambuflen bufflen) +{ + if (is_open() && (ebuf())) + return 0; + if ((!buffptr) || (bufflen <= 0)) + unbuffered(1); + else + setb(buffptr, buffptr+bufflen, 0); + return this; +} + +streampos +PRfilebuf::seekoff(streamoff offset, ios::seek_dir dir, int /* mode */) +{ + if (PR_GetDescType(_fd) == PR_DESC_FILE){ + PRSeekWhence fdir; + PRInt32 retpos; + switch (dir) { + case ios::beg : + fdir = PR_SEEK_SET; + break; + case ios::cur : + fdir = PR_SEEK_CUR; + break; + case ios::end : + fdir = PR_SEEK_END; + break; + default: + // error + return(EOF); + } + + if (PRfilebuf::sync()==EOF) + return EOF; + if ((retpos=PR_Seek(_fd, offset, fdir))==-1L) + return (EOF); + return((streampos)retpos); + }else + return (EOF); +} + + +int +PRfilebuf::sync() +{ + PRInt32 count; + + if (_fd==0) + return(EOF); + + if (!unbuffered()){ + // Sync write area + if ((count=out_waiting())!=0){ + PRInt32 nout; + if ((nout =PR_Write(_fd, + (void *) pbase(), + (unsigned int)count)) != count){ + if (nout > 0) { + // should set _pptr -= nout + pbump(-(int)nout); + memmove(pbase(), pbase()+nout, (int)(count-nout)); + } + return(EOF); + } + } + setp(0,0); // empty put area + + if (PR_GetDescType(_fd) == PR_DESC_FILE){ + // Sockets can't seek; don't need this + if ((count=in_avail()) > 0){ + if (PR_Seek(_fd, -count, PR_SEEK_CUR)!=-1L) + { + return (EOF); + } + } + } + setg(0,0,0); // empty get area + } + return(0); +} + +PRfilebuf * +PRfilebuf::close() +{ + int retval; + if (_fd==0) + return 0; + + retval = sync(); + + if ((PR_Close(_fd)==0) || (retval==EOF)) + return 0; + _fd = 0; + return this; +} + +PRifstream::PRifstream(): +istream(new PRfilebuf) +{ + _PRSTR_DELBUF(0); +} + +PRifstream::PRifstream(PRFileDesc *fd): +istream(new PRfilebuf(fd)) +{ + _PRSTR_DELBUF(0); +} + +PRifstream::PRifstream(PRFileDesc *fd, char *buff, int bufflen): +istream(new PRfilebuf(fd, buff, bufflen)) +{ + _PRSTR_DELBUF(0); +} + +PRifstream::PRifstream(const char * name, int mode, int flags): +istream(new PRfilebuf) +{ + _PRSTR_DELBUF(0); + if (!rdbuf()->open(name, (mode|ios::in), flags)) + clear(rdstate() | ios::failbit); +} + +PRifstream::~PRifstream() +{ + sync(); + + delete rdbuf(); +#ifdef _PRSTR_BP + _PRSTR_BP = 0; +#endif +} + +streambuf * +PRifstream::setbuf(char * ptr, int len) +{ + if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ + clear(rdstate() | ios::failbit); + return 0; + } + return rdbuf(); +} + +void +PRifstream::attach(PRFileDesc *fd) +{ + if (!(rdbuf()->attach(fd))) + clear(rdstate() | ios::failbit); +} + +void +PRifstream::open(const char * name, int mode, int flags) +{ + if (is_open() || !(rdbuf()->open(name, (mode|ios::in), flags))) + clear(rdstate() | ios::failbit); +} + +void +PRifstream::close() +{ + clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); +} + +PRofstream::PRofstream(): +ostream(new PRfilebuf) +{ + _PRSTR_DELBUF(0); +} + +PRofstream::PRofstream(PRFileDesc *fd): +ostream(new PRfilebuf(fd)) +{ + _PRSTR_DELBUF(0); +} + +PRofstream::PRofstream(PRFileDesc *fd, char *buff, int bufflen): +ostream(new PRfilebuf(fd, buff, bufflen)) +{ + _PRSTR_DELBUF(0); +} + +PRofstream::PRofstream(const char *name, int mode, int flags): +ostream(new PRfilebuf) +{ + _PRSTR_DELBUF(0); + if (!rdbuf()->open(name, (mode|ios::out), flags)) + clear(rdstate() | ios::failbit); +} + +PRofstream::~PRofstream() +{ + flush(); + + delete rdbuf(); +#ifdef _PRSTR_BP + _PRSTR_BP = 0; +#endif +} + +streambuf * +PRofstream::setbuf(char * ptr, int len) +{ + if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ + clear(rdstate() | ios::failbit); + return 0; + } + return rdbuf(); +} + +void +PRofstream::attach(PRFileDesc *fd) +{ + if (!(rdbuf()->attach(fd))) + clear(rdstate() | ios::failbit); +} + +void +PRofstream::open(const char * name, int mode, int flags) +{ + if (is_open() || !(rdbuf()->open(name, (mode|ios::out), flags))) + clear(rdstate() | ios::failbit); +} + +void +PRofstream::close() +{ + clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); +} + +PRfstream::PRfstream(): +iostream(new PRfilebuf) +{ + _PRSTR_DELBUF_C(istream, 0); + _PRSTR_DELBUF_C(ostream, 0); +} + +PRfstream::PRfstream(PRFileDesc *fd): +iostream(new PRfilebuf(fd)) +{ + _PRSTR_DELBUF_C(istream, 0); + _PRSTR_DELBUF_C(ostream, 0); +} + +PRfstream::PRfstream(PRFileDesc *fd, char *buff, int bufflen): +iostream(new PRfilebuf(fd, buff, bufflen)) +{ + _PRSTR_DELBUF_C(istream, 0); + _PRSTR_DELBUF_C(ostream, 0); +} + +PRfstream::PRfstream(const char *name, int mode, int flags): +iostream(new PRfilebuf) +{ + _PRSTR_DELBUF_C(istream, 0); + _PRSTR_DELBUF_C(ostream, 0); + if (!rdbuf()->open(name, (mode|(ios::in|ios::out)), flags)) + clear(rdstate() | ios::failbit); +} + +PRfstream::~PRfstream() +{ + sync(); + flush(); + + delete rdbuf(); +#ifdef _PRSTR_BP + istream::_PRSTR_BP = 0; + ostream::_PRSTR_BP = 0; +#endif +} + +streambuf * +PRfstream::setbuf(char * ptr, int len) +{ + if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ + clear(rdstate() | ios::failbit); + return 0; + } + return rdbuf(); +} + +void +PRfstream::attach(PRFileDesc *fd) +{ + if (!(rdbuf()->attach(fd))) + clear(rdstate() | ios::failbit); +} + +void +PRfstream::open(const char * name, int mode, int flags) +{ + if (is_open() || !(rdbuf()->open(name, (mode|(ios::in|ios::out)), flags))) + clear(rdstate() | ios::failbit); +} + +void +PRfstream::close() +{ + clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); +} + +#else + +// fix it sometime + +int fix_prfstreams () { return 0; } + +#endif diff --git a/nsprpub/lib/prstreams/prstrms.h b/nsprpub/lib/prstreams/prstrms.h new file mode 100644 index 00000000000..a6752fc4740 --- /dev/null +++ b/nsprpub/lib/prstreams/prstrms.h @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Robin J. Maxwell 11-22-96 + */ + +#ifndef _PRSTRMS_H +#define _PRSTRMS_H + +#include "prtypes.h" +#include "prio.h" + +#ifdef _MSC_VER +#pragma warning( disable : 4275) +#endif +#include + +#if defined(AIX) && defined(__64BIT__) +typedef long PRstreambuflen; +#else +typedef int PRstreambuflen; +#endif + +#if defined (PRFSTREAMS_BROKEN) + +// fix it sometime + +#define PRfilebuf streambuf +#define PRifstream ifstream +#define PRofstream ofstream +#define PRfstream fstream + +#else + +class PR_IMPLEMENT(PRfilebuf): public streambuf +{ +public: + PRfilebuf(); + PRfilebuf(PRFileDesc *fd); + PRfilebuf(PRFileDesc *fd, char * buffptr, int bufflen); + ~PRfilebuf(); + virtual int overflow(int=EOF); + virtual int underflow(); + virtual streambuf *setbuf(char *buff, PRstreambuflen bufflen); + virtual streampos seekoff(streamoff, ios::seek_dir, int); + virtual int sync(); + PRfilebuf *open(const char *name, int mode, int flags); + PRfilebuf *attach(PRFileDesc *fd); + PRfilebuf *close(); + int is_open() const {return (_fd != 0);} + PRFileDesc *fd(){return _fd;} + +private: + PRFileDesc * _fd; + PRBool _opened; + PRBool _allocated; +}; + +class PR_IMPLEMENT(PRifstream): public istream { +public: + PRifstream(); + PRifstream(const char *, int mode=ios::in, int flags = 0); + PRifstream(PRFileDesc *); + PRifstream(PRFileDesc *, char *, int); + ~PRifstream(); + + streambuf * setbuf(char *, int); + PRfilebuf* rdbuf(){return (PRfilebuf*) ios::rdbuf(); } + + void attach(PRFileDesc *fd); + PRFileDesc *fd() {return rdbuf()->fd();} + + int is_open(){return rdbuf()->is_open();} + void open(const char *, int mode=ios::in, int flags= 0); + void close(); +}; + +class PR_IMPLEMENT(PRofstream) : public ostream { +public: + PRofstream(); + PRofstream(const char *, int mode=ios::out, int flags = 0); + PRofstream(PRFileDesc *); + PRofstream(PRFileDesc *, char *, int); + ~PRofstream(); + + streambuf * setbuf(char *, int); + PRfilebuf* rdbuf() { return (PRfilebuf*) ios::rdbuf(); } + + void attach(PRFileDesc *); + PRFileDesc *fd() {return rdbuf()->fd();} + + int is_open(){return rdbuf()->is_open();} + void open(const char *, int =ios::out, int = 0); + void close(); +}; + +class PR_IMPLEMENT(PRfstream) : public iostream { +public: + PRfstream(); + PRfstream(const char *name, int mode, int flags= 0); + PRfstream(PRFileDesc *fd); + PRfstream(PRFileDesc *fd, char *buff, int bufflen); + ~PRfstream(); + + streambuf * setbuf(char *, int); + PRfilebuf* rdbuf(){ return (PRfilebuf*) ostream::rdbuf(); } + + void attach(PRFileDesc *); + PRFileDesc *fd() { return rdbuf()->fd(); } + + int is_open() { return rdbuf()->is_open(); } + void open(const char *, int, int = 0); + void close(); +}; + +#endif + +#endif /* _PRSTRMS_H */ diff --git a/nsprpub/lib/prstreams/prstrms.rc b/nsprpub/lib/prstreams/prstrms.rc new file mode 100644 index 00000000000..aff3bde9a37 --- /dev/null +++ b/nsprpub/lib/prstreams/prstrms.rc @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include + +#define MY_LIBNAME "prstrms" +#define MY_FILEDESCRIPTION "PRSTRMS Library" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define PR_VMAJOR_STR STRINGIZE2(PR_VMAJOR) + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if PR_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#define MY_INTERNAL_NAME "lib" MY_LIBNAME PR_VMAJOR_STR +#else +#define MY_FILEOS VOS__WINDOWS32 +#define MY_INTERNAL_NAME MY_LIBNAME PR_VMAJOR_STR +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + PRODUCTVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Mozilla Foundation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", PR_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Netscape Portable Runtime\0" + VALUE "ProductVersion", PR_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/nsprpub/lib/prstreams/tests/testprstrm/.cvsignore b/nsprpub/lib/prstreams/tests/testprstrm/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/prstreams/tests/testprstrm/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/prstreams/tests/testprstrm/Makefile.in b/nsprpub/lib/prstreams/tests/testprstrm/Makefile.in new file mode 100644 index 00000000000..e1405fd0b3e --- /dev/null +++ b/nsprpub/lib/prstreams/tests/testprstrm/Makefile.in @@ -0,0 +1,254 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CXXSRCS = \ + testprstrm.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CXXSRCS:.cpp=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(MOD_MAJOR_VERSION) +LIBPRSTRMS = -lprstrms$(MOD_MAJOR_VERSION) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPRSTRMS = $(dist_libdir)/prstrms$(MOD_MAJOR_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -INCREMENTAL:NO + ifeq ($(OS_TARGET), WIN95) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPRSTRMS = $(dist_libdir)/prstrms$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + else + LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPRSTRMS = $(dist_libdir)/libprstrms$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + endif +endif +endif + +ifeq ($(OS_ARCH),OS2) + ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO /S:32768 + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPRSTRMS = $(dist_libdir)/prstrms$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + else + LDOPTS += -Zomf -Zlinker /PM:VIO -lstdcpp + endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), IRIX) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), HP-UX) +LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) +LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib +ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) +LIBPR = -lnspr$(MOD_MAJOR_VERSION)_shr +LIBPRSTRMS = -lprstrms$(MOD_MAJOR_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_libdir) +else +LDOPTS += -R $(PWD)/$(dist_libdir) +# CC on SunOS 5.4 and 5.5.x need to link with -lthread or -lpthread +# (or use the -mt switch) even though we already linked with these +# system libraries when we built libnspr.so. +ifdef USE_PTHREADS +EXTRA_LIBS = -lpthread +else +EXTRA_LIBS = -lthread +endif # USE_PTHREADS +endif # NS_USE_GCC +endif # 4.1.3_U1 +endif # SunOS + +ifeq ($(OS_ARCH), NCR) +# XXX: We see some strange problems when we link with libnspr.so. +# So for now we use static libraries on NCR. The shared library +# stuff below is commented out. +LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a +LIBPRSTRMS = $(dist_libdir)/libprstrms$(MOD_MAJOR_VERSION).a +EXTRA_LIBS = -lsocket -lnsl -ldl + +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +#EXTRA_LIBS = -lsocket -lnsl +# 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_libdir) +endif + +ifeq ($(OS_ARCH), SCOOS) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# 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_libdir) +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPRSTRMS), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPR) $(LIBPRSTRMS) wsock32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(EXEFLAGS) $(LDOPTS) $< $(LIBPR) $(LIBPRSTRMS) $(OS_LIBS) $(EXTRA_LIBS) +else + $(CCC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPRSTRMS) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + +testlinker: + echo $(LINK) diff --git a/nsprpub/lib/prstreams/tests/testprstrm/testprstrm.cpp b/nsprpub/lib/prstreams/tests/testprstrm/testprstrm.cpp new file mode 100644 index 00000000000..6e8b866570e --- /dev/null +++ b/nsprpub/lib/prstreams/tests/testprstrm/testprstrm.cpp @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include "prstrms.h" +#include "prio.h" +#include +#include +#if defined(XP_UNIX) || defined(XP_OS2_EMX) +#include +#include +#endif + +const unsigned int MaxCnt = 1; + +void threadwork(void *mytag); + + +typedef struct threadarg { + void *mytag; +} threadarg; + +void +#ifdef XP_OS2_VACPP +_Optlink +#endif +threadmain(void *mytag) +{ + threadarg arg; + + arg.mytag = mytag; + + threadwork(&arg); +} + + +void +threadwork(void *_arg) +{ + threadarg *arg = (threadarg *)_arg; + unsigned int i; + + char fname1[256]; + char fname2[256]; + + strcpy(fname1, (char *)arg->mytag); + strcpy(fname2, (char *)arg->mytag); + strcat(fname2, "2"); + PR_Delete(fname1); + PR_Delete(fname2); + + PRfilebuf *fb[MaxCnt]; + PRifstream *ifs[MaxCnt]; + PRofstream *ofs[MaxCnt]; + int mode = 0; +#ifdef XP_UNIX + mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IRGRP|S_IWOTH|S_IROTH; +#endif + + // + // Allocate a bunch + cout << "Testing unused filebufs ----------------" << endl; + for (i=0; i < MaxCnt; i++){ + fb[i] = new PRfilebuf; + } + // Delete them + for (i=0; i < MaxCnt; i++){ + delete fb[i]; + } + cout << "Unused filebufs complete ---------------" << endl; + + // + // Allocate a bunch + cout << "Testing unused ifstream -----------------" << endl; + for (i=0; i < MaxCnt; i++){ + ifs[i] = new PRifstream; + } + // + // Delete them + for (i=0; i < MaxCnt; i++){ + delete ifs[i]; + } + cout << "Unused ifstream complete ----------------" << endl; + // + // Allocate a bunch + cout << "Testing unused ofstream -----------------" << endl; + for (i=0; i < MaxCnt; i++){ + ofs[i] = new PRofstream; + } + for (i=0; i < MaxCnt; i++){ + *(ofs[i]) << "A"; // Write a bit + delete ofs[i]; // Delete it. + } + cout << "Unused ofstream complete ----------------" << endl; + + cout << "Testing use of ofstream 1 (extra filebuf allocated) ---------" << endl; + PRofstream *aos = new PRofstream(fname1, ios::out|ios::ate, mode); + for (i=0; i < MaxCnt; i++){ + for (int j=0; j < 8192; j++) + *aos << "AaBbCcDdEeFfGg" << endl; + fb[i] = new PRfilebuf; // Allocate as we go to hack at the heap + } + // + // Delete the extra foo we allocated + for (i=0; i < MaxCnt; i++){ + delete fb[i]; + } + aos->flush(); // Explicit flush + delete aos; + cout << "Testing use of ofstream 1 complete (extra filebuf deleted) --" << endl; + cout << "Testing use of ofstream 2 (extra filebuf allocated) ---------" << endl; + PRofstream *aos2 = new PRofstream(fname2, ios::out, mode); + + for (i=0; i < MaxCnt; i++){ + *aos2 << "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + } + // Force flushing in the dtor + delete aos2; + cout << "Testing use of ofstream 2 complete (extra filebuf deleted) --" << endl; + char line[1024]; + cout << "Testing use of ifstream 1 (stack allocation) -------------" << endl; + PRifstream ais(fname1); + for (i=0; i < MaxCnt; i++){ + ais >> line; + } + cout << "Testing use of ifstream 1 complete -----------------------" << endl; + cout << "Testing use of ifstream 2 ----------------------" << endl; + PRifstream *ais2 = new PRifstream(fname2); + char achar; + for (i=0; i < MaxCnt*10; i++){ + *ais2 >> achar; + } + delete ais2; + cout << "Testing use of ifstream 2 complete -------------" << endl; +} + +#define STACKSIZE 1024*1024 +int +main(int argc, char **argv) +{ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 256); + threadmain("TestFile"); + PRThread *thr1 = PR_CreateThread(PR_SYSTEM_THREAD, + threadmain, + (void *)"TestFile1", + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + STACKSIZE); + PRThread *thr2 = PR_CreateThread(PR_SYSTEM_THREAD, + threadmain, + (void *)"TestFile2", + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + STACKSIZE); + + PRThread *thr3 = PR_CreateThread(PR_SYSTEM_THREAD, + threadmain, + (void *)"TestFile3", + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + STACKSIZE); + PR_JoinThread(thr1); + PR_JoinThread(thr2); + PR_JoinThread(thr3); + return 0; +} + diff --git a/nsprpub/lib/tests/.cvsignore b/nsprpub/lib/tests/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/lib/tests/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/lib/tests/Makefile.in b/nsprpub/lib/tests/Makefile.in new file mode 100644 index 00000000000..e833aabf6a3 --- /dev/null +++ b/nsprpub/lib/tests/Makefile.in @@ -0,0 +1,262 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CSRCS = \ + arena.c \ + base64t.c \ + getopt.c \ + string.c + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +CSRCS += arena.c +endif + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(MOD_MAJOR_VERSION) +LIBPLC = -lplc$(MOD_MAJOR_VERSION) +LIBPLDS = -lplds$(MOD_MAJOR_VERSION) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPLC= $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib + LIBPLDS= $(dist_libdir)/plds$(MOD_MAJOR_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -INCREMENTAL:NO + ifeq ($(OS_TARGET), WIN95) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPLC= $(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPLDS= $(dist_libdir)/plds$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + else + LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPLC= $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPLDS= $(dist_libdir)/libplds$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + endif +endif +endif + +ifeq ($(OS_ARCH),OS2) + ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO /S:32768 + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPLC = $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib + LIBPLDS= $(dist_libdir)/plds$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + else + LDOPTS += -Zomf -Zlinker /PM:VIO + endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), IRIX) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), Linux) + ifeq ($(OS_RELEASE), 1.2) + EXTRA_LIBS = -ldl + else + LDOPTS += -Xlinker -rpath $(PWD)/$(dist_libdir) + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif + endif +endif + +ifeq (,$(filter-out OpenBSD,$(OS_ARCH))) + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) -lpthread +endif + +ifeq ($(OS_ARCH), HP-UX) +LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) +LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib +LIBPR = -lnspr$(MOD_MAJOR_VERSION)_shr +LIBPLC = -lplc$(MOD_MAJOR_VERSION)_shr +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) +ifneq ($(OS_RELEASE), 4.1.3_U1) +ifdef NS_USE_GCC +LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) +else +LDOPTS += -R $(PWD)/$(dist_libdir) +endif +endif + +# 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 # SunOS + +ifeq ($(OS_ARCH), NCR) +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket -lnsl +# 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_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPLC), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPLC) $(LIBPLDS) $(LIBPR) wsock32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(EXEFLAGS) $(LDOPTS) $< $(LIBPLC) $(LIBPLDS) $(LIBPR) $(OS_LIBS) $(EXTRA_LIBS) +else + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBPLDS) $(LIBPR) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + + + diff --git a/nsprpub/lib/tests/arena.c b/nsprpub/lib/tests/arena.c new file mode 100644 index 00000000000..9c74479cbd7 --- /dev/null +++ b/nsprpub/lib/tests/arena.c @@ -0,0 +1,401 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: arena.c +** Description: Testing arenas +** +*/ + +#include +#include +#include +#include "nspr.h" +#include "plarena.h" +#include "plgetopt.h" + +PRLogModuleInfo *tLM; +PRIntn threadCount = 0; +PRMonitor *tMon; +PRBool failed_already = PR_FALSE; + +/* Arguments from the command line with default values */ +PRIntn debug_mode = 0; +PRIntn poolMin = 4096; +PRIntn poolMax = (100 * 4096); +PRIntn arenaMin = 40; +PRIntn arenaMax = (100 * 40); +PRIntn stressIterations = 15; +PRIntn maxAlloc = (1024 * 1024); +PRIntn stressThreads = 4; + +void DumpAll( void ) +{ + return; +} + +/* +** Test Arena allocation. +*/ +static void ArenaAllocate( void ) +{ + PLArenaPool ap; + void *ptr; + PRInt32 i; + + PL_InitArenaPool( &ap, "AllocArena", 2048, sizeof(double)); + PR_LOG( tLM, PR_LOG_DEBUG, ("AA, InitPool -- Pool: %p. first: %p, current: %p, size: %d", + &ap, ap.first, ap.current, ap.arenasize )); + + for( i = 0; i < 150; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d", + &ap, ap.first, ap.current, ap.arenasize )); + PR_LOG( tLM, PR_LOG_DEBUG,( + "AA -- Pool: %p. alloc: %p ", &ap, ptr )); + } + + PL_FreeArenaPool( &ap ); + + for( i = 0; i < 221; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d", + &ap, ap.first, ap.current, ap.arenasize )); + PR_LOG( tLM, PR_LOG_DEBUG,( + "AA -- Pool: %p. alloc: %p ", &ap, ptr )); + } + + PL_FreeArenaPool( &ap ); + + return; +} /* end ArenaGrow() */ +/* +** Test Arena grow. +*/ +static void ArenaGrow( void ) +{ + PLArenaPool ap; + void *ptr; + PRInt32 i; + + PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double)); + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + + PR_LOG( tLM, PR_LOG_DEBUG, ("Before growth -- Pool: %p. alloc: %p ", &ap, ptr )); + + for( i = 0; i < 10; i++ ) + { + PL_ARENA_GROW( ptr, &ap, 512, 7000 ); + PR_LOG( tLM, PR_LOG_DEBUG, ("After growth -- Pool: %p. alloc: %p ", &ap, ptr )); + } + + + return; +} /* end ArenaGrow() */ + + +/* +** Test arena Mark and Release. +*/ +static void MarkAndRelease( void ) +{ + PLArenaPool ap; + void *ptr = NULL; + void *mark0, *mark1; + PRIntn i; + + PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double)); + mark0 = PL_ARENA_MARK( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mark0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m0: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark0 )); + + for( i = 0; i < 201; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + } + + mark1 = PL_ARENA_MARK( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mark1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m1: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark1 )); + + + for( i = 0; i < 225; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + } + + PL_ARENA_RELEASE( &ap, mark1 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Release-1: %p -- Pool: %p. first: %p, current: %p, size: %d", + mark1, &ap, ap.first, ap.current, ap.arenasize )); + + for( i = 0; i < 20; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + } + + PL_ARENA_RELEASE( &ap, mark1 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Release-1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + + PL_ARENA_RELEASE( &ap, mark0 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Release-0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + + PL_FreeArenaPool( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Free. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + + PL_FinishArenaPool( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Finish. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + + return; +} /* end MarkAndRelease() */ + +/* +** RandSize() returns a random number in the range +** min..max, rounded to the next doubleword +** +*/ +static PRIntn RandSize( PRIntn min, PRIntn max ) +{ + PRIntn sz = (rand() % (max -min)) + min + sizeof(double); + + sz &= ~sizeof(double)-1; + + return(sz); +} + + +/* +** StressThread() +** A bunch of these beat on individual arenas +** This tests the free_list protection. +** +*/ +static void PR_CALLBACK StressThread( void *arg ) +{ + PLArenaPool ap; + PRIntn i; + PRIntn sz; + void *ptr; + PRThread *tp = PR_GetCurrentThread(); + + PR_LOG( tLM, PR_LOG_DEBUG, ("Stress Thread %p started\n", PR_GetCurrentThread())); + PL_InitArenaPool( &ap, "TheArena", RandSize( poolMin, poolMax), sizeof(double)); + + for ( i = 0; i < stressIterations; i++ ) + { + PRIntn allocated = 0; + + while ( allocated < maxAlloc ) + { + sz = RandSize( arenaMin, arenaMax ); + PL_ARENA_ALLOCATE( ptr, &ap, sz ); + if ( ptr == NULL ) + { + PR_LOG( tLM, PR_LOG_ERROR, ("ARENA_ALLOCATE() returned NULL\n\tAllocated: %d\n", allocated)); + break; + } + allocated += sz; + } + PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished one iteration\n", tp)); + PL_FreeArenaPool( &ap ); + } + PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished all iteration\n", tp)); + PL_FinishArenaPool( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p after FinishArenaPool()\n", tp)); + + /* That's all folks! let's quit */ + PR_EnterMonitor(tMon); + threadCount--; + PR_Notify(tMon); + PR_ExitMonitor(tMon); + return; +} + +/* +** Stress() +** Flog the hell out of arenas multi-threaded. +** Do NOT pass an individual arena to another thread. +** +*/ +static void Stress( void ) +{ + PRThread *tt; + PRIntn i; + + tMon = PR_NewMonitor(); + + for ( i = 0 ; i < stressThreads ; i++ ) + { + PR_EnterMonitor(tMon); + tt = PR_CreateThread(PR_USER_THREAD, + StressThread, + NULL, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + threadCount++; + PR_ExitMonitor(tMon); + } + + /* Wait for all threads to exit */ + PR_EnterMonitor(tMon); + while ( threadCount != 0 ) + { + PR_Wait(tMon, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(tMon); + PR_DestroyMonitor(tMon); + + return; +} /* end Stress() */ + +/* +** EvaluateResults() +** uses failed_already to display results and set program +** exit code. +*/ +static PRIntn EvaluateResults(void) +{ + PRIntn rc = 0; + + if ( failed_already == PR_TRUE ) + { + PR_LOG( tLM, PR_LOG_DEBUG, ("FAIL\n")); + rc =1; + } + else + { + PR_LOG( tLM, PR_LOG_DEBUG, ("PASS\n")); + } + return(rc); +} /* EvaluateResults() */ + +void Help( void ) +{ + printf("arena [options]\n"); + printf("where options are:\n"); + printf("-p minimum size of an arena pool. Default(%d)\n", poolMin); + printf("-P maximum size of an arena pool. Default(%d)\n", poolMax); + printf("-a minimum size of an arena allocation. Default(%d)\n", arenaMin); + printf("-A maximum size of an arena allocation. Default(%d)\n", arenaMax); + printf("-i number of iterations in a stress thread. Default(%d)\n", stressIterations); + printf("-s maximum allocation for a single stress thread. Default(%d)\n", maxAlloc); + printf("-t number of stress threads. Default(%d)\n", stressThreads ); + printf("-d enable debug mode\n"); + printf("\n"); + exit(1); +} + +PRIntn main(PRIntn argc, char *argv[]) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dhp:P:a:A:i:s:t:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'a': /* arena Min size */ + arenaMin = atol( opt->value ); + break; + case 'A': /* arena Max size */ + arenaMax = atol( opt->value ); + break; + case 'p': /* pool Min size */ + poolMin = atol( opt->value ); + break; + case 'P': /* pool Max size */ + poolMax = atol( opt->value ); + break; + case 'i': /* Iterations in stress tests */ + stressIterations = atol( opt->value ); + break; + case 's': /* storage to get per iteration */ + maxAlloc = atol( opt->value ); + break; + case 't': /* Number of stress threads to create */ + stressThreads = atol( opt->value ); + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'h': /* help */ + default: + Help(); + } /* end switch() */ + } /* end while() */ + PL_DestroyOptState(opt); + + srand( (unsigned)time( NULL ) ); /* seed random number generator */ + tLM = PR_NewLogModule("testcase"); + + +#if 0 + ArenaAllocate(); + ArenaGrow(); +#endif + + MarkAndRelease(); + + Stress(); + + return(EvaluateResults()); +} /* end main() */ + +/* arena.c */ diff --git a/nsprpub/lib/tests/base64t.c b/nsprpub/lib/tests/base64t.c new file mode 100644 index 00000000000..c3c488137fc --- /dev/null +++ b/nsprpub/lib/tests/base64t.c @@ -0,0 +1,3047 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plbase64.h" +#include "plstr.h" +#include "nspr.h" + +#include + +static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* PL_Base64Encode, single characters */ +PRBool test_001(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 001 (PL_Base64Encode, single characters) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Encode((char *)plain, 1, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d): return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)cypher, result, 4) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%.4s.\"\n", + a, b, cypher, result); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, double characters */ +PRBool test_002(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 002 (PL_Base64Encode, double characters) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Encode((char *)plain, 2, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d): return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)cypher, result, 4) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%.4s.\"\n", + a, b, c, d, cypher, result); + return PR_FALSE; + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, triple characters */ +PRBool test_003(void) +{ + PRUint32 a, b, c, d, e, f; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 003 (PL_Base64Encode, triple characters) ..."); fflush(stdout); + + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + for( e = 0; e < 4; e++ ) + { + cypher[2] = base[d*4 + e]; + for( f = 0; f < 64; f++ ) + { + plain[2] = e * 64 + f; + cypher[3] = base[f]; + + rv = PL_Base64Encode((char *)plain, 3, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): return value\n", a, b, c, d, e, f); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)cypher, result, 4) ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): expected \"%s,\" got \"%.4s.\"\n", + a, b, c, d, e, f, cypher, result); + return PR_FALSE; + } + } + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + + static struct + { + const char *plaintext; + const char *cyphertext; + } array[] = + { + /* Cyphertexts generated with uuenview 0.5.13 */ + { " ", "IA==" }, + { ".", "Lg==" }, + { "/", "Lw==" }, + { "C", "Qw==" }, + { "H", "SA==" }, + { "S", "Uw==" }, + { "^", "Xg==" }, + { "a", "YQ==" }, + { "o", "bw==" }, + { "t", "dA==" }, + + { "AB", "QUI=" }, + { "AH", "QUg=" }, + { "AQ", "QVE=" }, + { "BD", "QkQ=" }, + { "CR", "Q1I=" }, + { "CS", "Q1M=" }, + { "DB", "REI=" }, + { "DC", "REM=" }, + { "EK", "RUs=" }, + { "ET", "RVQ=" }, + { "IM", "SU0=" }, + { "JR", "SlI=" }, + { "LO", "TE8=" }, + { "LW", "TFc=" }, + { "ML", "TUw=" }, + { "SB", "U0I=" }, + { "TO", "VE8=" }, + { "VS", "VlM=" }, + { "WP", "V1A=" }, + /* legitimate two-letter words */ + { "ad", "YWQ=" }, + { "ah", "YWg=" }, + { "am", "YW0=" }, + { "an", "YW4=" }, + { "as", "YXM=" }, + { "at", "YXQ=" }, + { "ax", "YXg=" }, + { "be", "YmU=" }, + { "by", "Ynk=" }, + { "do", "ZG8=" }, + { "go", "Z28=" }, + { "he", "aGU=" }, + { "hi", "aGk=" }, + { "if", "aWY=" }, + { "in", "aW4=" }, + { "is", "aXM=" }, + { "it", "aXQ=" }, + { "me", "bWU=" }, + { "my", "bXk=" }, + { "no", "bm8=" }, + { "of", "b2Y=" }, + { "on", "b24=" }, + { "or", "b3I=" }, + { "ox", "b3g=" }, + { "so", "c28=" }, + { "to", "dG8=" }, + { "up", "dXA=" }, + { "us", "dXM=" }, + { "we", "d2U=" }, + /* all three-letter entries in /usr/dict/words */ + { "1st", "MXN0" }, + { "2nd", "Mm5k" }, + { "3rd", "M3Jk" }, + { "4th", "NHRo" }, + { "5th", "NXRo" }, + { "6th", "NnRo" }, + { "7th", "N3Ro" }, + { "8th", "OHRo" }, + { "9th", "OXRo" }, + { "AAA", "QUFB" }, + { "AAU", "QUFV" }, + { "ABA", "QUJB" }, + { "abc", "YWJj" }, + { "Abe", "QWJl" }, + { "Abo", "QWJv" }, + { "ace", "YWNl" }, + { "ACM", "QUNN" }, + { "ACS", "QUNT" }, + { "act", "YWN0" }, + { "Ada", "QWRh" }, + { "add", "YWRk" }, + { "ado", "YWRv" }, + { "aft", "YWZ0" }, + { "age", "YWdl" }, + { "ago", "YWdv" }, + { "aid", "YWlk" }, + { "ail", "YWls" }, + { "aim", "YWlt" }, + { "air", "YWly" }, + { "ala", "YWxh" }, + { "alb", "YWxi" }, + { "ale", "YWxl" }, + { "Ali", "QWxp" }, + { "all", "YWxs" }, + { "alp", "YWxw" }, + { "A&M", "QSZN" }, + { "AMA", "QU1B" }, + { "ami", "YW1p" }, + { "amp", "YW1w" }, + { "Amy", "QW15" }, + { "amy", "YW15" }, + { "ana", "YW5h" }, + { "and", "YW5k" }, + { "ani", "YW5p" }, + { "Ann", "QW5u" }, + { "ant", "YW50" }, + { "any", "YW55" }, + { "A&P", "QSZQ" }, + { "ape", "YXBl" }, + { "Apr", "QXBy" }, + { "APS", "QVBT" }, + { "apt", "YXB0" }, + { "arc", "YXJj" }, + { "are", "YXJl" }, + { "ark", "YXJr" }, + { "arm", "YXJt" }, + { "art", "YXJ0" }, + { "a's", "YSdz" }, + { "ash", "YXNo" }, + { "ask", "YXNr" }, + { "ass", "YXNz" }, + { "ate", "YXRl" }, + { "Aug", "QXVn" }, + { "auk", "YXVr" }, + { "Ave", "QXZl" }, + { "awe", "YXdl" }, + { "awl", "YXds" }, + { "awn", "YXdu" }, + { "axe", "YXhl" }, + { "aye", "YXll" }, + { "bad", "YmFk" }, + { "bag", "YmFn" }, + { "bah", "YmFo" }, + { "bam", "YmFt" }, + { "ban", "YmFu" }, + { "bar", "YmFy" }, + { "bat", "YmF0" }, + { "bay", "YmF5" }, + { "bed", "YmVk" }, + { "bee", "YmVl" }, + { "beg", "YmVn" }, + { "bel", "YmVs" }, + { "Ben", "QmVu" }, + { "bet", "YmV0" }, + { "bey", "YmV5" }, + { "bib", "Ymli" }, + { "bid", "Ymlk" }, + { "big", "Ymln" }, + { "bin", "Ymlu" }, + { "bit", "Yml0" }, + { "biz", "Yml6" }, + { "BMW", "Qk1X" }, + { "boa", "Ym9h" }, + { "bob", "Ym9i" }, + { "bog", "Ym9n" }, + { "bon", "Ym9u" }, + { "boo", "Ym9v" }, + { "bop", "Ym9w" }, + { "bow", "Ym93" }, + { "box", "Ym94" }, + { "boy", "Ym95" }, + { "b's", "Yidz" }, + { "BTL", "QlRM" }, + { "BTU", "QlRV" }, + { "bub", "YnVi" }, + { "bud", "YnVk" }, + { "bug", "YnVn" }, + { "bum", "YnVt" }, + { "bun", "YnVu" }, + { "bus", "YnVz" }, + { "but", "YnV0" }, + { "buy", "YnV5" }, + { "bye", "Ynll" }, + { "cab", "Y2Fi" }, + { "Cal", "Q2Fs" }, + { "cam", "Y2Ft" }, + { "can", "Y2Fu" }, + { "cap", "Y2Fw" }, + { "car", "Y2Fy" }, + { "cat", "Y2F0" }, + { "caw", "Y2F3" }, + { "CBS", "Q0JT" }, + { "CDC", "Q0RD" }, + { "CEQ", "Q0VR" }, + { "chi", "Y2hp" }, + { "CIA", "Q0lB" }, + { "cit", "Y2l0" }, + { "cod", "Y29k" }, + { "cog", "Y29n" }, + { "col", "Y29s" }, + { "con", "Y29u" }, + { "coo", "Y29v" }, + { "cop", "Y29w" }, + { "cos", "Y29z" }, + { "cot", "Y290" }, + { "cow", "Y293" }, + { "cox", "Y294" }, + { "coy", "Y295" }, + { "CPA", "Q1BB" }, + { "cpu", "Y3B1" }, + { "CRT", "Q1JU" }, + { "cry", "Y3J5" }, + { "c's", "Yydz" }, + { "cub", "Y3Vi" }, + { "cud", "Y3Vk" }, + { "cue", "Y3Vl" }, + { "cup", "Y3Vw" }, + { "cur", "Y3Vy" }, + { "cut", "Y3V0" }, + { "dab", "ZGFi" }, + { "dad", "ZGFk" }, + { "dam", "ZGFt" }, + { "Dan", "RGFu" }, + { "Dar", "RGFy" }, + { "day", "ZGF5" }, + { "Dec", "RGVj" }, + { "Dee", "RGVl" }, + { "Del", "RGVs" }, + { "den", "ZGVu" }, + { "Des", "RGVz" }, + { "dew", "ZGV3" }, + { "dey", "ZGV5" }, + { "did", "ZGlk" }, + { "die", "ZGll" }, + { "dig", "ZGln" }, + { "dim", "ZGlt" }, + { "din", "ZGlu" }, + { "dip", "ZGlw" }, + { "Dis", "RGlz" }, + { "DNA", "RE5B" }, + { "DOD", "RE9E" }, + { "doe", "ZG9l" }, + { "dog", "ZG9n" }, + { "don", "ZG9u" }, + { "dot", "ZG90" }, + { "Dow", "RG93" }, + { "dry", "ZHJ5" }, + { "d's", "ZCdz" }, + { "dub", "ZHVi" }, + { "dud", "ZHVk" }, + { "due", "ZHVl" }, + { "dug", "ZHVn" }, + { "dun", "ZHVu" }, + { "dye", "ZHll" }, + { "ear", "ZWFy" }, + { "eat", "ZWF0" }, + { "ebb", "ZWJi" }, + { "EDT", "RURU" }, + { "eel", "ZWVs" }, + { "eft", "ZWZ0" }, + { "e.g", "ZS5n" }, + { "egg", "ZWdn" }, + { "ego", "ZWdv" }, + { "eke", "ZWtl" }, + { "Eli", "RWxp" }, + { "elk", "ZWxr" }, + { "ell", "ZWxs" }, + { "elm", "ZWxt" }, + { "Ely", "RWx5" }, + { "end", "ZW5k" }, + { "Eng", "RW5n" }, + { "EPA", "RVBB" }, + { "era", "ZXJh" }, + { "ere", "ZXJl" }, + { "erg", "ZXJn" }, + { "err", "ZXJy" }, + { "e's", "ZSdz" }, + { "EST", "RVNU" }, + { "eta", "ZXRh" }, + { "etc", "ZXRj" }, + { "Eva", "RXZh" }, + { "eve", "ZXZl" }, + { "ewe", "ZXdl" }, + { "eye", "ZXll" }, + { "FAA", "RkFB" }, + { "fad", "ZmFk" }, + { "fag", "ZmFn" }, + { "fan", "ZmFu" }, + { "far", "ZmFy" }, + { "fat", "ZmF0" }, + { "fay", "ZmF5" }, + { "FBI", "RkJJ" }, + { "FCC", "RkND" }, + { "FDA", "RkRB" }, + { "Feb", "RmVi" }, + { "fed", "ZmVk" }, + { "fee", "ZmVl" }, + { "few", "ZmV3" }, + { "fib", "Zmli" }, + { "fig", "Zmln" }, + { "fin", "Zmlu" }, + { "fir", "Zmly" }, + { "fit", "Zml0" }, + { "fix", "Zml4" }, + { "Flo", "Rmxv" }, + { "flu", "Zmx1" }, + { "fly", "Zmx5" }, + { "FMC", "Rk1D" }, + { "fob", "Zm9i" }, + { "foe", "Zm9l" }, + { "fog", "Zm9n" }, + { "fop", "Zm9w" }, + { "for", "Zm9y" }, + { "fox", "Zm94" }, + { "FPC", "RlBD" }, + { "fro", "ZnJv" }, + { "fry", "ZnJ5" }, + { "f's", "Zidz" }, + { "FTC", "RlRD" }, + { "fum", "ZnVt" }, + { "fun", "ZnVu" }, + { "fur", "ZnVy" }, + { "gab", "Z2Fi" }, + { "gad", "Z2Fk" }, + { "gag", "Z2Fn" }, + { "gal", "Z2Fs" }, + { "gam", "Z2Ft" }, + { "GAO", "R0FP" }, + { "gap", "Z2Fw" }, + { "gar", "Z2Fy" }, + { "gas", "Z2Fz" }, + { "gay", "Z2F5" }, + { "gee", "Z2Vl" }, + { "gel", "Z2Vs" }, + { "gem", "Z2Vt" }, + { "get", "Z2V0" }, + { "gig", "Z2ln" }, + { "Gil", "R2ls" }, + { "gin", "Z2lu" }, + { "GMT", "R01U" }, + { "GNP", "R05Q" }, + { "gnu", "Z251" }, + { "Goa", "R29h" }, + { "gob", "Z29i" }, + { "god", "Z29k" }, + { "gog", "Z29n" }, + { "GOP", "R09Q" }, + { "got", "Z290" }, + { "GPO", "R1BP" }, + { "g's", "Zydz" }, + { "GSA", "R1NB" }, + { "gum", "Z3Vt" }, + { "gun", "Z3Vu" }, + { "Gus", "R3Vz" }, + { "gut", "Z3V0" }, + { "guy", "Z3V5" }, + { "gym", "Z3lt" }, + { "gyp", "Z3lw" }, + { "had", "aGFk" }, + { "Hal", "SGFs" }, + { "ham", "aGFt" }, + { "Han", "SGFu" }, + { "hap", "aGFw" }, + { "hat", "aGF0" }, + { "haw", "aGF3" }, + { "hay", "aGF5" }, + { "hem", "aGVt" }, + { "hen", "aGVu" }, + { "her", "aGVy" }, + { "hew", "aGV3" }, + { "hex", "aGV4" }, + { "hey", "aGV5" }, + { "hid", "aGlk" }, + { "him", "aGlt" }, + { "hip", "aGlw" }, + { "his", "aGlz" }, + { "hit", "aGl0" }, + { "hob", "aG9i" }, + { "hoc", "aG9j" }, + { "hoe", "aG9l" }, + { "hog", "aG9n" }, + { "hoi", "aG9p" }, + { "Hom", "SG9t" }, + { "hop", "aG9w" }, + { "hot", "aG90" }, + { "how", "aG93" }, + { "hoy", "aG95" }, + { "h's", "aCdz" }, + { "hub", "aHVi" }, + { "hue", "aHVl" }, + { "hug", "aHVn" }, + { "huh", "aHVo" }, + { "hum", "aHVt" }, + { "Hun", "SHVu" }, + { "hut", "aHV0" }, + { "Ian", "SWFu" }, + { "IBM", "SUJN" }, + { "Ibn", "SWJu" }, + { "ICC", "SUND" }, + { "ice", "aWNl" }, + { "icy", "aWN5" }, + { "I'd", "SSdk" }, + { "Ida", "SWRh" }, + { "i.e", "aS5l" }, + { "iii", "aWlp" }, + { "Ike", "SWtl" }, + { "ill", "aWxs" }, + { "I'm", "SSdt" }, + { "imp", "aW1w" }, + { "Inc", "SW5j" }, + { "ink", "aW5r" }, + { "inn", "aW5u" }, + { "ion", "aW9u" }, + { "Ira", "SXJh" }, + { "ire", "aXJl" }, + { "irk", "aXJr" }, + { "IRS", "SVJT" }, + { "i's", "aSdz" }, + { "Ito", "SXRv" }, + { "ITT", "SVRU" }, + { "ivy", "aXZ5" }, + { "jab", "amFi" }, + { "jag", "amFn" }, + { "jam", "amFt" }, + { "Jan", "SmFu" }, + { "jar", "amFy" }, + { "jaw", "amF3" }, + { "jay", "amF5" }, + { "Jed", "SmVk" }, + { "jet", "amV0" }, + { "Jew", "SmV3" }, + { "jig", "amln" }, + { "Jim", "Smlt" }, + { "job", "am9i" }, + { "Joe", "Sm9l" }, + { "jog", "am9n" }, + { "Jon", "Sm9u" }, + { "jot", "am90" }, + { "joy", "am95" }, + { "j's", "aidz" }, + { "jug", "anVn" }, + { "jut", "anV0" }, + { "Kay", "S2F5" }, + { "keg", "a2Vn" }, + { "ken", "a2Vu" }, + { "key", "a2V5" }, + { "kid", "a2lk" }, + { "Kim", "S2lt" }, + { "kin", "a2lu" }, + { "kit", "a2l0" }, + { "k's", "aydz" }, + { "lab", "bGFi" }, + { "lac", "bGFj" }, + { "lad", "bGFk" }, + { "lag", "bGFn" }, + { "lam", "bGFt" }, + { "Lao", "TGFv" }, + { "lap", "bGFw" }, + { "law", "bGF3" }, + { "lax", "bGF4" }, + { "lay", "bGF5" }, + { "lea", "bGVh" }, + { "led", "bGVk" }, + { "lee", "bGVl" }, + { "leg", "bGVn" }, + { "Len", "TGVu" }, + { "Leo", "TGVv" }, + { "let", "bGV0" }, + { "Lev", "TGV2" }, + { "Lew", "TGV3" }, + { "lew", "bGV3" }, + { "lid", "bGlk" }, + { "lie", "bGll" }, + { "lim", "bGlt" }, + { "Lin", "TGlu" }, + { "lip", "bGlw" }, + { "lit", "bGl0" }, + { "Liz", "TGl6" }, + { "lob", "bG9i" }, + { "log", "bG9n" }, + { "lop", "bG9w" }, + { "Los", "TG9z" }, + { "lot", "bG90" }, + { "Lou", "TG91" }, + { "low", "bG93" }, + { "loy", "bG95" }, + { "l's", "bCdz" }, + { "LSI", "TFNJ" }, + { "Ltd", "THRk" }, + { "LTV", "TFRW" }, + { "lug", "bHVn" }, + { "lux", "bHV4" }, + { "lye", "bHll" }, + { "Mac", "TWFj" }, + { "mad", "bWFk" }, + { "Mae", "TWFl" }, + { "man", "bWFu" }, + { "Mao", "TWFv" }, + { "map", "bWFw" }, + { "mar", "bWFy" }, + { "mat", "bWF0" }, + { "maw", "bWF3" }, + { "Max", "TWF4" }, + { "max", "bWF4" }, + { "may", "bWF5" }, + { "MBA", "TUJB" }, + { "Meg", "TWVn" }, + { "Mel", "TWVs" }, + { "men", "bWVu" }, + { "met", "bWV0" }, + { "mew", "bWV3" }, + { "mid", "bWlk" }, + { "mig", "bWln" }, + { "min", "bWlu" }, + { "MIT", "TUlU" }, + { "mix", "bWl4" }, + { "mob", "bW9i" }, + { "Moe", "TW9l" }, + { "moo", "bW9v" }, + { "mop", "bW9w" }, + { "mot", "bW90" }, + { "mow", "bW93" }, + { "MPH", "TVBI" }, + { "Mrs", "TXJz" }, + { "m's", "bSdz" }, + { "mud", "bXVk" }, + { "mug", "bXVn" }, + { "mum", "bXVt" }, + { "nab", "bmFi" }, + { "nag", "bmFn" }, + { "Nan", "TmFu" }, + { "nap", "bmFw" }, + { "Nat", "TmF0" }, + { "nay", "bmF5" }, + { "NBC", "TkJD" }, + { "NBS", "TkJT" }, + { "NCO", "TkNP" }, + { "NCR", "TkNS" }, + { "Ned", "TmVk" }, + { "nee", "bmVl" }, + { "net", "bmV0" }, + { "new", "bmV3" }, + { "nib", "bmli" }, + { "NIH", "TklI" }, + { "nil", "bmls" }, + { "nip", "bmlw" }, + { "nit", "bml0" }, + { "NNE", "Tk5F" }, + { "NNW", "Tk5X" }, + { "nob", "bm9i" }, + { "nod", "bm9k" }, + { "non", "bm9u" }, + { "nor", "bm9y" }, + { "not", "bm90" }, + { "Nov", "Tm92" }, + { "now", "bm93" }, + { "NRC", "TlJD" }, + { "n's", "bidz" }, + { "NSF", "TlNG" }, + { "nun", "bnVu" }, + { "nut", "bnV0" }, + { "NYC", "TllD" }, + { "NYU", "TllV" }, + { "oaf", "b2Fm" }, + { "oak", "b2Fr" }, + { "oar", "b2Fy" }, + { "oat", "b2F0" }, + { "Oct", "T2N0" }, + { "odd", "b2Rk" }, + { "ode", "b2Rl" }, + { "off", "b2Zm" }, + { "oft", "b2Z0" }, + { "ohm", "b2ht" }, + { "oil", "b2ls" }, + { "old", "b2xk" }, + { "one", "b25l" }, + { "opt", "b3B0" }, + { "orb", "b3Ji" }, + { "ore", "b3Jl" }, + { "Orr", "T3Jy" }, + { "o's", "bydz" }, + { "Ott", "T3R0" }, + { "our", "b3Vy" }, + { "out", "b3V0" }, + { "ova", "b3Zh" }, + { "owe", "b3dl" }, + { "owl", "b3ds" }, + { "own", "b3du" }, + { "pad", "cGFk" }, + { "pal", "cGFs" }, + { "Pam", "UGFt" }, + { "pan", "cGFu" }, + { "pap", "cGFw" }, + { "par", "cGFy" }, + { "pat", "cGF0" }, + { "paw", "cGF3" }, + { "pax", "cGF4" }, + { "pay", "cGF5" }, + { "Paz", "UGF6" }, + { "PBS", "UEJT" }, + { "PDP", "UERQ" }, + { "pea", "cGVh" }, + { "pee", "cGVl" }, + { "peg", "cGVn" }, + { "pen", "cGVu" }, + { "pep", "cGVw" }, + { "per", "cGVy" }, + { "pet", "cGV0" }, + { "pew", "cGV3" }, + { "PhD", "UGhE" }, + { "phi", "cGhp" }, + { "pie", "cGll" }, + { "pig", "cGln" }, + { "pin", "cGlu" }, + { "pip", "cGlw" }, + { "pit", "cGl0" }, + { "ply", "cGx5" }, + { "pod", "cG9k" }, + { "Poe", "UG9l" }, + { "poi", "cG9p" }, + { "pol", "cG9s" }, + { "pop", "cG9w" }, + { "pot", "cG90" }, + { "pow", "cG93" }, + { "ppm", "cHBt" }, + { "pro", "cHJv" }, + { "pry", "cHJ5" }, + { "p's", "cCdz" }, + { "psi", "cHNp" }, + { "PTA", "UFRB" }, + { "pub", "cHVi" }, + { "PUC", "UFVD" }, + { "pug", "cHVn" }, + { "pun", "cHVu" }, + { "pup", "cHVw" }, + { "pus", "cHVz" }, + { "put", "cHV0" }, + { "PVC", "UFZD" }, + { "QED", "UUVE" }, + { "q's", "cSdz" }, + { "qua", "cXVh" }, + { "quo", "cXVv" }, + { "Rae", "UmFl" }, + { "rag", "cmFn" }, + { "raj", "cmFq" }, + { "ram", "cmFt" }, + { "ran", "cmFu" }, + { "rap", "cmFw" }, + { "rat", "cmF0" }, + { "raw", "cmF3" }, + { "ray", "cmF5" }, + { "RCA", "UkNB" }, + { "R&D", "UiZE" }, + { "reb", "cmVi" }, + { "red", "cmVk" }, + { "rep", "cmVw" }, + { "ret", "cmV0" }, + { "rev", "cmV2" }, + { "Rex", "UmV4" }, + { "rho", "cmhv" }, + { "rib", "cmli" }, + { "rid", "cmlk" }, + { "rig", "cmln" }, + { "rim", "cmlt" }, + { "Rio", "Umlv" }, + { "rip", "cmlw" }, + { "RNA", "Uk5B" }, + { "rob", "cm9i" }, + { "rod", "cm9k" }, + { "roe", "cm9l" }, + { "Ron", "Um9u" }, + { "rot", "cm90" }, + { "row", "cm93" }, + { "Roy", "Um95" }, + { "RPM", "UlBN" }, + { "r's", "cidz" }, + { "rub", "cnVi" }, + { "rue", "cnVl" }, + { "rug", "cnVn" }, + { "rum", "cnVt" }, + { "run", "cnVu" }, + { "rut", "cnV0" }, + { "rye", "cnll" }, + { "sac", "c2Fj" }, + { "sad", "c2Fk" }, + { "sag", "c2Fn" }, + { "Sal", "U2Fs" }, + { "Sam", "U2Ft" }, + { "San", "U2Fu" }, + { "Sao", "U2Fv" }, + { "sap", "c2Fw" }, + { "sat", "c2F0" }, + { "saw", "c2F3" }, + { "sax", "c2F4" }, + { "say", "c2F5" }, + { "Sci", "U2Np" }, + { "SCM", "U0NN" }, + { "sea", "c2Vh" }, + { "sec", "c2Vj" }, + { "see", "c2Vl" }, + { "sen", "c2Vu" }, + { "seq", "c2Vx" }, + { "set", "c2V0" }, + { "sew", "c2V3" }, + { "sex", "c2V4" }, + { "she", "c2hl" }, + { "Shu", "U2h1" }, + { "shy", "c2h5" }, + { "sib", "c2li" }, + { "sic", "c2lj" }, + { "sin", "c2lu" }, + { "sip", "c2lw" }, + { "sir", "c2ly" }, + { "sis", "c2lz" }, + { "sit", "c2l0" }, + { "six", "c2l4" }, + { "ski", "c2tp" }, + { "sky", "c2t5" }, + { "sly", "c2x5" }, + { "sob", "c29i" }, + { "Soc", "U29j" }, + { "sod", "c29k" }, + { "Sol", "U29s" }, + { "son", "c29u" }, + { "sop", "c29w" }, + { "sou", "c291" }, + { "sow", "c293" }, + { "soy", "c295" }, + { "spa", "c3Bh" }, + { "spy", "c3B5" }, + { "Sri", "U3Jp" }, + { "s's", "cydz" }, + { "SSE", "U1NF" }, + { "SST", "U1NU" }, + { "SSW", "U1NX" }, + { "Stu", "U3R1" }, + { "sub", "c3Vi" }, + { "sud", "c3Vk" }, + { "sue", "c3Vl" }, + { "sum", "c3Vt" }, + { "sun", "c3Vu" }, + { "sup", "c3Vw" }, + { "Sus", "U3Vz" }, + { "tab", "dGFi" }, + { "tad", "dGFk" }, + { "tag", "dGFn" }, + { "tam", "dGFt" }, + { "tan", "dGFu" }, + { "tao", "dGFv" }, + { "tap", "dGFw" }, + { "tar", "dGFy" }, + { "tat", "dGF0" }, + { "tau", "dGF1" }, + { "tax", "dGF4" }, + { "tea", "dGVh" }, + { "Ted", "VGVk" }, + { "ted", "dGVk" }, + { "tee", "dGVl" }, + { "Tel", "VGVs" }, + { "ten", "dGVu" }, + { "the", "dGhl" }, + { "thy", "dGh5" }, + { "tic", "dGlj" }, + { "tid", "dGlk" }, + { "tie", "dGll" }, + { "til", "dGls" }, + { "Tim", "VGlt" }, + { "tin", "dGlu" }, + { "tip", "dGlw" }, + { "tit", "dGl0" }, + { "TNT", "VE5U" }, + { "toe", "dG9l" }, + { "tog", "dG9n" }, + { "Tom", "VG9t" }, + { "ton", "dG9u" }, + { "too", "dG9v" }, + { "top", "dG9w" }, + { "tor", "dG9y" }, + { "tot", "dG90" }, + { "tow", "dG93" }, + { "toy", "dG95" }, + { "TRW", "VFJX" }, + { "try", "dHJ5" }, + { "t's", "dCdz" }, + { "TTL", "VFRM" }, + { "TTY", "VFRZ" }, + { "tub", "dHVi" }, + { "tug", "dHVn" }, + { "tum", "dHVt" }, + { "tun", "dHVu" }, + { "TVA", "VFZB" }, + { "TWA", "VFdB" }, + { "two", "dHdv" }, + { "TWX", "VFdY" }, + { "ugh", "dWdo" }, + { "UHF", "VUhG" }, + { "Uri", "VXJp" }, + { "urn", "dXJu" }, + { "U.S", "VS5T" }, + { "u's", "dSdz" }, + { "USA", "VVNB" }, + { "USC", "VVND" }, + { "use", "dXNl" }, + { "USN", "VVNO" }, + { "van", "dmFu" }, + { "vat", "dmF0" }, + { "vee", "dmVl" }, + { "vet", "dmV0" }, + { "vex", "dmV4" }, + { "VHF", "VkhG" }, + { "via", "dmlh" }, + { "vie", "dmll" }, + { "vii", "dmlp" }, + { "vis", "dmlz" }, + { "viz", "dml6" }, + { "von", "dm9u" }, + { "vow", "dm93" }, + { "v's", "didz" }, + { "WAC", "V0FD" }, + { "wad", "d2Fk" }, + { "wag", "d2Fn" }, + { "wah", "d2Fo" }, + { "wan", "d2Fu" }, + { "war", "d2Fy" }, + { "was", "d2Fz" }, + { "wax", "d2F4" }, + { "way", "d2F5" }, + { "web", "d2Vi" }, + { "wed", "d2Vk" }, + { "wee", "d2Vl" }, + { "Wei", "V2Vp" }, + { "wet", "d2V0" }, + { "who", "d2hv" }, + { "why", "d2h5" }, + { "wig", "d2ln" }, + { "win", "d2lu" }, + { "wit", "d2l0" }, + { "woe", "d29l" }, + { "wok", "d29r" }, + { "won", "d29u" }, + { "woo", "d29v" }, + { "wop", "d29w" }, + { "wow", "d293" }, + { "wry", "d3J5" }, + { "w's", "dydz" }, + { "x's", "eCdz" }, + { "yah", "eWFo" }, + { "yak", "eWFr" }, + { "yam", "eWFt" }, + { "yap", "eWFw" }, + { "yaw", "eWF3" }, + { "yea", "eWVh" }, + { "yen", "eWVu" }, + { "yet", "eWV0" }, + { "yin", "eWlu" }, + { "yip", "eWlw" }, + { "yon", "eW9u" }, + { "you", "eW91" }, + { "yow", "eW93" }, + { "y's", "eSdz" }, + { "yuh", "eXVo" }, + { "zag", "emFn" }, + { "Zan", "WmFu" }, + { "zap", "emFw" }, + { "Zen", "WmVu" }, + { "zig", "emln" }, + { "zip", "emlw" }, + { "Zoe", "Wm9l" }, + { "zoo", "em9v" }, + { "z's", "eidz" }, + /* the false rumors file */ + { "\"So when I die, the first thing I will see in heaven is a score list?\"", + "IlNvIHdoZW4gSSBkaWUsIHRoZSBmaXJzdCB0aGluZyBJIHdpbGwgc2VlIGluIGhlYXZlbiBpcyBhIHNjb3JlIGxpc3Q/Ig==" }, + { "1st Law of Hacking: leaving is much more difficult than entering.", + "MXN0IExhdyBvZiBIYWNraW5nOiBsZWF2aW5nIGlzIG11Y2ggbW9yZSBkaWZmaWN1bHQgdGhhbiBlbnRlcmluZy4=" }, + { "2nd Law of Hacking: first in, first out.", + "Mm5kIExhdyBvZiBIYWNraW5nOiBmaXJzdCBpbiwgZmlyc3Qgb3V0Lg==" }, + { "3rd Law of Hacking: the last blow counts most.", + "M3JkIExhdyBvZiBIYWNraW5nOiB0aGUgbGFzdCBibG93IGNvdW50cyBtb3N0Lg==" }, + { "4th Law of Hacking: you will find the exit at the entrance.", + "NHRoIExhdyBvZiBIYWNraW5nOiB5b3Ugd2lsbCBmaW5kIHRoZSBleGl0IGF0IHRoZSBlbnRyYW5jZS4=" }, + { "A chameleon imitating a mail daemon often delivers scrolls of fire.", + "QSBjaGFtZWxlb24gaW1pdGF0aW5nIGEgbWFpbCBkYWVtb24gb2Z0ZW4gZGVsaXZlcnMgc2Nyb2xscyBvZiBmaXJlLg==" }, + { "A cockatrice corpse is guaranteed to be untainted!", + "QSBjb2NrYXRyaWNlIGNvcnBzZSBpcyBndWFyYW50ZWVkIHRvIGJlIHVudGFpbnRlZCE=" }, + { "A dead cockatrice is just a dead lizard.", + "QSBkZWFkIGNvY2thdHJpY2UgaXMganVzdCBhIGRlYWQgbGl6YXJkLg==" }, + { "A dragon is just a snake that ate a scroll of fire.", + "QSBkcmFnb24gaXMganVzdCBhIHNuYWtlIHRoYXQgYXRlIGEgc2Nyb2xsIG9mIGZpcmUu" }, + { "A fading corridor enlightens your insight.", + "QSBmYWRpbmcgY29ycmlkb3IgZW5saWdodGVucyB5b3VyIGluc2lnaHQu" }, + { "A glowing potion is too hot to drink.", + "QSBnbG93aW5nIHBvdGlvbiBpcyB0b28gaG90IHRvIGRyaW5rLg==" }, + { "A good amulet may protect you against guards.", + "QSBnb29kIGFtdWxldCBtYXkgcHJvdGVjdCB5b3UgYWdhaW5zdCBndWFyZHMu" }, + { "A lizard corpse is a good thing to turn undead.", + "QSBsaXphcmQgY29ycHNlIGlzIGEgZ29vZCB0aGluZyB0byB0dXJuIHVuZGVhZC4=" }, + { "A long worm can be defined recursively. So how should you attack it?", + "QSBsb25nIHdvcm0gY2FuIGJlIGRlZmluZWQgcmVjdXJzaXZlbHkuIFNvIGhvdyBzaG91bGQgeW91IGF0dGFjayBpdD8=" }, + { "A monstrous mind is a toy forever.", + "QSBtb25zdHJvdXMgbWluZCBpcyBhIHRveSBmb3JldmVyLg==" }, + { "A nymph will be very pleased if you call her by her real name: Lorelei.", + "QSBueW1waCB3aWxsIGJlIHZlcnkgcGxlYXNlZCBpZiB5b3UgY2FsbCBoZXIgYnkgaGVyIHJlYWwgbmFtZTogTG9yZWxlaS4=" }, + { "A ring of dungeon master control is a great find.", + "QSByaW5nIG9mIGR1bmdlb24gbWFzdGVyIGNvbnRyb2wgaXMgYSBncmVhdCBmaW5kLg==" }, + { "A ring of extra ring finger is useless if not enchanted.", + "QSByaW5nIG9mIGV4dHJhIHJpbmcgZmluZ2VyIGlzIHVzZWxlc3MgaWYgbm90IGVuY2hhbnRlZC4=" }, + { "A rope may form a trail in a maze.", + "QSByb3BlIG1heSBmb3JtIGEgdHJhaWwgaW4gYSBtYXplLg==" }, + { "A staff may recharge if you drop it for awhile.", + "QSBzdGFmZiBtYXkgcmVjaGFyZ2UgaWYgeW91IGRyb3AgaXQgZm9yIGF3aGlsZS4=" }, + { "A visit to the Zoo is very educational; you meet interesting animals.", + "QSB2aXNpdCB0byB0aGUgWm9vIGlzIHZlcnkgZWR1Y2F0aW9uYWw7IHlvdSBtZWV0IGludGVyZXN0aW5nIGFuaW1hbHMu" }, + { "A wand of deaf is a more dangerous weapon than a wand of sheep.", + "QSB3YW5kIG9mIGRlYWYgaXMgYSBtb3JlIGRhbmdlcm91cyB3ZWFwb24gdGhhbiBhIHdhbmQgb2Ygc2hlZXAu" }, + { "A wand of vibration might bring the whole cave crashing about your ears.", + "QSB3YW5kIG9mIHZpYnJhdGlvbiBtaWdodCBicmluZyB0aGUgd2hvbGUgY2F2ZSBjcmFzaGluZyBhYm91dCB5b3VyIGVhcnMu" }, + { "A winner never quits. A quitter never wins.", + "QSB3aW5uZXIgbmV2ZXIgcXVpdHMuIEEgcXVpdHRlciBuZXZlciB3aW5zLg==" }, + { "A wish? Okay, make me a fortune cookie!", + "QSB3aXNoPyBPa2F5LCBtYWtlIG1lIGEgZm9ydHVuZSBjb29raWUh" }, + { "Afraid of mimics? Try to wear a ring of true seeing.", + "QWZyYWlkIG9mIG1pbWljcz8gVHJ5IHRvIHdlYXIgYSByaW5nIG9mIHRydWUgc2VlaW5nLg==" }, + { "All monsters are created evil, but some are more evil than others.", + "QWxsIG1vbnN0ZXJzIGFyZSBjcmVhdGVkIGV2aWwsIGJ1dCBzb21lIGFyZSBtb3JlIGV2aWwgdGhhbiBvdGhlcnMu" }, + { "Always attack a floating eye from behind!", + "QWx3YXlzIGF0dGFjayBhIGZsb2F0aW5nIGV5ZSBmcm9tIGJlaGluZCE=" }, + { "An elven cloak is always the height of fashion.", + "QW4gZWx2ZW4gY2xvYWsgaXMgYWx3YXlzIHRoZSBoZWlnaHQgb2YgZmFzaGlvbi4=" }, + { "Any small object that is accidentally dropped will hide under a larger object.", + "QW55IHNtYWxsIG9iamVjdCB0aGF0IGlzIGFjY2lkZW50YWxseSBkcm9wcGVkIHdpbGwgaGlkZSB1bmRlciBhIGxhcmdlciBvYmplY3Qu" }, + { "Balrogs do not appear above level 20.", + "QmFscm9ncyBkbyBub3QgYXBwZWFyIGFib3ZlIGxldmVsIDIwLg==" }, + { "Banana peels work especially well against Keystone Kops.", + "QmFuYW5hIHBlZWxzIHdvcmsgZXNwZWNpYWxseSB3ZWxsIGFnYWluc3QgS2V5c3RvbmUgS29wcy4=" }, + { "Be careful when eating bananas. Monsters might slip on the peels.", + "QmUgY2FyZWZ1bCB3aGVuIGVhdGluZyBiYW5hbmFzLiBNb25zdGVycyBtaWdodCBzbGlwIG9uIHRoZSBwZWVscy4=" }, + { "Better leave the dungeon; otherwise you might get hurt badly.", + "QmV0dGVyIGxlYXZlIHRoZSBkdW5nZW9uOyBvdGhlcndpc2UgeW91IG1pZ2h0IGdldCBodXJ0IGJhZGx5Lg==" }, + { "Beware of the potion of nitroglycerin -- it's not for the weak of heart.", + "QmV3YXJlIG9mIHRoZSBwb3Rpb24gb2Ygbml0cm9nbHljZXJpbiAtLSBpdCdzIG5vdCBmb3IgdGhlIHdlYWsgb2YgaGVhcnQu" }, + { "Beware: there's always a chance that your wand explodes as you try to zap it!", + "QmV3YXJlOiB0aGVyZSdzIGFsd2F5cyBhIGNoYW5jZSB0aGF0IHlvdXIgd2FuZCBleHBsb2RlcyBhcyB5b3UgdHJ5IHRvIHphcCBpdCE=" }, + { "Beyond the 23rd level lies a happy retirement in a room of your own.", + "QmV5b25kIHRoZSAyM3JkIGxldmVsIGxpZXMgYSBoYXBweSByZXRpcmVtZW50IGluIGEgcm9vbSBvZiB5b3VyIG93bi4=" }, + { "Changing your suit without dropping your sword? You must be kidding!", + "Q2hhbmdpbmcgeW91ciBzdWl0IHdpdGhvdXQgZHJvcHBpbmcgeW91ciBzd29yZD8gWW91IG11c3QgYmUga2lkZGluZyE=" }, + { "Cockatrices might turn themselves to stone faced with a mirror.", + "Q29ja2F0cmljZXMgbWlnaHQgdHVybiB0aGVtc2VsdmVzIHRvIHN0b25lIGZhY2VkIHdpdGggYSBtaXJyb3Iu" }, + { "Consumption of home-made food is strictly forbidden in this dungeon.", + "Q29uc3VtcHRpb24gb2YgaG9tZS1tYWRlIGZvb2QgaXMgc3RyaWN0bHkgZm9yYmlkZGVuIGluIHRoaXMgZHVuZ2Vvbi4=" }, + { "Dark room? Your chance to develop your photographs!", + "RGFyayByb29tPyBZb3VyIGNoYW5jZSB0byBkZXZlbG9wIHlvdXIgcGhvdG9ncmFwaHMh" }, + { "Dark rooms are not *completely* dark: just wait and let your eyes adjust...", + "RGFyayByb29tcyBhcmUgbm90ICpjb21wbGV0ZWx5KiBkYXJrOiBqdXN0IHdhaXQgYW5kIGxldCB5b3VyIGV5ZXMgYWRqdXN0Li4u" }, + { "David London sez, \"Hey guys, *WIELD* a lizard corpse against a cockatrice!\"", + "RGF2aWQgTG9uZG9uIHNleiwgIkhleSBndXlzLCAqV0lFTEQqIGEgbGl6YXJkIGNvcnBzZSBhZ2FpbnN0IGEgY29ja2F0cmljZSEi" }, + { "Death is just life's way of telling you you've been fired.", + "RGVhdGggaXMganVzdCBsaWZlJ3Mgd2F5IG9mIHRlbGxpbmcgeW91IHlvdSd2ZSBiZWVuIGZpcmVkLg==" }, + { "Demi-gods don't need any help from the gods.", + "RGVtaS1nb2RzIGRvbid0IG5lZWQgYW55IGhlbHAgZnJvbSB0aGUgZ29kcy4=" }, + { "Demons *HATE* Priests and Priestesses.", + "RGVtb25zICpIQVRFKiBQcmllc3RzIGFuZCBQcmllc3Rlc3Nlcy4=" }, + { "Didn't you forget to pay?", + "RGlkbid0IHlvdSBmb3JnZXQgdG8gcGF5Pw==" }, + { "Didn't your mother tell you not to eat food off the floor?", + "RGlkbid0IHlvdXIgbW90aGVyIHRlbGwgeW91IG5vdCB0byBlYXQgZm9vZCBvZmYgdGhlIGZsb29yPw==" }, + { "Direct a direct hit on your direct opponent, directing in the right direction.", + "RGlyZWN0IGEgZGlyZWN0IGhpdCBvbiB5b3VyIGRpcmVjdCBvcHBvbmVudCwgZGlyZWN0aW5nIGluIHRoZSByaWdodCBkaXJlY3Rpb24u" }, + { "Do you want to make more money? Sure, we all do! Join the Fort Ludios guard!", + "RG8geW91IHdhbnQgdG8gbWFrZSBtb3JlIG1vbmV5PyBTdXJlLCB3ZSBhbGwgZG8hIEpvaW4gdGhlIEZvcnQgTHVkaW9zIGd1YXJkIQ==" }, + { "Don't eat too much: you might start hiccoughing!", + "RG9uJ3QgZWF0IHRvbyBtdWNoOiB5b3UgbWlnaHQgc3RhcnQgaGljY291Z2hpbmch" }, + { "Don't play hack at your work; your boss might hit you!", + "RG9uJ3QgcGxheSBoYWNrIGF0IHlvdXIgd29yazsgeW91ciBib3NzIG1pZ2h0IGhpdCB5b3Uh" }, + { "Don't tell a soul you found a secret door, otherwise it isn't a secret anymore.", + "RG9uJ3QgdGVsbCBhIHNvdWwgeW91IGZvdW5kIGEgc2VjcmV0IGRvb3IsIG90aGVyd2lzZSBpdCBpc24ndCBhIHNlY3JldCBhbnltb3JlLg==" }, + { "Drinking potions of booze may land you in jail if you are under 21.", + "RHJpbmtpbmcgcG90aW9ucyBvZiBib296ZSBtYXkgbGFuZCB5b3UgaW4gamFpbCBpZiB5b3UgYXJlIHVuZGVyIDIxLg==" }, + { "Drop your vanity and get rid of your jewels! Pickpockets about!", + "RHJvcCB5b3VyIHZhbml0eSBhbmQgZ2V0IHJpZCBvZiB5b3VyIGpld2VscyEgUGlja3BvY2tldHMgYWJvdXQh" }, + { "Eat 10 cloves of garlic and keep all humans at a two-square distance.", + "RWF0IDEwIGNsb3ZlcyBvZiBnYXJsaWMgYW5kIGtlZXAgYWxsIGh1bWFucyBhdCBhIHR3by1zcXVhcmUgZGlzdGFuY2Uu" }, + { "Eels hide under mud. Use a unicorn to clear the water and make them visible.", + "RWVscyBoaWRlIHVuZGVyIG11ZC4gVXNlIGEgdW5pY29ybiB0byBjbGVhciB0aGUgd2F0ZXIgYW5kIG1ha2UgdGhlbSB2aXNpYmxlLg==" }, + { "Engrave your wishes with a wand of wishing.", + "RW5ncmF2ZSB5b3VyIHdpc2hlcyB3aXRoIGEgd2FuZCBvZiB3aXNoaW5nLg==" }, + { "Eventually you will come to admire the swift elegance of a retreating nymph.", + "RXZlbnR1YWxseSB5b3Ugd2lsbCBjb21lIHRvIGFkbWlyZSB0aGUgc3dpZnQgZWxlZ2FuY2Ugb2YgYSByZXRyZWF0aW5nIG55bXBoLg==" }, + { "Ever heard hissing outside? I *knew* you hadn't!", + "RXZlciBoZWFyZCBoaXNzaW5nIG91dHNpZGU/IEkgKmtuZXcqIHlvdSBoYWRuJ3Qh" }, + { "Ever lifted a dragon corpse?", + "RXZlciBsaWZ0ZWQgYSBkcmFnb24gY29ycHNlPw==" }, + { "Ever seen a leocrotta dancing the tengu?", + "RXZlciBzZWVuIGEgbGVvY3JvdHRhIGRhbmNpbmcgdGhlIHRlbmd1Pw==" }, + { "Ever seen your weapon glow plaid?", + "RXZlciBzZWVuIHlvdXIgd2VhcG9uIGdsb3cgcGxhaWQ/" }, + { "Ever tamed a shopkeeper?", + "RXZlciB0YW1lZCBhIHNob3BrZWVwZXI/" }, + { "Ever tried digging through a Vault Guard?", + "RXZlciB0cmllZCBkaWdnaW5nIHRocm91Z2ggYSBWYXVsdCBHdWFyZD8=" }, + { "Ever tried enchanting a rope?", + "RXZlciB0cmllZCBlbmNoYW50aW5nIGEgcm9wZT8=" }, + { "Floating eyes can't stand Hawaiian shirts.", + "RmxvYXRpbmcgZXllcyBjYW4ndCBzdGFuZCBIYXdhaWlhbiBzaGlydHMu" }, + { "For any remedy there is a misery.", + "Rm9yIGFueSByZW1lZHkgdGhlcmUgaXMgYSBtaXNlcnku" }, + { "Giant bats turn into giant vampires.", + "R2lhbnQgYmF0cyB0dXJuIGludG8gZ2lhbnQgdmFtcGlyZXMu" }, + { "Good day for overcoming obstacles. Try a steeplechase.", + "R29vZCBkYXkgZm9yIG92ZXJjb21pbmcgb2JzdGFjbGVzLiBUcnkgYSBzdGVlcGxlY2hhc2Uu" }, + { "Half Moon tonight. (At least it's better than no Moon at all.)", + "SGFsZiBNb29uIHRvbmlnaHQuIChBdCBsZWFzdCBpdCdzIGJldHRlciB0aGFuIG5vIE1vb24gYXQgYWxsLik=" }, + { "Help! I'm being held prisoner in a fortune cookie factory!", + "SGVscCEgSSdtIGJlaW5nIGhlbGQgcHJpc29uZXIgaW4gYSBmb3J0dW5lIGNvb2tpZSBmYWN0b3J5IQ==" }, + { "Housecats have nine lives, kittens only one.", + "SG91c2VjYXRzIGhhdmUgbmluZSBsaXZlcywga2l0dGVucyBvbmx5IG9uZS4=" }, + { "How long can you tread water?", + "SG93IGxvbmcgY2FuIHlvdSB0cmVhZCB3YXRlcj8=" }, + { "Hungry? There is an abundance of food on the next level.", + "SHVuZ3J5PyBUaGVyZSBpcyBhbiBhYnVuZGFuY2Ugb2YgZm9vZCBvbiB0aGUgbmV4dCBsZXZlbC4=" }, + { "I guess you've never hit a mail daemon with the Amulet of Yendor...", + "SSBndWVzcyB5b3UndmUgbmV2ZXIgaGl0IGEgbWFpbCBkYWVtb24gd2l0aCB0aGUgQW11bGV0IG9mIFllbmRvci4uLg==" }, + { "If you are the shopkeeper, you can take things for free.", + "SWYgeW91IGFyZSB0aGUgc2hvcGtlZXBlciwgeW91IGNhbiB0YWtlIHRoaW5ncyBmb3IgZnJlZS4=" }, + { "If you can't learn to do it well, learn to enjoy doing it badly.", + "SWYgeW91IGNhbid0IGxlYXJuIHRvIGRvIGl0IHdlbGwsIGxlYXJuIHRvIGVuam95IGRvaW5nIGl0IGJhZGx5Lg==" }, + { "If you thought the Wizard was bad, just wait till you meet the Warlord!", + "SWYgeW91IHRob3VnaHQgdGhlIFdpemFyZCB3YXMgYmFkLCBqdXN0IHdhaXQgdGlsbCB5b3UgbWVldCB0aGUgV2FybG9yZCE=" }, + { "If you turn blind, don't expect your dog to be turned into a seeing-eye dog.", + "SWYgeW91IHR1cm4gYmxpbmQsIGRvbid0IGV4cGVjdCB5b3VyIGRvZyB0byBiZSB0dXJuZWQgaW50byBhIHNlZWluZy1leWUgZG9nLg==" }, + { "If you want to feel great, you must eat something real big.", + "SWYgeW91IHdhbnQgdG8gZmVlbCBncmVhdCwgeW91IG11c3QgZWF0IHNvbWV0aGluZyByZWFsIGJpZy4=" }, + { "If you want to float, you'd better eat a floating eye.", + "SWYgeW91IHdhbnQgdG8gZmxvYXQsIHlvdSdkIGJldHRlciBlYXQgYSBmbG9hdGluZyBleWUu" }, + { "If your ghost kills a player, it increases your score.", + "SWYgeW91ciBnaG9zdCBraWxscyBhIHBsYXllciwgaXQgaW5jcmVhc2VzIHlvdXIgc2NvcmUu" }, + { "Increase mindpower: Tame your own ghost!", + "SW5jcmVhc2UgbWluZHBvd2VyOiBUYW1lIHlvdXIgb3duIGdob3N0IQ==" }, + { "It furthers one to see the great man.", + "SXQgZnVydGhlcnMgb25lIHRvIHNlZSB0aGUgZ3JlYXQgbWFuLg==" }, + { "It's easy to overlook a monster in a wood.", + "SXQncyBlYXN5IHRvIG92ZXJsb29rIGEgbW9uc3RlciBpbiBhIHdvb2Qu" }, + { "Just below any trapdoor there may be another one. Just keep falling!", + "SnVzdCBiZWxvdyBhbnkgdHJhcGRvb3IgdGhlcmUgbWF5IGJlIGFub3RoZXIgb25lLiBKdXN0IGtlZXAgZmFsbGluZyE=" }, + { "Katanas are very sharp; watch you don't cut yourself.", + "S2F0YW5hcyBhcmUgdmVyeSBzaGFycDsgd2F0Y2ggeW91IGRvbid0IGN1dCB5b3Vyc2VsZi4=" }, + { "Keep a clear mind: quaff clear potions.", + "S2VlcCBhIGNsZWFyIG1pbmQ6IHF1YWZmIGNsZWFyIHBvdGlvbnMu" }, + { "Kicking the terminal doesn't hurt the monsters.", + "S2lja2luZyB0aGUgdGVybWluYWwgZG9lc24ndCBodXJ0IHRoZSBtb25zdGVycy4=" }, + { "Killer bees keep appearing till you kill their queen.", + "S2lsbGVyIGJlZXMga2VlcCBhcHBlYXJpbmcgdGlsbCB5b3Uga2lsbCB0aGVpciBxdWVlbi4=" }, + { "Killer bunnies can be tamed with carrots only.", + "S2lsbGVyIGJ1bm5pZXMgY2FuIGJlIHRhbWVkIHdpdGggY2Fycm90cyBvbmx5Lg==" }, + { "Latest news? Put `rec.games.roguelike.nethack' in your .newsrc!", + "TGF0ZXN0IG5ld3M/IFB1dCBgcmVjLmdhbWVzLnJvZ3VlbGlrZS5uZXRoYWNrJyBpbiB5b3VyIC5uZXdzcmMh" }, + { "Learn how to spell. Play NetHack!", + "TGVhcm4gaG93IHRvIHNwZWxsLiBQbGF5IE5ldEhhY2sh" }, + { "Leprechauns hide their gold in a secret room.", + "TGVwcmVjaGF1bnMgaGlkZSB0aGVpciBnb2xkIGluIGEgc2VjcmV0IHJvb20u" }, + { "Let your fingers do the walking on the yulkjhnb keys.", + "TGV0IHlvdXIgZmluZ2VycyBkbyB0aGUgd2Fsa2luZyBvbiB0aGUgeXVsa2pobmIga2V5cy4=" }, + { "Let's face it: this time you're not going to win.", + "TGV0J3MgZmFjZSBpdDogdGhpcyB0aW1lIHlvdSdyZSBub3QgZ29pbmcgdG8gd2luLg==" }, + { "Let's have a party, drink a lot of booze.", + "TGV0J3MgaGF2ZSBhIHBhcnR5LCBkcmluayBhIGxvdCBvZiBib296ZS4=" }, + { "Liquor sellers do not drink; they hate to see you twice.", + "TGlxdW9yIHNlbGxlcnMgZG8gbm90IGRyaW5rOyB0aGV5IGhhdGUgdG8gc2VlIHlvdSB0d2ljZS4=" }, + { "Lunar eclipse tonight. May as well quit now!", + "THVuYXIgZWNsaXBzZSB0b25pZ2h0LiBNYXkgYXMgd2VsbCBxdWl0IG5vdyE=" }, + { "Meeting your own ghost decreases your luck considerably!", + "TWVldGluZyB5b3VyIG93biBnaG9zdCBkZWNyZWFzZXMgeW91ciBsdWNrIGNvbnNpZGVyYWJseSE=" }, + { "Money to invest? Take it to the local branch of the Magic Memory Vault!", + "TW9uZXkgdG8gaW52ZXN0PyBUYWtlIGl0IHRvIHRoZSBsb2NhbCBicmFuY2ggb2YgdGhlIE1hZ2ljIE1lbW9yeSBWYXVsdCE=" }, + { "Monsters come from nowhere to hit you everywhere.", + "TW9uc3RlcnMgY29tZSBmcm9tIG5vd2hlcmUgdG8gaGl0IHlvdSBldmVyeXdoZXJlLg==" }, + { "Monsters sleep because you are boring, not because they ever get tired.", + "TW9uc3RlcnMgc2xlZXAgYmVjYXVzZSB5b3UgYXJlIGJvcmluZywgbm90IGJlY2F1c2UgdGhleSBldmVyIGdldCB0aXJlZC4=" }, + { "Most monsters prefer minced meat. That's why they are hitting you!", + "TW9zdCBtb25zdGVycyBwcmVmZXIgbWluY2VkIG1lYXQuIFRoYXQncyB3aHkgdGhleSBhcmUgaGl0dGluZyB5b3Uh" }, + { "Most of the bugs in NetHack are on the floor.", + "TW9zdCBvZiB0aGUgYnVncyBpbiBOZXRIYWNrIGFyZSBvbiB0aGUgZmxvb3Iu" }, + { "Much ado Nothing Happens.", + "TXVjaCBhZG8gTm90aGluZyBIYXBwZW5zLg==" }, + { "Multi-player NetHack is a myth.", + "TXVsdGktcGxheWVyIE5ldEhhY2sgaXMgYSBteXRoLg==" }, + { "NetHack is addictive. Too late, you're already hooked.", + "TmV0SGFjayBpcyBhZGRpY3RpdmUuIFRvbyBsYXRlLCB5b3UncmUgYWxyZWFkeSBob29rZWQu" }, + { "Never ask a shopkeeper for a price list.", + "TmV2ZXIgYXNrIGEgc2hvcGtlZXBlciBmb3IgYSBwcmljZSBsaXN0Lg==" }, + { "Never burn a tree, unless you like getting whacked with a +5 shovel.", + "TmV2ZXIgYnVybiBhIHRyZWUsIHVubGVzcyB5b3UgbGlrZSBnZXR0aW5nIHdoYWNrZWQgd2l0aCBhICs1IHNob3ZlbC4=" }, + { "Never eat with glowing hands!", + "TmV2ZXIgZWF0IHdpdGggZ2xvd2luZyBoYW5kcyE=" }, + { "Never mind the monsters hitting you: they just replace the charwomen.", + "TmV2ZXIgbWluZCB0aGUgbW9uc3RlcnMgaGl0dGluZyB5b3U6IHRoZXkganVzdCByZXBsYWNlIHRoZSBjaGFyd29tZW4u" }, + { "Never play leapfrog with a unicorn.", + "TmV2ZXIgcGxheSBsZWFwZnJvZyB3aXRoIGEgdW5pY29ybi4=" }, + { "Never step on a cursed engraving.", + "TmV2ZXIgc3RlcCBvbiBhIGN1cnNlZCBlbmdyYXZpbmcu" }, + { "Never swim with a camera: there's nothing to take pictures of.", + "TmV2ZXIgc3dpbSB3aXRoIGEgY2FtZXJhOiB0aGVyZSdzIG5vdGhpbmcgdG8gdGFrZSBwaWN0dXJlcyBvZi4=" }, + { "Never teach your pet rust monster to fetch.", + "TmV2ZXIgdGVhY2ggeW91ciBwZXQgcnVzdCBtb25zdGVyIHRvIGZldGNoLg==" }, + { "Never trust a random generator in magic fields.", + "TmV2ZXIgdHJ1c3QgYSByYW5kb20gZ2VuZXJhdG9yIGluIG1hZ2ljIGZpZWxkcy4=" }, + { "Never use a wand of death.", + "TmV2ZXIgdXNlIGEgd2FuZCBvZiBkZWF0aC4=" }, + { "No level contains two shops. The maze is no level. So...", + "Tm8gbGV2ZWwgY29udGFpbnMgdHdvIHNob3BzLiBUaGUgbWF6ZSBpcyBubyBsZXZlbC4gU28uLi4=" }, + { "No part of this fortune may be reproduced, stored in a retrieval system, ...", + "Tm8gcGFydCBvZiB0aGlzIGZvcnR1bmUgbWF5IGJlIHJlcHJvZHVjZWQsIHN0b3JlZCBpbiBhIHJldHJpZXZhbCBzeXN0ZW0sIC4uLg==" }, + { "Not all rumors are as misleading as this one.", + "Tm90IGFsbCBydW1vcnMgYXJlIGFzIG1pc2xlYWRpbmcgYXMgdGhpcyBvbmUu" }, + { "Nymphs and nurses like beautiful rings.", + "TnltcGhzIGFuZCBudXJzZXMgbGlrZSBiZWF1dGlmdWwgcmluZ3Mu" }, + { "Nymphs are blondes. Are you a gentleman?", + "TnltcGhzIGFyZSBibG9uZGVzLiBBcmUgeW91IGEgZ2VudGxlbWFuPw==" }, + { "Offering a unicorn a worthless piece of glass might prove to be fatal!", + "T2ZmZXJpbmcgYSB1bmljb3JuIGEgd29ydGhsZXNzIHBpZWNlIG9mIGdsYXNzIG1pZ2h0IHByb3ZlIHRvIGJlIGZhdGFsIQ==" }, + { "Old hackers never die: young ones do.", + "T2xkIGhhY2tlcnMgbmV2ZXIgZGllOiB5b3VuZyBvbmVzIGRvLg==" }, + { "One has to leave shops before closing time.", + "T25lIGhhcyB0byBsZWF2ZSBzaG9wcyBiZWZvcmUgY2xvc2luZyB0aW1lLg==" }, + { "One homunculus a day keeps the doctor away.", + "T25lIGhvbXVuY3VsdXMgYSBkYXkga2VlcHMgdGhlIGRvY3RvciBhd2F5Lg==" }, + { "One level further down somebody is getting killed, right now.", + "T25lIGxldmVsIGZ1cnRoZXIgZG93biBzb21lYm9keSBpcyBnZXR0aW5nIGtpbGxlZCwgcmlnaHQgbm93Lg==" }, + { "Only a wizard can use a magic whistle.", + "T25seSBhIHdpemFyZCBjYW4gdXNlIGEgbWFnaWMgd2hpc3RsZS4=" }, + { "Only adventurers of evil alignment think of killing their dog.", + "T25seSBhZHZlbnR1cmVycyBvZiBldmlsIGFsaWdubWVudCB0aGluayBvZiBraWxsaW5nIHRoZWlyIGRvZy4=" }, + { "Only chaotic evils kill sleeping monsters.", + "T25seSBjaGFvdGljIGV2aWxzIGtpbGwgc2xlZXBpbmcgbW9uc3RlcnMu" }, + { "Only real trappers escape traps.", + "T25seSByZWFsIHRyYXBwZXJzIGVzY2FwZSB0cmFwcy4=" }, + { "Only real wizards can write scrolls.", + "T25seSByZWFsIHdpemFyZHMgY2FuIHdyaXRlIHNjcm9sbHMu" }, + { "Operation OVERKILL has started now.", + "T3BlcmF0aW9uIE9WRVJLSUxMIGhhcyBzdGFydGVkIG5vdy4=" }, + { "PLEASE ignore previous rumor.", + "UExFQVNFIGlnbm9yZSBwcmV2aW91cyBydW1vci4=" }, + { "Polymorph into an ettin; meet your opponents face to face to face.", + "UG9seW1vcnBoIGludG8gYW4gZXR0aW47IG1lZXQgeW91ciBvcHBvbmVudHMgZmFjZSB0byBmYWNlIHRvIGZhY2Uu" }, + { "Praying will frighten demons.", + "UHJheWluZyB3aWxsIGZyaWdodGVuIGRlbW9ucy4=" }, + { "Row (3x) that boat gently down the stream, Charon (4x), death is but a dream.", + "Um93ICgzeCkgdGhhdCBib2F0IGdlbnRseSBkb3duIHRoZSBzdHJlYW0sIENoYXJvbiAoNHgpLCBkZWF0aCBpcyBidXQgYSBkcmVhbS4=" }, + { "Running is good for your legs.", + "UnVubmluZyBpcyBnb29kIGZvciB5b3VyIGxlZ3Mu" }, + { "Screw up your courage! You've screwed up everything else.", + "U2NyZXcgdXAgeW91ciBjb3VyYWdlISBZb3UndmUgc2NyZXdlZCB1cCBldmVyeXRoaW5nIGVsc2Uu" }, + { "Seepage? Leaky pipes? Rising damp? Summon the plumber!", + "U2VlcGFnZT8gTGVha3kgcGlwZXM/IFJpc2luZyBkYW1wPyBTdW1tb24gdGhlIHBsdW1iZXIh" }, + { "Segmentation fault (core dumped).", + "U2VnbWVudGF0aW9uIGZhdWx0IChjb3JlIGR1bXBlZCku" }, + { "Shopkeepers sometimes die from old age.", + "U2hvcGtlZXBlcnMgc29tZXRpbWVzIGRpZSBmcm9tIG9sZCBhZ2Uu" }, + { "Some mazes (especially small ones) have no solutions, says man 6 maze.", + "U29tZSBtYXplcyAoZXNwZWNpYWxseSBzbWFsbCBvbmVzKSBoYXZlIG5vIHNvbHV0aW9ucywgc2F5cyBtYW4gNiBtYXplLg==" }, + { "Some questions the Sphynx asks just *don't* have any answers.", + "U29tZSBxdWVzdGlvbnMgdGhlIFNwaHlueCBhc2tzIGp1c3QgKmRvbid0KiBoYXZlIGFueSBhbnN3ZXJzLg==" }, + { "Sometimes \"mu\" is the answer.", + "U29tZXRpbWVzICJtdSIgaXMgdGhlIGFuc3dlci4=" }, + { "Sorry, no fortune this time. Better luck next cookie!", + "U29ycnksIG5vIGZvcnR1bmUgdGhpcyB0aW1lLiBCZXR0ZXIgbHVjayBuZXh0IGNvb2tpZSE=" }, + { "Spare your scrolls of make-edible until it's really necessary!", + "U3BhcmUgeW91ciBzY3JvbGxzIG9mIG1ha2UtZWRpYmxlIHVudGlsIGl0J3MgcmVhbGx5IG5lY2Vzc2FyeSE=" }, + { "Suddenly, the dungeon will collapse...", + "U3VkZGVubHksIHRoZSBkdW5nZW9uIHdpbGwgY29sbGFwc2UuLi4=" }, + { "Taming a mail daemon may cause a system security violation.", + "VGFtaW5nIGEgbWFpbCBkYWVtb24gbWF5IGNhdXNlIGEgc3lzdGVtIHNlY3VyaXR5IHZpb2xhdGlvbi4=" }, + { "The crowd was so tough, the Stooges won't play the Dungeon anymore, nyuk nyuk.", + "VGhlIGNyb3dkIHdhcyBzbyB0b3VnaCwgdGhlIFN0b29nZXMgd29uJ3QgcGxheSB0aGUgRHVuZ2VvbiBhbnltb3JlLCBueXVrIG55dWsu" }, + { "The leprechauns hide their treasure in a small hidden room.", + "VGhlIGxlcHJlY2hhdW5zIGhpZGUgdGhlaXIgdHJlYXN1cmUgaW4gYSBzbWFsbCBoaWRkZW4gcm9vbS4=" }, + { "The longer the wand the better.", + "VGhlIGxvbmdlciB0aGUgd2FuZCB0aGUgYmV0dGVyLg==" }, + { "The magic word is \"XYZZY\".", + "VGhlIG1hZ2ljIHdvcmQgaXMgIlhZWlpZIi4=" }, + { "The meek shall inherit your bones files.", + "VGhlIG1lZWsgc2hhbGwgaW5oZXJpdCB5b3VyIGJvbmVzIGZpbGVzLg==" }, + { "The mines are dark and deep, and I have levels to go before I sleep.", + "VGhlIG1pbmVzIGFyZSBkYXJrIGFuZCBkZWVwLCBhbmQgSSBoYXZlIGxldmVscyB0byBnbyBiZWZvcmUgSSBzbGVlcC4=" }, + { "The use of dynamite is dangerous.", + "VGhlIHVzZSBvZiBkeW5hbWl0ZSBpcyBkYW5nZXJvdXMu" }, + { "There are no worms in the UNIX version.", + "VGhlcmUgYXJlIG5vIHdvcm1zIGluIHRoZSBVTklYIHZlcnNpb24u" }, + { "There is a trap on this level!", + "VGhlcmUgaXMgYSB0cmFwIG9uIHRoaXMgbGV2ZWwh" }, + { "They say that Demogorgon, Asmodeus, Orcus, Yeenoghu & Juiblex is no law firm.", + "VGhleSBzYXkgdGhhdCBEZW1vZ29yZ29uLCBBc21vZGV1cywgT3JjdXMsIFllZW5vZ2h1ICYgSnVpYmxleCBpcyBubyBsYXcgZmlybS4=" }, + { "They say that Geryon has an evil twin, beware!", + "VGhleSBzYXkgdGhhdCBHZXJ5b24gaGFzIGFuIGV2aWwgdHdpbiwgYmV3YXJlIQ==" }, + { "They say that Medusa would make a terrible pet.", + "VGhleSBzYXkgdGhhdCBNZWR1c2Egd291bGQgbWFrZSBhIHRlcnJpYmxlIHBldC4=" }, + { "They say that NetHack bugs are Seldon planned.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGJ1Z3MgYXJlIFNlbGRvbiBwbGFubmVkLg==" }, + { "They say that NetHack comes in 256 flavors.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGNvbWVzIGluIDI1NiBmbGF2b3JzLg==" }, + { "They say that NetHack is just a computer game.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGlzIGp1c3QgYSBjb21wdXRlciBnYW1lLg==" }, + { "They say that NetHack is more than just a computer game.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGlzIG1vcmUgdGhhbiBqdXN0IGEgY29tcHV0ZXIgZ2FtZS4=" }, + { "They say that NetHack is never what it used to be.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGlzIG5ldmVyIHdoYXQgaXQgdXNlZCB0byBiZS4=" }, + { "They say that a baby dragon is too small to hurt or help you.", + "VGhleSBzYXkgdGhhdCBhIGJhYnkgZHJhZ29uIGlzIHRvbyBzbWFsbCB0byBodXJ0IG9yIGhlbHAgeW91Lg==" }, + { "They say that a black pudding is simply a brown pudding gone bad.", + "VGhleSBzYXkgdGhhdCBhIGJsYWNrIHB1ZGRpbmcgaXMgc2ltcGx5IGEgYnJvd24gcHVkZGluZyBnb25lIGJhZC4=" }, + { "They say that a black sheep has 3 bags full of wool.", + "VGhleSBzYXkgdGhhdCBhIGJsYWNrIHNoZWVwIGhhcyAzIGJhZ3MgZnVsbCBvZiB3b29sLg==" }, + { "They say that a blank scroll is like a blank check.", + "VGhleSBzYXkgdGhhdCBhIGJsYW5rIHNjcm9sbCBpcyBsaWtlIGEgYmxhbmsgY2hlY2su" }, + { "They say that a cat named Morris has nine lives.", + "VGhleSBzYXkgdGhhdCBhIGNhdCBuYW1lZCBNb3JyaXMgaGFzIG5pbmUgbGl2ZXMu" }, + { "They say that a desperate shopper might pay any price in a shop.", + "VGhleSBzYXkgdGhhdCBhIGRlc3BlcmF0ZSBzaG9wcGVyIG1pZ2h0IHBheSBhbnkgcHJpY2UgaW4gYSBzaG9wLg==" }, + { "They say that a diamond dog is everybody's best friend.", + "VGhleSBzYXkgdGhhdCBhIGRpYW1vbmQgZG9nIGlzIGV2ZXJ5Ym9keSdzIGJlc3QgZnJpZW5kLg==" }, + { "They say that a dwarf lord can carry a pick-axe because his armor is light.", + "VGhleSBzYXkgdGhhdCBhIGR3YXJmIGxvcmQgY2FuIGNhcnJ5IGEgcGljay1heGUgYmVjYXVzZSBoaXMgYXJtb3IgaXMgbGlnaHQu" }, + { "They say that a floating eye can defeat Medusa.", + "VGhleSBzYXkgdGhhdCBhIGZsb2F0aW5nIGV5ZSBjYW4gZGVmZWF0IE1lZHVzYS4=" }, + { "They say that a fortune only has 1 line and you can't read between it.", + "VGhleSBzYXkgdGhhdCBhIGZvcnR1bmUgb25seSBoYXMgMSBsaW5lIGFuZCB5b3UgY2FuJ3QgcmVhZCBiZXR3ZWVuIGl0Lg==" }, + { "They say that a fortune only has 1 line, but you can read between it.", + "VGhleSBzYXkgdGhhdCBhIGZvcnR1bmUgb25seSBoYXMgMSBsaW5lLCBidXQgeW91IGNhbiByZWFkIGJldHdlZW4gaXQu" }, + { "They say that a fountain looks nothing like a regularly erupting geyser.", + "VGhleSBzYXkgdGhhdCBhIGZvdW50YWluIGxvb2tzIG5vdGhpbmcgbGlrZSBhIHJlZ3VsYXJseSBlcnVwdGluZyBnZXlzZXIu" }, + { "They say that a gold doubloon is worth more than its weight in gold.", + "VGhleSBzYXkgdGhhdCBhIGdvbGQgZG91Ymxvb24gaXMgd29ydGggbW9yZSB0aGFuIGl0cyB3ZWlnaHQgaW4gZ29sZC4=" }, + { "They say that a grid bug won't pay a shopkeeper for zapping you in a shop.", + "VGhleSBzYXkgdGhhdCBhIGdyaWQgYnVnIHdvbid0IHBheSBhIHNob3BrZWVwZXIgZm9yIHphcHBpbmcgeW91IGluIGEgc2hvcC4=" }, + { "They say that a gypsy could tell your fortune for a price.", + "VGhleSBzYXkgdGhhdCBhIGd5cHN5IGNvdWxkIHRlbGwgeW91ciBmb3J0dW5lIGZvciBhIHByaWNlLg==" }, + { "They say that a hacker named Alice once level teleported by using a mirror.", + "VGhleSBzYXkgdGhhdCBhIGhhY2tlciBuYW1lZCBBbGljZSBvbmNlIGxldmVsIHRlbGVwb3J0ZWQgYnkgdXNpbmcgYSBtaXJyb3Iu" }, + { "They say that a hacker named David once slew a giant with a sling and a rock.", + "VGhleSBzYXkgdGhhdCBhIGhhY2tlciBuYW1lZCBEYXZpZCBvbmNlIHNsZXcgYSBnaWFudCB3aXRoIGEgc2xpbmcgYW5kIGEgcm9jay4=" }, + { "They say that a hacker named Dorothy once rode a fog cloud to Oz.", + "VGhleSBzYXkgdGhhdCBhIGhhY2tlciBuYW1lZCBEb3JvdGh5IG9uY2Ugcm9kZSBhIGZvZyBjbG91ZCB0byBPei4=" }, + { "They say that a hacker named Mary once lost a white sheep in the mazes.", + "VGhleSBzYXkgdGhhdCBhIGhhY2tlciBuYW1lZCBNYXJ5IG9uY2UgbG9zdCBhIHdoaXRlIHNoZWVwIGluIHRoZSBtYXplcy4=" }, + { "They say that a helm of brilliance is not to be taken lightly.", + "VGhleSBzYXkgdGhhdCBhIGhlbG0gb2YgYnJpbGxpYW5jZSBpcyBub3QgdG8gYmUgdGFrZW4gbGlnaHRseS4=" }, + { "They say that a hot dog and a hell hound are the same thing.", + "VGhleSBzYXkgdGhhdCBhIGhvdCBkb2cgYW5kIGEgaGVsbCBob3VuZCBhcmUgdGhlIHNhbWUgdGhpbmcu" }, + { "They say that a lamp named Aladdin's Lamp contains a djinni with 3 wishes.", + "VGhleSBzYXkgdGhhdCBhIGxhbXAgbmFtZWQgQWxhZGRpbidzIExhbXAgY29udGFpbnMgYSBkamlubmkgd2l0aCAzIHdpc2hlcy4=" }, + { "They say that a large dog named Lassie will lead you to the amulet.", + "VGhleSBzYXkgdGhhdCBhIGxhcmdlIGRvZyBuYW1lZCBMYXNzaWUgd2lsbCBsZWFkIHlvdSB0byB0aGUgYW11bGV0Lg==" }, + { "They say that a long sword is not a light sword.", + "VGhleSBzYXkgdGhhdCBhIGxvbmcgc3dvcmQgaXMgbm90IGEgbGlnaHQgc3dvcmQu" }, + { "They say that a manes won't mince words with you.", + "VGhleSBzYXkgdGhhdCBhIG1hbmVzIHdvbid0IG1pbmNlIHdvcmRzIHdpdGggeW91Lg==" }, + { "They say that a mind is a terrible thing to waste.", + "VGhleSBzYXkgdGhhdCBhIG1pbmQgaXMgYSB0ZXJyaWJsZSB0aGluZyB0byB3YXN0ZS4=" }, + { "They say that a plain nymph will only wear a wire ring in one ear.", + "VGhleSBzYXkgdGhhdCBhIHBsYWluIG55bXBoIHdpbGwgb25seSB3ZWFyIGEgd2lyZSByaW5nIGluIG9uZSBlYXIu" }, + { "They say that a plumed hat could be a previously used crested helmet.", + "VGhleSBzYXkgdGhhdCBhIHBsdW1lZCBoYXQgY291bGQgYmUgYSBwcmV2aW91c2x5IHVzZWQgY3Jlc3RlZCBoZWxtZXQu" }, + { "They say that a potion of oil is difficult to grasp.", + "VGhleSBzYXkgdGhhdCBhIHBvdGlvbiBvZiBvaWwgaXMgZGlmZmljdWx0IHRvIGdyYXNwLg==" }, + { "They say that a potion of yogurt is a cancelled potion of sickness.", + "VGhleSBzYXkgdGhhdCBhIHBvdGlvbiBvZiB5b2d1cnQgaXMgYSBjYW5jZWxsZWQgcG90aW9uIG9mIHNpY2tuZXNzLg==" }, + { "They say that a purple worm is not a baby purple dragon.", + "VGhleSBzYXkgdGhhdCBhIHB1cnBsZSB3b3JtIGlzIG5vdCBhIGJhYnkgcHVycGxlIGRyYWdvbi4=" }, + { "They say that a quivering blob tastes different than a gelatinous cube.", + "VGhleSBzYXkgdGhhdCBhIHF1aXZlcmluZyBibG9iIHRhc3RlcyBkaWZmZXJlbnQgdGhhbiBhIGdlbGF0aW5vdXMgY3ViZS4=" }, + { "They say that a runed broadsword named Stormbringer attracts vortices.", + "VGhleSBzYXkgdGhhdCBhIHJ1bmVkIGJyb2Fkc3dvcmQgbmFtZWQgU3Rvcm1icmluZ2VyIGF0dHJhY3RzIHZvcnRpY2VzLg==" }, + { "They say that a scroll of summoning has other names.", + "VGhleSBzYXkgdGhhdCBhIHNjcm9sbCBvZiBzdW1tb25pbmcgaGFzIG90aGVyIG5hbWVzLg==" }, + { "They say that a shaman can bestow blessings but usually doesn't.", + "VGhleSBzYXkgdGhhdCBhIHNoYW1hbiBjYW4gYmVzdG93IGJsZXNzaW5ncyBidXQgdXN1YWxseSBkb2Vzbid0Lg==" }, + { "They say that a shaman will bless you for an eye of newt and wing of bat.", + "VGhleSBzYXkgdGhhdCBhIHNoYW1hbiB3aWxsIGJsZXNzIHlvdSBmb3IgYW4gZXllIG9mIG5ld3QgYW5kIHdpbmcgb2YgYmF0Lg==" }, + { "They say that a shimmering gold shield is not a polished silver shield.", + "VGhleSBzYXkgdGhhdCBhIHNoaW1tZXJpbmcgZ29sZCBzaGllbGQgaXMgbm90IGEgcG9saXNoZWQgc2lsdmVyIHNoaWVsZC4=" }, + { "They say that a spear will hit a neo-otyugh. (Do YOU know what that is?)", + "VGhleSBzYXkgdGhhdCBhIHNwZWFyIHdpbGwgaGl0IGEgbmVvLW90eXVnaC4gKERvIFlPVSBrbm93IHdoYXQgdGhhdCBpcz8p" }, + { "They say that a spotted dragon is the ultimate shape changer.", + "VGhleSBzYXkgdGhhdCBhIHNwb3R0ZWQgZHJhZ29uIGlzIHRoZSB1bHRpbWF0ZSBzaGFwZSBjaGFuZ2VyLg==" }, + { "They say that a stethoscope is no good if you can only hear your heartbeat.", + "VGhleSBzYXkgdGhhdCBhIHN0ZXRob3Njb3BlIGlzIG5vIGdvb2QgaWYgeW91IGNhbiBvbmx5IGhlYXIgeW91ciBoZWFydGJlYXQu" }, + { "They say that a succubus named Suzy will sometimes warn you of danger.", + "VGhleSBzYXkgdGhhdCBhIHN1Y2N1YnVzIG5hbWVkIFN1enkgd2lsbCBzb21ldGltZXMgd2FybiB5b3Ugb2YgZGFuZ2VyLg==" }, + { "They say that a wand of cancellation is not like a wand of polymorph.", + "VGhleSBzYXkgdGhhdCBhIHdhbmQgb2YgY2FuY2VsbGF0aW9uIGlzIG5vdCBsaWtlIGEgd2FuZCBvZiBwb2x5bW9ycGgu" }, + { "They say that a wood golem named Pinocchio would be easy to control.", + "VGhleSBzYXkgdGhhdCBhIHdvb2QgZ29sZW0gbmFtZWQgUGlub2NjaGlvIHdvdWxkIGJlIGVhc3kgdG8gY29udHJvbC4=" }, + { "They say that after killing a dragon it's time for a change of scenery.", + "VGhleSBzYXkgdGhhdCBhZnRlciBraWxsaW5nIGEgZHJhZ29uIGl0J3MgdGltZSBmb3IgYSBjaGFuZ2Ugb2Ygc2NlbmVyeS4=" }, + { "They say that an amulet of strangulation is worse than ring around the collar.", + "VGhleSBzYXkgdGhhdCBhbiBhbXVsZXQgb2Ygc3RyYW5ndWxhdGlvbiBpcyB3b3JzZSB0aGFuIHJpbmcgYXJvdW5kIHRoZSBjb2xsYXIu" }, + { "They say that an attic is the best place to hide your toys.", + "VGhleSBzYXkgdGhhdCBhbiBhdHRpYyBpcyB0aGUgYmVzdCBwbGFjZSB0byBoaWRlIHlvdXIgdG95cy4=" }, + { "They say that an axe named Cleaver once belonged to a hacker named Beaver.", + "VGhleSBzYXkgdGhhdCBhbiBheGUgbmFtZWQgQ2xlYXZlciBvbmNlIGJlbG9uZ2VkIHRvIGEgaGFja2VyIG5hbWVkIEJlYXZlci4=" }, + { "They say that an eye of newt and a wing of bat are double the trouble.", + "VGhleSBzYXkgdGhhdCBhbiBleWUgb2YgbmV3dCBhbmQgYSB3aW5nIG9mIGJhdCBhcmUgZG91YmxlIHRoZSB0cm91YmxlLg==" }, + { "They say that an incubus named Izzy sometimes makes women feel sensitive.", + "VGhleSBzYXkgdGhhdCBhbiBpbmN1YnVzIG5hbWVkIEl6enkgc29tZXRpbWVzIG1ha2VzIHdvbWVuIGZlZWwgc2Vuc2l0aXZlLg==" }, + { "They say that an opulent throne room is rarely a place to wish you'd be in.", + "VGhleSBzYXkgdGhhdCBhbiBvcHVsZW50IHRocm9uZSByb29tIGlzIHJhcmVseSBhIHBsYWNlIHRvIHdpc2ggeW91J2QgYmUgaW4u" }, + { "They say that an unlucky hacker once had a nose bleed at an altar and died.", + "VGhleSBzYXkgdGhhdCBhbiB1bmx1Y2t5IGhhY2tlciBvbmNlIGhhZCBhIG5vc2UgYmxlZWQgYXQgYW4gYWx0YXIgYW5kIGRpZWQu" }, + { "They say that and they say this but they never say never, never!", + "VGhleSBzYXkgdGhhdCBhbmQgdGhleSBzYXkgdGhpcyBidXQgdGhleSBuZXZlciBzYXkgbmV2ZXIsIG5ldmVyIQ==" }, + { "They say that any quantum mechanic knows that speed kills.", + "VGhleSBzYXkgdGhhdCBhbnkgcXVhbnR1bSBtZWNoYW5pYyBrbm93cyB0aGF0IHNwZWVkIGtpbGxzLg==" }, + { "They say that applying a unicorn horn means you've missed the point.", + "VGhleSBzYXkgdGhhdCBhcHBseWluZyBhIHVuaWNvcm4gaG9ybiBtZWFucyB5b3UndmUgbWlzc2VkIHRoZSBwb2ludC4=" }, + { "They say that blue stones are radioactive, beware.", + "VGhleSBzYXkgdGhhdCBibHVlIHN0b25lcyBhcmUgcmFkaW9hY3RpdmUsIGJld2FyZS4=" }, + { "They say that building a dungeon is a team effort.", + "VGhleSBzYXkgdGhhdCBidWlsZGluZyBhIGR1bmdlb24gaXMgYSB0ZWFtIGVmZm9ydC4=" }, + { "They say that chaotic characters never get a kick out of altars.", + "VGhleSBzYXkgdGhhdCBjaGFvdGljIGNoYXJhY3RlcnMgbmV2ZXIgZ2V0IGEga2ljayBvdXQgb2YgYWx0YXJzLg==" }, + { "They say that collapsing a dungeon often creates a panic.", + "VGhleSBzYXkgdGhhdCBjb2xsYXBzaW5nIGEgZHVuZ2VvbiBvZnRlbiBjcmVhdGVzIGEgcGFuaWMu" }, + { "They say that counting your eggs before they hatch shows that you care.", + "VGhleSBzYXkgdGhhdCBjb3VudGluZyB5b3VyIGVnZ3MgYmVmb3JlIHRoZXkgaGF0Y2ggc2hvd3MgdGhhdCB5b3UgY2FyZS4=" }, + { "They say that dipping a bag of tricks in a fountain won't make it an icebox.", + "VGhleSBzYXkgdGhhdCBkaXBwaW5nIGEgYmFnIG9mIHRyaWNrcyBpbiBhIGZvdW50YWluIHdvbid0IG1ha2UgaXQgYW4gaWNlYm94Lg==" }, + { "They say that dipping an eel and brown mold in hot water makes bouillabaisse.", + "VGhleSBzYXkgdGhhdCBkaXBwaW5nIGFuIGVlbCBhbmQgYnJvd24gbW9sZCBpbiBob3Qgd2F0ZXIgbWFrZXMgYm91aWxsYWJhaXNzZS4=" }, + { "They say that donating a doubloon is extremely pious charity.", + "VGhleSBzYXkgdGhhdCBkb25hdGluZyBhIGRvdWJsb29uIGlzIGV4dHJlbWVseSBwaW91cyBjaGFyaXR5Lg==" }, + { "They say that eating royal jelly attracts grizzly owlbears.", + "VGhleSBzYXkgdGhhdCBlYXRpbmcgcm95YWwgamVsbHkgYXR0cmFjdHMgZ3JpenpseSBvd2xiZWFycy4=" }, + { "They say that eggs, pancakes and juice are just a mundane breakfast.", + "VGhleSBzYXkgdGhhdCBlZ2dzLCBwYW5jYWtlcyBhbmQganVpY2UgYXJlIGp1c3QgYSBtdW5kYW5lIGJyZWFrZmFzdC4=" }, + { "They say that everyone knows why Medusa stands alone in the dark.", + "VGhleSBzYXkgdGhhdCBldmVyeW9uZSBrbm93cyB3aHkgTWVkdXNhIHN0YW5kcyBhbG9uZSBpbiB0aGUgZGFyay4=" }, + { "They say that everyone wanted rec.games.hack to undergo a name change.", + "VGhleSBzYXkgdGhhdCBldmVyeW9uZSB3YW50ZWQgcmVjLmdhbWVzLmhhY2sgdG8gdW5kZXJnbyBhIG5hbWUgY2hhbmdlLg==" }, + { "They say that finding a winning strategy is a deliberate move on your part.", + "VGhleSBzYXkgdGhhdCBmaW5kaW5nIGEgd2lubmluZyBzdHJhdGVneSBpcyBhIGRlbGliZXJhdGUgbW92ZSBvbiB5b3VyIHBhcnQu" }, + { "They say that finding worthless glass is worth something.", + "VGhleSBzYXkgdGhhdCBmaW5kaW5nIHdvcnRobGVzcyBnbGFzcyBpcyB3b3J0aCBzb21ldGhpbmcu" }, + { "They say that fortune cookies are food for thought.", + "VGhleSBzYXkgdGhhdCBmb3J0dW5lIGNvb2tpZXMgYXJlIGZvb2QgZm9yIHRob3VnaHQu" }, + { "They say that gold is only wasted on a pet dragon.", + "VGhleSBzYXkgdGhhdCBnb2xkIGlzIG9ubHkgd2FzdGVkIG9uIGEgcGV0IGRyYWdvbi4=" }, + { "They say that good things come to those that wait.", + "VGhleSBzYXkgdGhhdCBnb29kIHRoaW5ncyBjb21lIHRvIHRob3NlIHRoYXQgd2FpdC4=" }, + { "They say that greased objects will slip out of monsters' hands.", + "VGhleSBzYXkgdGhhdCBncmVhc2VkIG9iamVjdHMgd2lsbCBzbGlwIG91dCBvZiBtb25zdGVycycgaGFuZHMu" }, + { "They say that if you can't spell then you'll wish you had a spell book.", + "VGhleSBzYXkgdGhhdCBpZiB5b3UgY2FuJ3Qgc3BlbGwgdGhlbiB5b3UnbGwgd2lzaCB5b3UgaGFkIGEgc3BlbGwgYm9vay4=" }, + { "They say that if you live by the sword, you'll die by the sword.", + "VGhleSBzYXkgdGhhdCBpZiB5b3UgbGl2ZSBieSB0aGUgc3dvcmQsIHlvdSdsbCBkaWUgYnkgdGhlIHN3b3JkLg==" }, + { "They say that if you play like a monster you'll have a better game.", + "VGhleSBzYXkgdGhhdCBpZiB5b3UgcGxheSBsaWtlIGEgbW9uc3RlciB5b3UnbGwgaGF2ZSBhIGJldHRlciBnYW1lLg==" }, + { "They say that if you sleep with a demon you might awake with a headache.", + "VGhleSBzYXkgdGhhdCBpZiB5b3Ugc2xlZXAgd2l0aCBhIGRlbW9uIHlvdSBtaWdodCBhd2FrZSB3aXRoIGEgaGVhZGFjaGUu" }, + { "They say that if you step on a crack you could break your mother's back.", + "VGhleSBzYXkgdGhhdCBpZiB5b3Ugc3RlcCBvbiBhIGNyYWNrIHlvdSBjb3VsZCBicmVhayB5b3VyIG1vdGhlcidzIGJhY2su" }, + { "They say that if you're invisible you can still be heard!", + "VGhleSBzYXkgdGhhdCBpZiB5b3UncmUgaW52aXNpYmxlIHlvdSBjYW4gc3RpbGwgYmUgaGVhcmQh" }, + { "They say that if you're lucky you can feel the runes on a scroll.", + "VGhleSBzYXkgdGhhdCBpZiB5b3UncmUgbHVja3kgeW91IGNhbiBmZWVsIHRoZSBydW5lcyBvbiBhIHNjcm9sbC4=" }, + { "They say that in the big picture gold is only small change.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgYmlnIHBpY3R1cmUgZ29sZCBpcyBvbmx5IHNtYWxsIGNoYW5nZS4=" }, + { "They say that in the dungeon it's not what you know that really matters.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiBpdCdzIG5vdCB3aGF0IHlvdSBrbm93IHRoYXQgcmVhbGx5IG1hdHRlcnMu" }, + { "They say that in the dungeon moon rocks are really dilithium crystals.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiBtb29uIHJvY2tzIGFyZSByZWFsbHkgZGlsaXRoaXVtIGNyeXN0YWxzLg==" }, + { "They say that in the dungeon the boorish customer is never right.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiB0aGUgYm9vcmlzaCBjdXN0b21lciBpcyBuZXZlciByaWdodC4=" }, + { "They say that in the dungeon you don't need a watch to tell time.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiB5b3UgZG9uJ3QgbmVlZCBhIHdhdGNoIHRvIHRlbGwgdGltZS4=" }, + { "They say that in the dungeon you need something old, new, burrowed and blue.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiB5b3UgbmVlZCBzb21ldGhpbmcgb2xkLCBuZXcsIGJ1cnJvd2VkIGFuZCBibHVlLg==" }, + { "They say that in the dungeon you should always count your blessings.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiB5b3Ugc2hvdWxkIGFsd2F5cyBjb3VudCB5b3VyIGJsZXNzaW5ncy4=" }, + { "They say that iron golem plate mail isn't worth wishing for.", + "VGhleSBzYXkgdGhhdCBpcm9uIGdvbGVtIHBsYXRlIG1haWwgaXNuJ3Qgd29ydGggd2lzaGluZyBmb3Iu" }, + { "They say that it takes four quarterstaffs to make one staff.", + "VGhleSBzYXkgdGhhdCBpdCB0YWtlcyBmb3VyIHF1YXJ0ZXJzdGFmZnMgdG8gbWFrZSBvbmUgc3RhZmYu" }, + { "They say that it's not over till the fat ladies sing.", + "VGhleSBzYXkgdGhhdCBpdCdzIG5vdCBvdmVyIHRpbGwgdGhlIGZhdCBsYWRpZXMgc2luZy4=" }, + { "They say that it's not over till the fat lady shouts `Off with its head'.", + "VGhleSBzYXkgdGhhdCBpdCdzIG5vdCBvdmVyIHRpbGwgdGhlIGZhdCBsYWR5IHNob3V0cyBgT2ZmIHdpdGggaXRzIGhlYWQnLg==" }, + { "They say that kicking a heavy statue is really a dumb move.", + "VGhleSBzYXkgdGhhdCBraWNraW5nIGEgaGVhdnkgc3RhdHVlIGlzIHJlYWxseSBhIGR1bWIgbW92ZS4=" }, + { "They say that kicking a valuable gem doesn't seem to make sense.", + "VGhleSBzYXkgdGhhdCBraWNraW5nIGEgdmFsdWFibGUgZ2VtIGRvZXNuJ3Qgc2VlbSB0byBtYWtlIHNlbnNlLg==" }, + { "They say that leprechauns know Latin and you should too.", + "VGhleSBzYXkgdGhhdCBsZXByZWNoYXVucyBrbm93IExhdGluIGFuZCB5b3Ugc2hvdWxkIHRvby4=" }, + { "They say that minotaurs get lost outside of the mazes.", + "VGhleSBzYXkgdGhhdCBtaW5vdGF1cnMgZ2V0IGxvc3Qgb3V0c2lkZSBvZiB0aGUgbWF6ZXMu" }, + { "They say that most trolls are born again.", + "VGhleSBzYXkgdGhhdCBtb3N0IHRyb2xscyBhcmUgYm9ybiBhZ2Fpbi4=" }, + { "They say that naming your cat Garfield will make you more attractive.", + "VGhleSBzYXkgdGhhdCBuYW1pbmcgeW91ciBjYXQgR2FyZmllbGQgd2lsbCBtYWtlIHlvdSBtb3JlIGF0dHJhY3RpdmUu" }, + { "They say that no one knows everything about everything in the dungeon.", + "VGhleSBzYXkgdGhhdCBubyBvbmUga25vd3MgZXZlcnl0aGluZyBhYm91dCBldmVyeXRoaW5nIGluIHRoZSBkdW5nZW9uLg==" }, + { "They say that no one plays NetHack just for the fun of it.", + "VGhleSBzYXkgdGhhdCBubyBvbmUgcGxheXMgTmV0SGFjayBqdXN0IGZvciB0aGUgZnVuIG9mIGl0Lg==" }, + { "They say that no one really subscribes to rec.games.roguelike.nethack.", + "VGhleSBzYXkgdGhhdCBubyBvbmUgcmVhbGx5IHN1YnNjcmliZXMgdG8gcmVjLmdhbWVzLnJvZ3VlbGlrZS5uZXRoYWNrLg==" }, + { "They say that no one will admit to starting a rumor.", + "VGhleSBzYXkgdGhhdCBubyBvbmUgd2lsbCBhZG1pdCB0byBzdGFydGluZyBhIHJ1bW9yLg==" }, + { "They say that nurses sometimes carry scalpels and never use them.", + "VGhleSBzYXkgdGhhdCBudXJzZXMgc29tZXRpbWVzIGNhcnJ5IHNjYWxwZWxzIGFuZCBuZXZlciB1c2UgdGhlbS4=" }, + { "They say that once you've met one wizard you've met them all.", + "VGhleSBzYXkgdGhhdCBvbmNlIHlvdSd2ZSBtZXQgb25lIHdpemFyZCB5b3UndmUgbWV0IHRoZW0gYWxsLg==" }, + { "They say that one troll is worth 10,000 newts.", + "VGhleSBzYXkgdGhhdCBvbmUgdHJvbGwgaXMgd29ydGggMTAsMDAwIG5ld3RzLg==" }, + { "They say that only David can find the zoo!", + "VGhleSBzYXkgdGhhdCBvbmx5IERhdmlkIGNhbiBmaW5kIHRoZSB6b28h" }, + { "They say that only angels play their harps for their pets.", + "VGhleSBzYXkgdGhhdCBvbmx5IGFuZ2VscyBwbGF5IHRoZWlyIGhhcnBzIGZvciB0aGVpciBwZXRzLg==" }, + { "They say that only big spenders carry gold.", + "VGhleSBzYXkgdGhhdCBvbmx5IGJpZyBzcGVuZGVycyBjYXJyeSBnb2xkLg==" }, + { "They say that orc shamans are healthy, wealthy and wise.", + "VGhleSBzYXkgdGhhdCBvcmMgc2hhbWFucyBhcmUgaGVhbHRoeSwgd2VhbHRoeSBhbmQgd2lzZS4=" }, + { "They say that playing NetHack is like walking into a death trap.", + "VGhleSBzYXkgdGhhdCBwbGF5aW5nIE5ldEhhY2sgaXMgbGlrZSB3YWxraW5nIGludG8gYSBkZWF0aCB0cmFwLg==" }, + { "They say that problem breathing is best treated by a proper diet.", + "VGhleSBzYXkgdGhhdCBwcm9ibGVtIGJyZWF0aGluZyBpcyBiZXN0IHRyZWF0ZWQgYnkgYSBwcm9wZXIgZGlldC4=" }, + { "They say that quaffing many potions of levitation can give you a headache.", + "VGhleSBzYXkgdGhhdCBxdWFmZmluZyBtYW55IHBvdGlvbnMgb2YgbGV2aXRhdGlvbiBjYW4gZ2l2ZSB5b3UgYSBoZWFkYWNoZS4=" }, + { "They say that queen bees get that way by eating royal jelly.", + "VGhleSBzYXkgdGhhdCBxdWVlbiBiZWVzIGdldCB0aGF0IHdheSBieSBlYXRpbmcgcm95YWwgamVsbHku" }, + { "They say that reading a scare monster scroll is the same as saying Elbereth.", + "VGhleSBzYXkgdGhhdCByZWFkaW5nIGEgc2NhcmUgbW9uc3RlciBzY3JvbGwgaXMgdGhlIHNhbWUgYXMgc2F5aW5nIEVsYmVyZXRoLg==" }, + { "They say that real hackers always are controlled.", + "VGhleSBzYXkgdGhhdCByZWFsIGhhY2tlcnMgYWx3YXlzIGFyZSBjb250cm9sbGVkLg==" }, + { "They say that real hackers never sleep.", + "VGhleSBzYXkgdGhhdCByZWFsIGhhY2tlcnMgbmV2ZXIgc2xlZXAu" }, + { "They say that shopkeepers are insured by Croesus himself!", + "VGhleSBzYXkgdGhhdCBzaG9wa2VlcGVycyBhcmUgaW5zdXJlZCBieSBDcm9lc3VzIGhpbXNlbGYh" }, + { "They say that shopkeepers never carry more than 20 gold pieces, at night.", + "VGhleSBzYXkgdGhhdCBzaG9wa2VlcGVycyBuZXZlciBjYXJyeSBtb3JlIHRoYW4gMjAgZ29sZCBwaWVjZXMsIGF0IG5pZ2h0Lg==" }, + { "They say that shopkeepers never sell blessed potions of invisibility.", + "VGhleSBzYXkgdGhhdCBzaG9wa2VlcGVycyBuZXZlciBzZWxsIGJsZXNzZWQgcG90aW9ucyBvZiBpbnZpc2liaWxpdHku" }, + { "They say that soldiers wear kid gloves and silly helmets.", + "VGhleSBzYXkgdGhhdCBzb2xkaWVycyB3ZWFyIGtpZCBnbG92ZXMgYW5kIHNpbGx5IGhlbG1ldHMu" }, + { "They say that some Kops are on the take.", + "VGhleSBzYXkgdGhhdCBzb21lIEtvcHMgYXJlIG9uIHRoZSB0YWtlLg==" }, + { "They say that some guards' palms can be greased.", + "VGhleSBzYXkgdGhhdCBzb21lIGd1YXJkcycgcGFsbXMgY2FuIGJlIGdyZWFzZWQu" }, + { "They say that some monsters may kiss your boots to stop your drum playing.", + "VGhleSBzYXkgdGhhdCBzb21lIG1vbnN0ZXJzIG1heSBraXNzIHlvdXIgYm9vdHMgdG8gc3RvcCB5b3VyIGRydW0gcGxheWluZy4=" }, + { "They say that sometimes you can be the hit of the party when playing a horn.", + "VGhleSBzYXkgdGhhdCBzb21ldGltZXMgeW91IGNhbiBiZSB0aGUgaGl0IG9mIHRoZSBwYXJ0eSB3aGVuIHBsYXlpbmcgYSBob3JuLg==" }, + { "They say that the NetHack gods generally welcome your sacrifices.", + "VGhleSBzYXkgdGhhdCB0aGUgTmV0SGFjayBnb2RzIGdlbmVyYWxseSB3ZWxjb21lIHlvdXIgc2FjcmlmaWNlcy4=" }, + { "They say that the Three Rings are named Vilya, Nenya and Narya.", + "VGhleSBzYXkgdGhhdCB0aGUgVGhyZWUgUmluZ3MgYXJlIG5hbWVkIFZpbHlhLCBOZW55YSBhbmQgTmFyeWEu" }, + { "They say that the Wizard of Yendor has a death wish.", + "VGhleSBzYXkgdGhhdCB0aGUgV2l6YXJkIG9mIFllbmRvciBoYXMgYSBkZWF0aCB3aXNoLg==" }, + { "They say that the `hair of the dog' is sometimes an effective remedy.", + "VGhleSBzYXkgdGhhdCB0aGUgYGhhaXIgb2YgdGhlIGRvZycgaXMgc29tZXRpbWVzIGFuIGVmZmVjdGl2ZSByZW1lZHku" }, + { "They say that the best time to save your game is now before its too late.", + "VGhleSBzYXkgdGhhdCB0aGUgYmVzdCB0aW1lIHRvIHNhdmUgeW91ciBnYW1lIGlzIG5vdyBiZWZvcmUgaXRzIHRvbyBsYXRlLg==" }, + { "They say that the biggest obstacle in NetHack is your mind.", + "VGhleSBzYXkgdGhhdCB0aGUgYmlnZ2VzdCBvYnN0YWNsZSBpbiBOZXRIYWNrIGlzIHlvdXIgbWluZC4=" }, + { "They say that the gods are angry when they hit you with objects.", + "VGhleSBzYXkgdGhhdCB0aGUgZ29kcyBhcmUgYW5ncnkgd2hlbiB0aGV5IGhpdCB5b3Ugd2l0aCBvYmplY3RzLg==" }, + { "They say that the priesthood are specially favored by the gods.", + "VGhleSBzYXkgdGhhdCB0aGUgcHJpZXN0aG9vZCBhcmUgc3BlY2lhbGx5IGZhdm9yZWQgYnkgdGhlIGdvZHMu" }, + { "They say that the way to make a unicorn happy is to give it what it wants.", + "VGhleSBzYXkgdGhhdCB0aGUgd2F5IHRvIG1ha2UgYSB1bmljb3JuIGhhcHB5IGlzIHRvIGdpdmUgaXQgd2hhdCBpdCB3YW50cy4=" }, + { "They say that there are no black or white stones, only gray.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBhcmUgbm8gYmxhY2sgb3Igd2hpdGUgc3RvbmVzLCBvbmx5IGdyYXku" }, + { "They say that there are no skeletons hence there are no skeleton keys.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBhcmUgbm8gc2tlbGV0b25zIGhlbmNlIHRoZXJlIGFyZSBubyBza2VsZXRvbiBrZXlzLg==" }, + { "They say that there is a clever rogue in every hacker just dying to escape.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBpcyBhIGNsZXZlciByb2d1ZSBpbiBldmVyeSBoYWNrZXIganVzdCBkeWluZyB0byBlc2NhcGUu" }, + { "They say that there is no such thing as free advice.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBpcyBubyBzdWNoIHRoaW5nIGFzIGZyZWUgYWR2aWNlLg==" }, + { "They say that there is only one way to win at NetHack.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBpcyBvbmx5IG9uZSB3YXkgdG8gd2luIGF0IE5ldEhhY2su" }, + { "They say that there once was a fearsome chaotic samurai named Luk No.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBvbmNlIHdhcyBhIGZlYXJzb21lIGNoYW90aWMgc2FtdXJhaSBuYW1lZCBMdWsgTm8u" }, + { "They say that there was a time when cursed holy water wasn't water.", + "VGhleSBzYXkgdGhhdCB0aGVyZSB3YXMgYSB0aW1lIHdoZW4gY3Vyc2VkIGhvbHkgd2F0ZXIgd2Fzbid0IHdhdGVyLg==" }, + { "They say that there's no point in crying over a gray ooze.", + "VGhleSBzYXkgdGhhdCB0aGVyZSdzIG5vIHBvaW50IGluIGNyeWluZyBvdmVyIGEgZ3JheSBvb3plLg==" }, + { "They say that there's only hope left after you've opened Pandora's box.", + "VGhleSBzYXkgdGhhdCB0aGVyZSdzIG9ubHkgaG9wZSBsZWZ0IGFmdGVyIHlvdSd2ZSBvcGVuZWQgUGFuZG9yYSdzIGJveC4=" }, + { "They say that trapdoors should always be marked `Caution: Trap Door'.", + "VGhleSBzYXkgdGhhdCB0cmFwZG9vcnMgc2hvdWxkIGFsd2F5cyBiZSBtYXJrZWQgYENhdXRpb246IFRyYXAgRG9vcicu" }, + { "They say that using an amulet of change isn't a difficult operation.", + "VGhleSBzYXkgdGhhdCB1c2luZyBhbiBhbXVsZXQgb2YgY2hhbmdlIGlzbid0IGEgZGlmZmljdWx0IG9wZXJhdGlvbi4=" }, + { "They say that water walking boots are better if you are fast like Hermes.", + "VGhleSBzYXkgdGhhdCB3YXRlciB3YWxraW5nIGJvb3RzIGFyZSBiZXR0ZXIgaWYgeW91IGFyZSBmYXN0IGxpa2UgSGVybWVzLg==" }, + { "They say that when you wear a circular amulet you might resemble a troll.", + "VGhleSBzYXkgdGhhdCB3aGVuIHlvdSB3ZWFyIGEgY2lyY3VsYXIgYW11bGV0IHlvdSBtaWdodCByZXNlbWJsZSBhIHRyb2xsLg==" }, + { "They say that when you're hungry you can get a pizza in 30 moves or it's free.", + "VGhleSBzYXkgdGhhdCB3aGVuIHlvdSdyZSBodW5ncnkgeW91IGNhbiBnZXQgYSBwaXp6YSBpbiAzMCBtb3ZlcyBvciBpdCdzIGZyZWUu" }, + { "They say that when your god is angry you should try another one.", + "VGhleSBzYXkgdGhhdCB3aGVuIHlvdXIgZ29kIGlzIGFuZ3J5IHlvdSBzaG91bGQgdHJ5IGFub3RoZXIgb25lLg==" }, + { "They say that wielding a unicorn horn takes strength.", + "VGhleSBzYXkgdGhhdCB3aWVsZGluZyBhIHVuaWNvcm4gaG9ybiB0YWtlcyBzdHJlbmd0aC4=" }, + { "They say that with speed boots you never worry about hit and run accidents.", + "VGhleSBzYXkgdGhhdCB3aXRoIHNwZWVkIGJvb3RzIHlvdSBuZXZlciB3b3JyeSBhYm91dCBoaXQgYW5kIHJ1biBhY2NpZGVudHMu" }, + { "They say that you can defeat a killer bee with a unicorn horn.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIGRlZmVhdCBhIGtpbGxlciBiZWUgd2l0aCBhIHVuaWNvcm4gaG9ybi4=" }, + { "They say that you can only cross the River Styx in Charon's boat.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIG9ubHkgY3Jvc3MgdGhlIFJpdmVyIFN0eXggaW4gQ2hhcm9uJ3MgYm9hdC4=" }, + { "They say that you can only kill a lich once and then you'd better be careful.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIG9ubHkga2lsbCBhIGxpY2ggb25jZSBhbmQgdGhlbiB5b3UnZCBiZXR0ZXIgYmUgY2FyZWZ1bC4=" }, + { "They say that you can only wish for things you've already had.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIG9ubHkgd2lzaCBmb3IgdGhpbmdzIHlvdSd2ZSBhbHJlYWR5IGhhZC4=" }, + { "They say that you can train a cat by talking gently to it.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIHRyYWluIGEgY2F0IGJ5IHRhbGtpbmcgZ2VudGx5IHRvIGl0Lg==" }, + { "They say that you can train a dog by talking firmly to it.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIHRyYWluIGEgZG9nIGJ5IHRhbGtpbmcgZmlybWx5IHRvIGl0Lg==" }, + { "They say that you can trust your gold with the king.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIHRydXN0IHlvdXIgZ29sZCB3aXRoIHRoZSBraW5nLg==" }, + { "They say that you can't wipe your greasy bare hands on a blank scroll.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuJ3Qgd2lwZSB5b3VyIGdyZWFzeSBiYXJlIGhhbmRzIG9uIGEgYmxhbmsgc2Nyb2xsLg==" }, + { "They say that you cannot trust scrolls of rumor.", + "VGhleSBzYXkgdGhhdCB5b3UgY2Fubm90IHRydXN0IHNjcm9sbHMgb2YgcnVtb3Iu" }, + { "They say that you could fall head over heels for an energy vortex.", + "VGhleSBzYXkgdGhhdCB5b3UgY291bGQgZmFsbCBoZWFkIG92ZXIgaGVlbHMgZm9yIGFuIGVuZXJneSB2b3J0ZXgu" }, + { "They say that you need a key in order to open locked doors.", + "VGhleSBzYXkgdGhhdCB5b3UgbmVlZCBhIGtleSBpbiBvcmRlciB0byBvcGVuIGxvY2tlZCBkb29ycy4=" }, + { "They say that you need a mirror to notice a mimic in an antique shop.", + "VGhleSBzYXkgdGhhdCB5b3UgbmVlZCBhIG1pcnJvciB0byBub3RpY2UgYSBtaW1pYyBpbiBhbiBhbnRpcXVlIHNob3Au" }, + { "They say that you really can use a pick-axe unless you really can't.", + "VGhleSBzYXkgdGhhdCB5b3UgcmVhbGx5IGNhbiB1c2UgYSBwaWNrLWF4ZSB1bmxlc3MgeW91IHJlYWxseSBjYW4ndC4=" }, + { "They say that you should always store your tools in the cellar.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIGFsd2F5cyBzdG9yZSB5b3VyIHRvb2xzIGluIHRoZSBjZWxsYXIu" }, + { "They say that you should be careful while climbing the ladder to success.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIGJlIGNhcmVmdWwgd2hpbGUgY2xpbWJpbmcgdGhlIGxhZGRlciB0byBzdWNjZXNzLg==" }, + { "They say that you should call your armor `rustproof'.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIGNhbGwgeW91ciBhcm1vciBgcnVzdHByb29mJy4=" }, + { "They say that you should name your dog Spuds to have a cool pet.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5hbWUgeW91ciBkb2cgU3B1ZHMgdG8gaGF2ZSBhIGNvb2wgcGV0Lg==" }, + { "They say that you should name your weapon after your first monster kill.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5hbWUgeW91ciB3ZWFwb24gYWZ0ZXIgeW91ciBmaXJzdCBtb25zdGVyIGtpbGwu" }, + { "They say that you should never introduce a rope golem to a succubus.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5ldmVyIGludHJvZHVjZSBhIHJvcGUgZ29sZW0gdG8gYSBzdWNjdWJ1cy4=" }, + { "They say that you should never sleep near invisible ring wraiths.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5ldmVyIHNsZWVwIG5lYXIgaW52aXNpYmxlIHJpbmcgd3JhaXRocy4=" }, + { "They say that you should never try to leave the dungeon with a bag of gems.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5ldmVyIHRyeSB0byBsZWF2ZSB0aGUgZHVuZ2VvbiB3aXRoIGEgYmFnIG9mIGdlbXMu" }, + { "They say that you should remove your armor before sitting on a throne.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIHJlbW92ZSB5b3VyIGFybW9yIGJlZm9yZSBzaXR0aW5nIG9uIGEgdGhyb25lLg==" }, + { "This fortune cookie is copy protected.", + "VGhpcyBmb3J0dW5lIGNvb2tpZSBpcyBjb3B5IHByb3RlY3RlZC4=" }, + { "This fortune cookie is the property of Fortune Cookies, Inc.", + "VGhpcyBmb3J0dW5lIGNvb2tpZSBpcyB0aGUgcHJvcGVydHkgb2YgRm9ydHVuZSBDb29raWVzLCBJbmMu" }, + { "Tired? Try a scroll of charging on yourself.", + "VGlyZWQ/IFRyeSBhIHNjcm9sbCBvZiBjaGFyZ2luZyBvbiB5b3Vyc2VsZi4=" }, + { "To achieve the next higher rating, you need 3 more points.", + "VG8gYWNoaWV2ZSB0aGUgbmV4dCBoaWdoZXIgcmF0aW5nLCB5b3UgbmVlZCAzIG1vcmUgcG9pbnRzLg==" }, + { "To reach heaven, escape the dungeon while wearing a ring of levitation.", + "VG8gcmVhY2ggaGVhdmVuLCBlc2NhcGUgdGhlIGR1bmdlb24gd2hpbGUgd2VhcmluZyBhIHJpbmcgb2YgbGV2aXRhdGlvbi4=" }, + { "Tourists wear shirts loud enough to wake the dead.", + "VG91cmlzdHMgd2VhciBzaGlydHMgbG91ZCBlbm91Z2ggdG8gd2FrZSB0aGUgZGVhZC4=" }, + { "Try calling your katana Moulinette.", + "VHJ5IGNhbGxpbmcgeW91ciBrYXRhbmEgTW91bGluZXR0ZS4=" }, + { "Ulch! That meat was painted!", + "VWxjaCEgVGhhdCBtZWF0IHdhcyBwYWludGVkIQ==" }, + { "Unfortunately, this message was left intentionally blank.", + "VW5mb3J0dW5hdGVseSwgdGhpcyBtZXNzYWdlIHdhcyBsZWZ0IGludGVudGlvbmFsbHkgYmxhbmsu" }, + { "Using a morning star in the evening has no effect.", + "VXNpbmcgYSBtb3JuaW5nIHN0YXIgaW4gdGhlIGV2ZW5pbmcgaGFzIG5vIGVmZmVjdC4=" }, + { "Want a hint? Zap a wand of make invisible on your weapon!", + "V2FudCBhIGhpbnQ/IFphcCBhIHdhbmQgb2YgbWFrZSBpbnZpc2libGUgb24geW91ciB3ZWFwb24h" }, + { "Want to ascend in a hurry? Apply at Gizmonic Institute.", + "V2FudCB0byBhc2NlbmQgaW4gYSBodXJyeT8gQXBwbHkgYXQgR2l6bW9uaWMgSW5zdGl0dXRlLg==" }, + { "Wanted: shopkeepers. Send a scroll of mail to Mage of Yendor/Level 35/Dungeon.", + "V2FudGVkOiBzaG9wa2VlcGVycy4gU2VuZCBhIHNjcm9sbCBvZiBtYWlsIHRvIE1hZ2Ugb2YgWWVuZG9yL0xldmVsIDM1L0R1bmdlb24u" }, + { "Warning: fortune reading can be hazardous to your health.", + "V2FybmluZzogZm9ydHVuZSByZWFkaW5nIGNhbiBiZSBoYXphcmRvdXMgdG8geW91ciBoZWFsdGgu" }, + { "We have new ways of detecting treachery...", + "V2UgaGF2ZSBuZXcgd2F5cyBvZiBkZXRlY3RpbmcgdHJlYWNoZXJ5Li4u" }, + { "Wet towels make great weapons!", + "V2V0IHRvd2VscyBtYWtlIGdyZWF0IHdlYXBvbnMh" }, + { "What a pity, you cannot read it!", + "V2hhdCBhIHBpdHksIHlvdSBjYW5ub3QgcmVhZCBpdCE=" }, + { "When a piercer drops in on you, you will be tempted to hit the ceiling!", + "V2hlbiBhIHBpZXJjZXIgZHJvcHMgaW4gb24geW91LCB5b3Ugd2lsbCBiZSB0ZW1wdGVkIHRvIGhpdCB0aGUgY2VpbGluZyE=" }, + { "When in a maze follow the right wall and you will never get lost.", + "V2hlbiBpbiBhIG1hemUgZm9sbG93IHRoZSByaWdodCB3YWxsIGFuZCB5b3Ugd2lsbCBuZXZlciBnZXQgbG9zdC4=" }, + { "When you have a key, you don't have to wait for the guard.", + "V2hlbiB5b3UgaGF2ZSBhIGtleSwgeW91IGRvbid0IGhhdmUgdG8gd2FpdCBmb3IgdGhlIGd1YXJkLg==" }, + { "Why are you wasting time reading fortunes?", + "V2h5IGFyZSB5b3Ugd2FzdGluZyB0aW1lIHJlYWRpbmcgZm9ydHVuZXM/" }, + { "Wish for a master key and open the Magic Memory Vault!", + "V2lzaCBmb3IgYSBtYXN0ZXIga2V5IGFuZCBvcGVuIHRoZSBNYWdpYyBNZW1vcnkgVmF1bHQh" }, + { "Wizard expects every monster to do its duty.", + "V2l6YXJkIGV4cGVjdHMgZXZlcnkgbW9uc3RlciB0byBkbyBpdHMgZHV0eS4=" }, + { "Wow! You could've had a potion of fruit juice!", + "V293ISBZb3UgY291bGQndmUgaGFkIGEgcG90aW9uIG9mIGZydWl0IGp1aWNlIQ==" }, + { "Yet Another Silly Message (YASM).", + "WWV0IEFub3RoZXIgU2lsbHkgTWVzc2FnZSAoWUFTTSku" }, + { "You are destined to be misled by a fortune.", + "WW91IGFyZSBkZXN0aW5lZCB0byBiZSBtaXNsZWQgYnkgYSBmb3J0dW5lLg==" }, + { "You can get a genuine Amulet of Yendor by doing the following: --More--", + "WW91IGNhbiBnZXQgYSBnZW51aW5lIEFtdWxldCBvZiBZZW5kb3IgYnkgZG9pbmcgdGhlIGZvbGxvd2luZzogLS1Nb3JlLS0=" }, + { "You can protect yourself from black dragons by doing the following: --More--", + "WW91IGNhbiBwcm90ZWN0IHlvdXJzZWxmIGZyb20gYmxhY2sgZHJhZ29ucyBieSBkb2luZyB0aGUgZm9sbG93aW5nOiAtLU1vcmUtLQ==" }, + { "You can't get by the snake.", + "WW91IGNhbid0IGdldCBieSB0aGUgc25ha2Uu" }, + { "You feel like someone is pulling your leg.", + "WW91IGZlZWwgbGlrZSBzb21lb25lIGlzIHB1bGxpbmcgeW91ciBsZWcu" }, + { "You have to outwit the Sphynx or pay her.", + "WW91IGhhdmUgdG8gb3V0d2l0IHRoZSBTcGh5bnggb3IgcGF5IGhlci4=" }, + { "You hear the fortune cookie's hissing!", + "WW91IGhlYXIgdGhlIGZvcnR1bmUgY29va2llJ3MgaGlzc2luZyE=" }, + { "You may get rich selling letters, but beware of being blackmailed!", + "WW91IG1heSBnZXQgcmljaCBzZWxsaW5nIGxldHRlcnMsIGJ1dCBiZXdhcmUgb2YgYmVpbmcgYmxhY2ttYWlsZWQh" }, + { "You offend Shai-Hulud by sheathing your crysknife without having drawn blood.", + "WW91IG9mZmVuZCBTaGFpLUh1bHVkIGJ5IHNoZWF0aGluZyB5b3VyIGNyeXNrbmlmZSB3aXRob3V0IGhhdmluZyBkcmF3biBibG9vZC4=" }, + { "You swallowed the fortune!", + "WW91IHN3YWxsb3dlZCB0aGUgZm9ydHVuZSE=" }, + { "You want to regain strength? Two levels ahead is a guesthouse!", + "WW91IHdhbnQgdG8gcmVnYWluIHN0cmVuZ3RoPyBUd28gbGV2ZWxzIGFoZWFkIGlzIGEgZ3Vlc3Rob3VzZSE=" }, + { "You will encounter a tall, dark, and gruesome creature...", + "WW91IHdpbGwgZW5jb3VudGVyIGEgdGFsbCwgZGFyaywgYW5kIGdydWVzb21lIGNyZWF0dXJlLi4u" }, + + { "The End", "VGhlIEVuZA==" } + }; + +/* PL_Base64Encode, random strings */ +PRBool test_004(void) +{ + int i; + char result[ 4096 ]; + + printf("Test 004 (PL_Base64Encode, random strings) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 plen = PL_strlen(array[i].plaintext); + PRUint32 clen = ((plen + 2)/3)*4; + + char *rv = PL_Base64Encode(array[i].plaintext, plen, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strncmp(result, array[i].cyphertext, clen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].plaintext, array[i].cyphertext, clen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, single characters, malloc */ +PRBool test_005(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 005 (PL_Base64Encode, single characters, malloc) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Encode((char *)plain, 1, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d): no return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)cypher, rv) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, cypher, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, double characters, malloc */ +PRBool test_006(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 006 (PL_Base64Encode, double characters, malloc) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Encode((char *)plain, 2, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d): no return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)cypher, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, c, d, cypher, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, triple characters, malloc */ +PRBool test_007(void) +{ + PRUint32 a, b, c, d, e, f; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 007 (PL_Base64Encode, triple characters, malloc) ..."); fflush(stdout); + + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + for( e = 0; e < 4; e++ ) + { + cypher[2] = base[d*4 + e]; + for( f = 0; f < 64; f++ ) + { + plain[2] = e * 64 + f; + cypher[3] = base[f]; + + rv = PL_Base64Encode((char *)plain, 3, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): no return value\n", a, b, c, d, e, f); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)cypher, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): expected \"%s,\" got \"%.4s.\"\n", + a, b, c, d, e, f, cypher, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings, malloc */ +PRBool test_008(void) +{ + int i; + + printf("Test 008 (PL_Base64Encode, random strings, malloc) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 plen = PL_strlen(array[i].plaintext); + PRUint32 clen = ((plen + 2)/3)*4; + + char *rv = PL_Base64Encode(array[i].plaintext, plen, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].cyphertext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].plaintext, array[i].cyphertext, rv); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, single characters */ +PRBool test_009(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 009 (PL_Base64Decode, single characters, equals) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Decode((char *)cypher, 4, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d): return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 1) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%.1s.\"\n", + a, b, plain, result); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, single characters */ +PRBool test_010(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 010 (PL_Base64Decode, single characters, no equals) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)0; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Decode((char *)cypher, 2, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d): return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 1) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%.1s.\"\n", + a, b, plain, result); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, double characters */ +PRBool test_011(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 011 (PL_Base64Decode, double characters, equals) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Decode((char *)cypher, 4, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d): return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 2) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%.2s.\"\n", + a, b, c, d, plain, result); + return PR_FALSE; + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, double characters */ +PRBool test_012(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 012 (PL_Base64Decode, double characters, no equals) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)0; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Decode((char *)cypher, 3, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d): return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 2) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%.2s.\"\n", + a, b, c, d, cypher, result); + return PR_FALSE; + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, triple characters */ +PRBool test_013(void) +{ + PRUint32 a, b, c, d, e, f; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 013 (PL_Base64Decode, triple characters) ..."); fflush(stdout); + + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + for( e = 0; e < 4; e++ ) + { + cypher[2] = base[d*4 + e]; + for( f = 0; f < 64; f++ ) + { + plain[2] = e * 64 + f; + cypher[3] = base[f]; + + rv = PL_Base64Decode((char *)cypher, 4, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): return value\n", a, b, c, d, e, f); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 3) ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): expected \"%s,\" got \"%.3s.\"\n", + a, b, c, d, e, f, plain, result); + return PR_FALSE; + } + } + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings */ +PRBool test_014(void) +{ + int i; + char result[ 4096 ]; + + printf("Test 014 (PL_Base64Decode, random strings, equals) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen = PL_strlen(array[i].cyphertext); + PRUint32 plen = (clen * 3) / 4; + + char *rv = PL_Base64Decode(array[i].cyphertext, clen, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 == (clen & 3) ) + { + if( '=' == array[i].cyphertext[clen-1] ) + { + if( '=' == array[i].cyphertext[clen-2] ) + { + plen -= 2; + } + else + { + plen -= 1; + } + } + } + + if( 0 != PL_strncmp(result, array[i].plaintext, plen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].cyphertext, array[i].plaintext, plen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings */ +PRBool test_015(void) +{ + int i; + char buffer[ 4096 ]; + char result[ 4096 ]; + char *rv; + + printf("Test 015 (PL_Base64Decode, random strings, no equals) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen, plen; + + PL_strcpy(buffer, array[i].cyphertext); + clen = PL_strlen(buffer); + + if( 0 == (clen & 3) ) + { + if( '=' == buffer[clen-1] ) + { + if( '=' == buffer[clen-2] ) + { + buffer[clen-2] = buffer[clen-1] = (char)0; + clen -= 2; + } + else + { + buffer[clen-1] = (char)0; + clen -= 1; + } + } + } + + plen = (clen * 3) / 4; + + rv = PL_Base64Decode(buffer, clen, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strncmp(result, array[i].plaintext, plen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].cyphertext, array[i].plaintext, plen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, single characters, malloc */ +PRBool test_016(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 016 (PL_Base64Decode, single characters, equals, malloc) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Decode((char *)cypher, 4, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d): no return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, plain, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, single characters, malloc */ +PRBool test_017(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 017 (PL_Base64Decode, single characters, no equals, malloc) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)0; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Decode((char *)cypher, 2, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d): no return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, plain, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, double characters, malloc */ +PRBool test_018(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 018 (PL_Base64Decode, double characters, equals, malloc) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Decode((char *)cypher, 4, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d): no return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, c, d, plain, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, double characters, malloc */ +PRBool test_019(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 019 (PL_Base64Decode, double characters, no equals, malloc) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)0; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Decode((char *)cypher, 3, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d): no return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, c, d, cypher, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, triple characters, malloc */ +PRBool test_020(void) +{ + PRUint32 a, b, c, d, e, f; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 020 (PL_Base64Decode, triple characters, malloc) ..."); fflush(stdout); + + cypher[4] = (unsigned char)0; + plain[3] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + for( e = 0; e < 4; e++ ) + { + cypher[2] = base[d*4 + e]; + for( f = 0; f < 64; f++ ) + { + plain[2] = e * 64 + f; + cypher[3] = base[f]; + + rv = PL_Base64Decode((char *)cypher, 4, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): no return value\n", a, b, c, d, e, f); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): expected \"%s,\" got \"%.3s.\"\n", + a, b, c, d, e, f, plain, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings, malloc */ +PRBool test_021(void) +{ + int i; + + printf("Test 021 (PL_Base64Decode, random strings, equals, malloc) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen = PL_strlen(array[i].cyphertext); + + char *rv = PL_Base64Decode(array[i].cyphertext, clen, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].plaintext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].cyphertext, array[i].plaintext, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings, malloc */ +PRBool test_022(void) +{ + int i; + char buffer[ 4096 ]; + char *rv; + + printf("Test 022 (PL_Base64Decode, random strings, no equals, malloc) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen; + + PL_strcpy(buffer, array[i].cyphertext); + clen = PL_strlen(buffer); + + if( 0 == (clen & 3) ) + { + if( '=' == buffer[clen-1] ) + { + if( '=' == buffer[clen-2] ) + { + buffer[clen-2] = buffer[clen-1] = (char)0; + clen -= 2; + } + else + { + buffer[clen-1] = (char)0; + clen -= 1; + } + } + } + + rv = PL_Base64Decode(buffer, clen, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].plaintext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].cyphertext, array[i].plaintext, rv); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings */ +PRBool test_023(void) +{ + int i; + char result[ 4096 ]; + + printf("Test 023 (PL_Base64Encode, random strings, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 plen = PL_strlen(array[i].plaintext); + PRUint32 clen = ((plen + 2)/3)*4; + + char *rv = PL_Base64Encode(array[i].plaintext, 0, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strncmp(result, array[i].cyphertext, clen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].plaintext, array[i].cyphertext, clen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings, malloc */ +PRBool test_024(void) +{ + int i; + + printf("Test 024 (PL_Base64Encode, random strings, malloc, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 plen = PL_strlen(array[i].plaintext); + PRUint32 clen = ((plen + 2)/3)*4; + + char *rv = PL_Base64Encode(array[i].plaintext, 0, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].cyphertext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].plaintext, array[i].cyphertext, rv); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings */ +PRBool test_025(void) +{ + int i; + char result[ 4096 ]; + + printf("Test 025 (PL_Base64Decode, random strings, equals, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen = PL_strlen(array[i].cyphertext); + PRUint32 plen = (clen * 3) / 4; + + char *rv = PL_Base64Decode(array[i].cyphertext, 0, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 == (clen & 3) ) + { + if( '=' == array[i].cyphertext[clen-1] ) + { + if( '=' == array[i].cyphertext[clen-2] ) + { + plen -= 2; + } + else + { + plen -= 1; + } + } + } + + if( 0 != PL_strncmp(result, array[i].plaintext, plen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].cyphertext, array[i].plaintext, plen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings */ +PRBool test_026(void) +{ + int i; + char buffer[ 4096 ]; + char result[ 4096 ]; + char *rv; + + printf("Test 026 (PL_Base64Decode, random strings, no equals, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen, plen; + + PL_strcpy(buffer, array[i].cyphertext); + clen = PL_strlen(buffer); + + if( 0 == (clen & 3) ) + { + if( '=' == buffer[clen-1] ) + { + if( '=' == buffer[clen-2] ) + { + buffer[clen-2] = buffer[clen-1] = (char)0; + clen -= 2; + } + else + { + buffer[clen-1] = (char)0; + clen -= 1; + } + } + } + + plen = (clen * 3) / 4; + + rv = PL_Base64Decode(buffer, 0, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strncmp(result, array[i].plaintext, plen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].cyphertext, array[i].plaintext, plen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings, malloc */ +PRBool test_027(void) +{ + int i; + + printf("Test 027 (PL_Base64Decode, random strings, equals, malloc, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen = PL_strlen(array[i].cyphertext); + + char *rv = PL_Base64Decode(array[i].cyphertext, 0, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].plaintext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].cyphertext, array[i].plaintext, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings, malloc */ +PRBool test_028(void) +{ + int i; + char buffer[ 4096 ]; + char *rv; + + printf("Test 028 (PL_Base64Decode, random strings, no equals, malloc, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen; + + PL_strcpy(buffer, array[i].cyphertext); + clen = PL_strlen(buffer); + + if( 0 == (clen & 3) ) + { + if( '=' == buffer[clen-1] ) + { + if( '=' == buffer[clen-2] ) + { + buffer[clen-2] = buffer[clen-1] = (char)0; + clen -= 2; + } + else + { + buffer[clen-1] = (char)0; + clen -= 1; + } + } + } + + rv = PL_Base64Decode(buffer, 0, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].plaintext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].cyphertext, array[i].plaintext, rv); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +int +main +( + int argc, + char *argv[] +) +{ + printf("Testing the Portable Library base64 functions:\n"); + printf("(warning: the \"triple characters\" tests are slow)\n"); + + if( 1 + && test_001() + && test_002() + && test_003() + && test_004() + && test_005() + && test_006() + && test_007() + && test_008() + && test_009() + && test_010() + && test_011() + && test_012() + && test_013() + && test_014() + && test_015() + && test_016() + && test_017() + && test_018() + && test_019() + && test_020() + && test_021() + && test_022() + && test_023() + && test_024() + && test_025() + && test_026() + && test_027() + && test_028() + ) + { + printf("Suite passed.\n"); + return 0; + } + else + { + printf("Suite failed.\n"); + return 1; + } + + /*NOTREACHED*/ +} diff --git a/nsprpub/lib/tests/getopt.c b/nsprpub/lib/tests/getopt.c new file mode 100644 index 00000000000..52b971989a3 --- /dev/null +++ b/nsprpub/lib/tests/getopt.c @@ -0,0 +1,40 @@ +#include +#include +#include + +#include "nspr.h" +#include "plgetopt.h" + + + +static const PLLongOpt optArray[] = { + { "longa", 'a' , PR_TRUE }, + { "longb", 'b' , PR_TRUE }, + { "longc", 'c' , PR_FALSE }, + { "longd", 'd' | 0x100, PR_TRUE }, + { "longe", 'e' | 0x100, PR_FALSE }, + { NULL, } +}; + +int +main(int argc, char **argv) +{ + PLOptState *opt; + PLOptStatus ostat; + + opt = PL_CreateLongOptState(argc, argv, "a:b:c", optArray); + + while (PL_OPT_OK == (ostat = PL_GetNextOpt(opt))) { + if (opt->option == 0 && opt->longOptIndex < 0) + printf("Positional parameter: \"%s\"\n", opt->value); + else + printf("%s option: %x (\'%c\', index %d), argument: \"%s\"\n", + (ostat == PL_OPT_BAD) ? "BAD" : "GOOD", + opt->longOption, opt->option ? opt->option : ' ', + opt->longOptIndex, opt->value); + + } + printf("last result was %s\n", (ostat == PL_OPT_BAD) ? "BAD" : "EOL"); + PL_DestroyOptState(opt); + return 0; +} diff --git a/nsprpub/lib/tests/string.c b/nsprpub/lib/tests/string.c new file mode 100644 index 00000000000..482e17b5dc5 --- /dev/null +++ b/nsprpub/lib/tests/string.c @@ -0,0 +1,3116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plstr.h" +#include "nspr.h" + +#include + +/* PL_strlen */ +PRBool test_001(void) +{ + static struct + { + const char *str; + PRUint32 len; + } array[] = + { + { (const char *)0, 0 }, + { "", 0 }, + { "a", 1 }, + { "abcdefg", 7 }, + { "abcdefg\0hijk", 7 } + }; + + int i; + + printf("Test 001 (PL_strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + if( PL_strlen(array[i].str) != array[i].len ) + { + printf("FAIL (%d: %s->%d, %d)\n", i, + array[i].str ? array[i].str : "(null)", + PL_strlen(array[i].str), array[i].len); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnlen */ +PRBool test_002(void) +{ + static struct + { + const char *str; + PRUint32 max; + PRUint32 len; + } array[] = + { + { (const char *)0, 0, 0 }, + { (const char *)0, 12, 0 }, + { "", 0, 0 }, + { "", 12, 0 }, + { "a", 0, 0 }, + { "a", 1, 1 }, + { "a", 12, 1 }, + { "abcdefg", 0, 0 }, + { "abcdefg", 1, 1 }, + { "abcdefg", 7, 7 }, + { "abcdefg", 12, 7 }, + { "abcdefg\0hijk", 0, 0 }, + { "abcdefg\0hijk", 1, 1 }, + { "abcdefg\0hijk", 7, 7 }, + { "abcdefg\0hijk", 12, 7 }, + }; + + int i; + + printf("Test 002 (PL_strnlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + if( PL_strnlen(array[i].str, array[i].max) != array[i].len ) + { + printf("FAIL (%d: %s,%d->%d, %d)\n", i, + array[i].str ? array[i].str : "(null)", array[i].max, + PL_strnlen(array[i].str, array[i].max), array[i].len); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcpy */ +PRBool test_003(void) +{ + static char buffer[ 1024 ]; + + static struct + { + const char *str; + char *dest; + char *rv; + PRBool comp; + } array[] = + { + { (const char *)0, (char *)0, (char *)0, PR_FALSE }, + { (const char *)0, buffer, (char *)0, PR_FALSE }, + { "", (char *)0, (char *)0, PR_FALSE }, + { "", buffer, buffer, PR_TRUE }, + { "a", (char *)0, (char *)0, PR_FALSE }, + { "a", buffer, buffer, PR_TRUE }, + { "abcdefg", (char *)0, (char *)0, PR_FALSE }, + { "abcdefg", buffer, buffer, PR_TRUE }, + { "wxyz\0abcdefg", (char *)0, (char *)0, PR_FALSE }, + { "wxyz\0abcdefg", buffer, buffer, PR_TRUE } + }; + + int i; + + printf("Test 003 (PL_strcpy) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv; + const char *a = array[i].str; + const char *b = (const char *)array[i].dest; + + rv = PL_strcpy(array[i].dest, array[i].str); + if( array[i].rv != rv ) + { + printf("FAIL %d: (0x%x, %s)->0x%x\n", i, array[i].dest, + array[i].str ? array[i].str : "(null)", rv); + return PR_FALSE; + } + + if( array[i].comp ) + { + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s->%.32s\n", i, + array[i].str ? array[i].str : "(null)", + array[i].dest ? array[i].dest : "(null)"); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncpy */ +PRBool test_004(void) +{ + static char buffer[ 1024 ]; + + static struct + { + const char *str; + PRUint32 len; + char *dest; + char *rv; + PRBool comp; + const char *result; + PRBool nulled; + } array[] = + { + { (const char *)0, 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 0, buffer, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 1, buffer, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 7, buffer, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 1, buffer, buffer, PR_TRUE, "", PR_TRUE }, + { "", 7, buffer, buffer, PR_TRUE, "", PR_TRUE }, + { "a", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "a", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "a", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "a", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "b", 1, buffer, buffer, PR_TRUE, "b", PR_FALSE }, + { "c", 7, buffer, buffer, PR_TRUE, "c", PR_TRUE }, + { "de", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "de", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "de", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "de", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "fg", 1, buffer, buffer, PR_TRUE, "f", PR_FALSE }, + { "hi", 7, buffer, buffer, PR_TRUE, "hi", PR_TRUE }, + { "jklmnopq", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "rstuvwxy", 1, buffer, buffer, PR_TRUE, "r", PR_FALSE }, + { "zABCDEFG", 7, buffer, buffer, PR_TRUE, "zABCDEF", PR_FALSE }, + { "a\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "a\0XXX", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "a\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "a\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "b\0XXX", 1, buffer, buffer, PR_TRUE, "b", PR_FALSE }, + { "c\0XXX", 7, buffer, buffer, PR_TRUE, "c", PR_TRUE }, + { "de\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "de\0XXX", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "de\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "de\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "fg\0XXX", 1, buffer, buffer, PR_TRUE, "f", PR_FALSE }, + { "hi\0XXX", 7, buffer, buffer, PR_TRUE, "hi", PR_TRUE }, + { "jklmnopq\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq\0XXX", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "rstuvwxy\0XXX", 1, buffer, buffer, PR_TRUE, "r", PR_FALSE }, + { "zABCDEFG\0XXX", 7, buffer, buffer, PR_TRUE, "zABCDEF", PR_FALSE }, + }; + + int i; + + printf("Test 004 (PL_strncpy) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv; + int j; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + rv = PL_strncpy(array[i].dest, array[i].str, array[i].len); + if( array[i].rv != rv ) + { + printf("FAIL %d: (0x%x, %s, %lu)->0x%x\n", i, array[i].dest, + array[i].str ? array[i].str : "(null)", array[i].len, rv); + return PR_FALSE; + } + + if( array[i].comp ) + { + const char *a = array[i].result; + const char *b = array[i].dest; + + while( *a ) + { + if( *a != *b ) + { + printf("FAIL %d: %s != %.32s\n", i, + array[i].result, array[i].dest); + return PR_FALSE; + } + + a++; + b++; + } + + if( array[i].nulled ) + { + if( *b != '\0' ) + { + printf("FAIL %d: not terminated\n", i); + return PR_FALSE; + } + } + else + { + if( *b != '-' ) + { + printf("FAIL %d: overstepped\n", i); + return PR_FALSE; + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncpyz */ +PRBool test_005(void) +{ + static char buffer[ 1024 ]; + + static struct + { + const char *str; + PRUint32 len; + char *dest; + char *rv; + PRBool comp; + const char *result; + } array[] = + { + { (const char *)0, 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 1, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 7, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "", 1, buffer, buffer, PR_TRUE, "" }, + { "", 7, buffer, buffer, PR_TRUE, "" }, + { "a", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "a", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "a", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "a", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "b", 1, buffer, buffer, PR_TRUE, "" }, + { "c", 7, buffer, buffer, PR_TRUE, "c" }, + { "de", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "de", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "de", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "de", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "fg", 1, buffer, buffer, PR_TRUE, "" }, + { "hi", 7, buffer, buffer, PR_TRUE, "hi" }, + { "jklmnopq", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "rstuvwxy", 1, buffer, buffer, PR_TRUE, "" }, + { "zABCDEFG", 7, buffer, buffer, PR_TRUE, "zABCDE" }, + { "a\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "a\0XXX", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "a\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "a\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "b\0XXX", 1, buffer, buffer, PR_TRUE, "" }, + { "c\0XXX", 7, buffer, buffer, PR_TRUE, "c" }, + { "de\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "de\0XXX", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "de\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "de\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "fg\0XXX", 1, buffer, buffer, PR_TRUE, "" }, + { "hi\0XXX", 7, buffer, buffer, PR_TRUE, "hi" }, + { "jklmnopq\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq\0XXX", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "rstuvwxy\0XXX", 1, buffer, buffer, PR_TRUE, "" }, + { "zABCDEFG\0XXX", 7, buffer, buffer, PR_TRUE, "zABCDE" }, + }; + + int i; + + printf("Test 005 (PL_strncpyz) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv; + int j; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + rv = PL_strncpyz(array[i].dest, array[i].str, array[i].len); + if( array[i].rv != rv ) + { + printf("FAIL %d: (0x%x, %s, %lu)->0x%x\n", i, array[i].dest, + array[i].str ? array[i].str : "(null)", array[i].len, rv); + return PR_FALSE; + } + + if( array[i].comp ) + { + const char *a = array[i].result; + const char *b = array[i].dest; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s != %.32s\n", i, + array[i].result, array[i].dest); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strdup */ +PRBool test_006(void) +{ + static const char *array[] = + { + (const char *)0, + "", + "a", + "abcdefg" + }; + + int i; + + printf("Test 006 (PL_strdup) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strdup(array[i]); + + if( (char *)0 == rv ) + { + printf("FAIL %d: 0x%x -> 0\n", i, array[i]); + return PR_FALSE; + } + + if( (const char *)0 == array[i] ) + { + if( (char)0 != *rv ) + { + printf("FAIL %d: (const char *)0 -> %.32s\n", i, rv); + return PR_FALSE; + } + } + else + { + const char *a = array[i]; + const char *b = (const char *)rv; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s != %.32s\n", i, array[i], rv); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + + } + PL_strfree(rv); + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strndup */ +PRBool test_007(void) +{ + static struct + { + const char *str; + PRUint32 len; + const char *result; + } array[] = + { + { (const char *)0, 0, "" }, + { (const char *)0, 1, "" }, + { (const char *)0, 7, "" }, + { "", 0, "" }, + { "", 1, "" }, + { "", 7, "" }, + { "a", 0, "" }, + { "a", 1, "a" }, + { "a", 7, "a" }, + { "ab", 0, "" }, + { "ab", 1, "a" }, + { "ab", 7, "ab" }, + { "abcdefg", 0, "" }, + { "abcdefg", 1, "a" }, + { "abcdefg", 7, "abcdefg" }, + { "abcdefghijk", 0, "" }, + { "abcdefghijk", 1, "a" }, + { "abcdefghijk", 7, "abcdefg" }, + { "abcdef\0ghijk", 0, "" }, + { "abcdef\0ghijk", 1, "a" }, + { "abcdef\0ghijk", 7, "abcdef" } + }; + + int i; + + printf("Test 007 (PL_strndup) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strndup(array[i].str, array[i].len); + const char *a; + const char *b; + + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%lu -> 0\n", i, + array[i].str ? array[i].str : "(null)", array[i].len); + return PR_FALSE; + } + + a = array[i].result; + b = (const char *)rv; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s != %.32s\n", i, array[i].result, rv); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + + free(rv); + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcat */ +PRBool test_008(void) +{ + static struct + { + const char *first; + const char *second; + const char *result; + } array[] = + { + { (const char *)0, (const char *)0, (const char *)0 }, + { (const char *)0, "xyz", (const char *)0 }, + { "", (const char *)0, "" }, + { "", "", "" }, + { "ab", "", "ab" }, + { "cd", "ef", "cdef" }, + { "gh\0X", "", "gh" }, + { "ij\0X", "kl", "ijkl" }, + { "mn\0X", "op\0X", "mnop" }, + { "qr", "st\0X", "qrst" }, + { "uv\0X", "wx\0X", "uvwx" } + }; + + int i; + + printf("Test 008 (PL_strcat) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char buffer[ 1024 ]; + int j; + char *rv; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + if( (const char *)0 != array[i].first ) + (void)PL_strcpy(buffer, array[i].first); + + rv = PL_strcat(((const char *)0 == array[i].first) ? (char *)0 : buffer, + array[i].second); + + if( (const char *)0 == array[i].result ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s+%s -> %.32s, not zero\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s+%s -> null, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].result); + return PR_FALSE; + } + else + { + const char *a = array[i].result; + const char *b = (const char *)rv; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s+%s -> %.32s, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + rv, array[i].result); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncat */ +PRBool test_009(void) +{ + static struct + { + const char *first; + const char *second; + PRUint32 length; + PRBool nulled; + const char *result; + } array[] = + { + { (const char *)0, (const char *)0, 0, PR_FALSE, (const char *)0 }, + { (const char *)0, (const char *)0, 1, PR_FALSE, (const char *)0 }, + { (const char *)0, (const char *)0, 7, PR_FALSE, (const char *)0 }, + { (const char *)0, "", 0, PR_FALSE, (const char *)0 }, + { (const char *)0, "", 1, PR_FALSE, (const char *)0 }, + { (const char *)0, "", 7, PR_FALSE, (const char *)0 }, + { (const char *)0, "stuff", 0, PR_FALSE, (const char *)0 }, + { (const char *)0, "stuff", 1, PR_FALSE, (const char *)0 }, + { (const char *)0, "stuff", 7, PR_FALSE, (const char *)0 }, + { "", (const char *)0, 0, PR_TRUE, "" }, + { "", (const char *)0, 1, PR_TRUE, "" }, + { "", (const char *)0, 7, PR_TRUE, "" }, + { "", "", 0, PR_TRUE, "" }, + { "", "", 1, PR_TRUE, "" }, + { "", "", 7, PR_TRUE, "" }, + { "", "abcdefgh", 0, PR_TRUE, "" }, + { "", "abcdefgh", 1, PR_FALSE, "a" }, + { "", "abcdefgh", 7, PR_FALSE, "abcdefg" }, + { "xyz", (const char *)0, 0, PR_TRUE, "xyz" }, + { "xyz", (const char *)0, 1, PR_TRUE, "xyz" }, + { "xyz", (const char *)0, 7, PR_TRUE, "xyz" }, + { "xyz", "", 0, PR_TRUE, "xyz" }, + { "xyz", "", 1, PR_TRUE, "xyz" }, + { "xyz", "", 7, PR_TRUE, "xyz" }, + { "xyz", "abcdefgh", 0, PR_TRUE, "xyz" }, + { "xyz", "abcdefgh", 1, PR_FALSE, "xyza" }, + { "xyz", "abcdefgh", 7, PR_FALSE, "xyzabcdefg" } + }; + + int i; + + printf("Test 009 (PL_strncat) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char buffer[ 1024 ]; + int j; + char *rv; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + if( (const char *)0 != array[i].first ) + (void)PL_strcpy(buffer, array[i].first); + + rv = PL_strncat(((const char *)0 == array[i].first) ? (char *)0 : buffer, + array[i].second, array[i].length); + + if( (const char *)0 == array[i].result ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s+%s/%lu -> %.32s, not zero\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s+%s/%lu -> null, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, array[i].result); + return PR_FALSE; + } + else + { + const char *a = array[i].result; + const char *b = (const char *)rv; + + while( *a ) + { + if( *a != *b ) + { + printf("FAIL %d: %s+%s/%lu -> %.32s, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, rv, array[i].result); + return PR_FALSE; + } + + a++; + b++; + } + + if( array[i].nulled ) + { + if( (char)0 != *b ) + { + printf("FAIL %d: %s+%s/%lu -> not nulled\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length); + return PR_FALSE; + } + } + else + { + if( (char)0 == *b ) + { + printf("FAIL %d: %s+%s/%lu -> overrun\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length); + return PR_FALSE; + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcatn */ +PRBool test_010(void) +{ + static struct + { + const char *first; + const char *second; + PRUint32 length; + const char *result; + } array[] = + { + { (const char *)0, (const char *)0, 0, (const char *)0 }, + { (const char *)0, (const char *)0, 1, (const char *)0 }, + { (const char *)0, (const char *)0, 7, (const char *)0 }, + { (const char *)0, "", 0, (const char *)0 }, + { (const char *)0, "", 1, (const char *)0 }, + { (const char *)0, "", 7, (const char *)0 }, + { (const char *)0, "stuff", 0, (const char *)0 }, + { (const char *)0, "stuff", 1, (const char *)0 }, + { (const char *)0, "stuff", 7, (const char *)0 }, + { "", (const char *)0, 0, "" }, + { "", (const char *)0, 1, "" }, + { "", (const char *)0, 7, "" }, + { "", "", 0, "" }, + { "", "", 1, "" }, + { "", "", 7, "" }, + { "", "abcdefgh", 0, "" }, + { "", "abcdefgh", 1, "" }, + { "", "abcdefgh", 7, "abcdef" }, + { "xyz", (const char *)0, 0, "xyz" }, + { "xyz", (const char *)0, 1, "xyz" }, + { "xyz", (const char *)0, 7, "xyz" }, + { "xyz", "", 0, "xyz" }, + { "xyz", "", 1, "xyz" }, + { "xyz", "", 7, "xyz" }, + { "xyz", "abcdefgh", 0, "xyz" }, + { "xyz", "abcdefgh", 1, "xyz" }, + { "xyz", "abcdefgh", 7, "xyzabc" } + }; + + int i; + + printf("Test 010 (PL_strcatn) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char buffer[ 1024 ]; + int j; + char *rv; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + if( (const char *)0 != array[i].first ) + (void)PL_strcpy(buffer, array[i].first); + + rv = PL_strcatn(((const char *)0 == array[i].first) ? (char *)0 : buffer, + array[i].length, array[i].second); + + if( (const char *)0 == array[i].result ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s+%s/%lu -> %.32s, not zero\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s+%s/%lu -> null, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, array[i].result); + return PR_FALSE; + } + else + { + const char *a = array[i].result; + const char *b = (const char *)rv; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s+%s/%lu -> %.32s, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, rv, array[i].result); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcmp */ +PRBool test_011(void) +{ + static struct + { + const char *one; + const char *two; + PRIntn sign; + } array[] = + { + { (const char *)0, (const char *)0, 0 }, + { (const char *)0, "word", -1 }, + { "word", (const char *)0, 1 }, + { "word", "word", 0 }, + { "aZYXVUT", "bZYXVUT", -1 }, + { "aZYXVUT", "bAAAAAA", -1 }, + { "a", "aa", -1 }, + { "a", "a", 0 }, + { "a", "A", 1 }, + { "aaaaa", "baaaa", -1 }, + { "aaaaa", "abaaa", -1 }, + { "aaaaa", "aabaa", -1 }, + { "aaaaa", "aaaba", -1 }, + { "aaaaa", "aaaab", -1 }, + { "bZYXVUT", "aZYXVUT", 1 }, + { "bAAAAAA", "aZYXVUT", 1 }, + { "aa", "a", 1 }, + { "A", "a", -1 }, + { "baaaa", "aaaaa", 1 }, + { "abaaa", "aaaaa", 1 }, + { "aabaa", "aaaaa", 1 }, + { "aaaba", "aaaaa", 1 }, + { "aaaab", "aaaaa", 1 }, + { "word", "Word", 1 }, + { "word", "wOrd", 1 }, + { "word", "woRd", 1 }, + { "word", "worD", 1 }, + { "WORD", "wORD", -1 }, + { "WORD", "WoRD", -1 }, + { "WORD", "WOrD", -1 }, + { "WORD", "WORd", -1 } + }; + + int i; + + printf("Test 011 (PL_strcmp) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRIntn rv = PL_strcmp(array[i].one, array[i].two); + + switch( array[i].sign ) + { + case -1: + if( rv < 0 ) continue; + break; + case 1: + if( rv > 0 ) continue; + break; + case 0: + if( 0 == rv ) continue; + break; + default: + PR_NOT_REACHED("static data inconsistancy"); + break; + } + + printf("FAIL %d: %s-%s -> %d, not %d\n", i, + array[i].one ? array[i].one : "(null)", + array[i].two ? array[i].two : "(null)", + rv, array[i].sign); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncmp */ +PRBool test_012(void) +{ + static struct + { + const char *one; + const char *two; + PRUint32 max; + PRIntn sign; + } array[] = + { + { (const char *)0, (const char *)0, 0, 0 }, + { (const char *)0, (const char *)0, 1, 0 }, + { (const char *)0, (const char *)0, 4, 0 }, + { (const char *)0, "word", 0, -1 }, + { (const char *)0, "word", 1, -1 }, + { (const char *)0, "word", 4, -1 }, + { "word", (const char *)0, 0, 1 }, + { "word", (const char *)0, 1, 1 }, + { "word", (const char *)0, 4, 1 }, + { "word", "word", 0, 0 }, + { "word", "word", 1, 0 }, + { "word", "word", 3, 0 }, + { "word", "word", 5, 0 }, + { "aZYXVUT", "bZYXVUT", 0, 0 }, + { "aZYXVUT", "bZYXVUT", 1, -1 }, + { "aZYXVUT", "bZYXVUT", 4, -1 }, + { "aZYXVUT", "bZYXVUT", 9, -1 }, + { "aZYXVUT", "bAAAAAA", 0, 0 }, + { "aZYXVUT", "bAAAAAA", 1, -1 }, + { "aZYXVUT", "bAAAAAA", 4, -1 }, + { "aZYXVUT", "bAAAAAA", 5, -1 }, + { "a", "aa", 0, 0 }, + { "a", "aa", 1, 0 }, + { "a", "aa", 4, -1 }, + { "a", "a", 0, 0 }, + { "a", "a", 1, 0 }, + { "a", "a", 4, 0 }, + { "a", "A", 0, 0 }, + { "a", "A", 1, 1 }, + { "a", "A", 4, 1 }, + { "aaaaa", "baaaa", 0, 0 }, + { "aaaaa", "baaaa", 1, -1 }, + { "aaaaa", "baaaa", 4, -1 }, + { "aaaaa", "abaaa", 0, 0 }, + { "aaaaa", "abaaa", 1, 0 }, + { "aaaaa", "abaaa", 4, -1 }, + { "aaaaa", "aabaa", 0, 0 }, + { "aaaaa", "aabaa", 1, 0 }, + { "aaaaa", "aabaa", 4, -1 }, + { "aaaaa", "aaaba", 0, 0 }, + { "aaaaa", "aaaba", 1, 0 }, + { "aaaaa", "aaaba", 4, -1 }, + { "aaaaa", "aaaab", 0, 0 }, + { "aaaaa", "aaaab", 1, 0 }, + { "aaaaa", "aaaab", 4, 0 }, + { "bZYXVUT", "aZYXVUT", 0, 0 }, + { "bZYXVUT", "aZYXVUT", 1, 1 }, + { "bZYXVUT", "aZYXVUT", 4, 1 }, + { "bAAAAAA", "aZYXVUT", 0, 0 }, + { "bAAAAAA", "aZYXVUT", 1, 1 }, + { "bAAAAAA", "aZYXVUT", 4, 1 }, + { "aa", "a", 0, 0 }, + { "aa", "a", 1, 0 }, + { "aa", "a", 4, 1 }, + { "A", "a", 0, 0 }, + { "A", "a", 1, -1 }, + { "A", "a", 4, -1 }, + { "baaaa", "aaaaa", 0, 0 }, + { "baaaa", "aaaaa", 1, 1 }, + { "baaaa", "aaaaa", 4, 1 }, + { "abaaa", "aaaaa", 0, 0 }, + { "abaaa", "aaaaa", 1, 0 }, + { "abaaa", "aaaaa", 4, 1 }, + { "aabaa", "aaaaa", 0, 0 }, + { "aabaa", "aaaaa", 1, 0 }, + { "aabaa", "aaaaa", 4, 1 }, + { "aaaba", "aaaaa", 0, 0 }, + { "aaaba", "aaaaa", 1, 0 }, + { "aaaba", "aaaaa", 4, 1 }, + { "aaaab", "aaaaa", 0, 0 }, + { "aaaab", "aaaaa", 1, 0 }, + { "aaaab", "aaaaa", 4, 0 }, + { "word", "Word", 0, 0 }, + { "word", "Word", 1, 1 }, + { "word", "Word", 3, 1 }, + { "word", "wOrd", 0, 0 }, + { "word", "wOrd", 1, 0 }, + { "word", "wOrd", 3, 1 }, + { "word", "woRd", 0, 0 }, + { "word", "woRd", 1, 0 }, + { "word", "woRd", 3, 1 }, + { "word", "worD", 0, 0 }, + { "word", "worD", 1, 0 }, + { "word", "worD", 3, 0 }, + { "WORD", "wORD", 0, 0 }, + { "WORD", "wORD", 1, -1 }, + { "WORD", "wORD", 3, -1 }, + { "WORD", "WoRD", 0, 0 }, + { "WORD", "WoRD", 1, 0 }, + { "WORD", "WoRD", 3, -1 }, + { "WORD", "WOrD", 0, 0 }, + { "WORD", "WOrD", 1, 0 }, + { "WORD", "WOrD", 3, -1 }, + { "WORD", "WORd", 0, 0 }, + { "WORD", "WORd", 1, 0 }, + { "WORD", "WORd", 3, 0 } + + }; + + int i; + + printf("Test 012 (PL_strncmp) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRIntn rv = PL_strncmp(array[i].one, array[i].two, array[i].max); + + switch( array[i].sign ) + { + case -1: + if( rv < 0 ) continue; + break; + case 1: + if( rv > 0 ) continue; + break; + case 0: + if( 0 == rv ) continue; + break; + default: + PR_NOT_REACHED("static data inconsistancy"); + break; + } + + printf("FAIL %d: %s-%s/%ld -> %d, not %d\n", i, + array[i].one ? array[i].one : "(null)", + array[i].two ? array[i].two : "(null)", + array[i].max, rv, array[i].sign); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcasecmp */ +PRBool test_013(void) +{ + static struct + { + const char *one; + const char *two; + PRIntn sign; + } array[] = + { + { (const char *)0, (const char *)0, 0 }, + { (const char *)0, "word", -1 }, + { "word", (const char *)0, 1 }, + { "word", "word", 0 }, + { "aZYXVUT", "bZYXVUT", -1 }, + { "aZYXVUT", "bAAAAAA", -1 }, + { "a", "aa", -1 }, + { "a", "a", 0 }, + { "a", "A", 0 }, + { "aaaaa", "baaaa", -1 }, + { "aaaaa", "abaaa", -1 }, + { "aaaaa", "aabaa", -1 }, + { "aaaaa", "aaaba", -1 }, + { "aaaaa", "aaaab", -1 }, + { "bZYXVUT", "aZYXVUT", 1 }, + { "bAAAAAA", "aZYXVUT", 1 }, + { "aa", "a", 1 }, + { "A", "a", 0 }, + { "baaaa", "aaaaa", 1 }, + { "abaaa", "aaaaa", 1 }, + { "aabaa", "aaaaa", 1 }, + { "aaaba", "aaaaa", 1 }, + { "aaaab", "aaaaa", 1 }, + { "word", "Word", 0 }, + { "word", "wOrd", 0 }, + { "word", "woRd", 0 }, + { "word", "worD", 0 }, + { "WORD", "wORD", 0 }, + { "WORD", "WoRD", 0 }, + { "WORD", "WOrD", 0 }, + { "WORD", "WORd", 0 } + }; + + int i; + + printf("Test 013 (PL_strcasecmp) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRIntn rv = PL_strcasecmp(array[i].one, array[i].two); + + switch( array[i].sign ) + { + case -1: + if( rv < 0 ) continue; + break; + case 1: + if( rv > 0 ) continue; + break; + case 0: + if( 0 == rv ) continue; + break; + default: + PR_NOT_REACHED("static data inconsistancy"); + break; + } + + printf("FAIL %d: %s-%s -> %d, not %d\n", i, + array[i].one ? array[i].one : "(null)", + array[i].two ? array[i].two : "(null)", + rv, array[i].sign); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncasecmp */ +PRBool test_014(void) +{ + static struct + { + const char *one; + const char *two; + PRUint32 max; + PRIntn sign; + } array[] = + { + { (const char *)0, (const char *)0, 0, 0 }, + { (const char *)0, (const char *)0, 1, 0 }, + { (const char *)0, (const char *)0, 4, 0 }, + { (const char *)0, "word", 0, -1 }, + { (const char *)0, "word", 1, -1 }, + { (const char *)0, "word", 4, -1 }, + { "word", (const char *)0, 0, 1 }, + { "word", (const char *)0, 1, 1 }, + { "word", (const char *)0, 4, 1 }, + { "word", "word", 0, 0 }, + { "word", "word", 1, 0 }, + { "word", "word", 3, 0 }, + { "word", "word", 5, 0 }, + { "aZYXVUT", "bZYXVUT", 0, 0 }, + { "aZYXVUT", "bZYXVUT", 1, -1 }, + { "aZYXVUT", "bZYXVUT", 4, -1 }, + { "aZYXVUT", "bZYXVUT", 9, -1 }, + { "aZYXVUT", "bAAAAAA", 0, 0 }, + { "aZYXVUT", "bAAAAAA", 1, -1 }, + { "aZYXVUT", "bAAAAAA", 4, -1 }, + { "aZYXVUT", "bAAAAAA", 5, -1 }, + { "a", "aa", 0, 0 }, + { "a", "aa", 1, 0 }, + { "a", "aa", 4, -1 }, + { "a", "a", 0, 0 }, + { "a", "a", 1, 0 }, + { "a", "a", 4, 0 }, + { "a", "A", 0, 0 }, + { "a", "A", 1, 0 }, + { "a", "A", 4, 0 }, + { "aaaaa", "baaaa", 0, 0 }, + { "aaaaa", "baaaa", 1, -1 }, + { "aaaaa", "baaaa", 4, -1 }, + { "aaaaa", "abaaa", 0, 0 }, + { "aaaaa", "abaaa", 1, 0 }, + { "aaaaa", "abaaa", 4, -1 }, + { "aaaaa", "aabaa", 0, 0 }, + { "aaaaa", "aabaa", 1, 0 }, + { "aaaaa", "aabaa", 4, -1 }, + { "aaaaa", "aaaba", 0, 0 }, + { "aaaaa", "aaaba", 1, 0 }, + { "aaaaa", "aaaba", 4, -1 }, + { "aaaaa", "aaaab", 0, 0 }, + { "aaaaa", "aaaab", 1, 0 }, + { "aaaaa", "aaaab", 4, 0 }, + { "bZYXVUT", "aZYXVUT", 0, 0 }, + { "bZYXVUT", "aZYXVUT", 1, 1 }, + { "bZYXVUT", "aZYXVUT", 4, 1 }, + { "bAAAAAA", "aZYXVUT", 0, 0 }, + { "bAAAAAA", "aZYXVUT", 1, 1 }, + { "bAAAAAA", "aZYXVUT", 4, 1 }, + { "aa", "a", 0, 0 }, + { "aa", "a", 1, 0 }, + { "aa", "a", 4, 1 }, + { "A", "a", 0, 0 }, + { "A", "a", 1, 0 }, + { "A", "a", 4, 0 }, + { "baaaa", "aaaaa", 0, 0 }, + { "baaaa", "aaaaa", 1, 1 }, + { "baaaa", "aaaaa", 4, 1 }, + { "abaaa", "aaaaa", 0, 0 }, + { "abaaa", "aaaaa", 1, 0 }, + { "abaaa", "aaaaa", 4, 1 }, + { "aabaa", "aaaaa", 0, 0 }, + { "aabaa", "aaaaa", 1, 0 }, + { "aabaa", "aaaaa", 4, 1 }, + { "aaaba", "aaaaa", 0, 0 }, + { "aaaba", "aaaaa", 1, 0 }, + { "aaaba", "aaaaa", 4, 1 }, + { "aaaab", "aaaaa", 0, 0 }, + { "aaaab", "aaaaa", 1, 0 }, + { "aaaab", "aaaaa", 4, 0 }, + { "word", "Word", 0, 0 }, + { "word", "Word", 1, 0 }, + { "word", "Word", 3, 0 }, + { "word", "wOrd", 0, 0 }, + { "word", "wOrd", 1, 0 }, + { "word", "wOrd", 3, 0 }, + { "word", "woRd", 0, 0 }, + { "word", "woRd", 1, 0 }, + { "word", "woRd", 3, 0 }, + { "word", "worD", 0, 0 }, + { "word", "worD", 1, 0 }, + { "word", "worD", 3, 0 }, + { "WORD", "wORD", 0, 0 }, + { "WORD", "wORD", 1, 0 }, + { "WORD", "wORD", 3, 0 }, + { "WORD", "WoRD", 0, 0 }, + { "WORD", "WoRD", 1, 0 }, + { "WORD", "WoRD", 3, 0 }, + { "WORD", "WOrD", 0, 0 }, + { "WORD", "WOrD", 1, 0 }, + { "WORD", "WOrD", 3, 0 }, + { "WORD", "WORd", 0, 0 }, + { "WORD", "WORd", 1, 0 }, + { "WORD", "WORd", 3, 0 } + }; + + int i; + + printf("Test 014 (PL_strncasecmp) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRIntn rv = PL_strncasecmp(array[i].one, array[i].two, array[i].max); + + switch( array[i].sign ) + { + case -1: + if( rv < 0 ) continue; + break; + case 1: + if( rv > 0 ) continue; + break; + case 0: + if( 0 == rv ) continue; + break; + default: + PR_NOT_REACHED("static data inconsistancy"); + break; + } + + printf("FAIL %d: %s-%s/%ld -> %d, not %d\n", i, + array[i].one ? array[i].one : "(null)", + array[i].two ? array[i].two : "(null)", + array[i].max, rv, array[i].sign); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strchr */ +PRBool test_015(void) +{ + static struct + { + const char *str; + char chr; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, 'a', PR_FALSE, 0 }, + { (const char *)0, '\0', PR_FALSE, 0 }, + { "abcdefg", 'a', PR_TRUE, 0 }, + { "abcdefg", 'b', PR_TRUE, 1 }, + { "abcdefg", 'c', PR_TRUE, 2 }, + { "abcdefg", 'd', PR_TRUE, 3 }, + { "abcdefg", 'e', PR_TRUE, 4 }, + { "abcdefg", 'f', PR_TRUE, 5 }, + { "abcdefg", 'g', PR_TRUE, 6 }, + { "abcdefg", 'h', PR_FALSE, 0 }, + { "abcdefg", '\0', PR_TRUE, 7 }, + { "abcdefg", 'A', PR_FALSE, 0 }, + { "abcdefg", 'B', PR_FALSE, 0 }, + { "abcdefg", 'C', PR_FALSE, 0 }, + { "abcdefg", 'D', PR_FALSE, 0 }, + { "abcdefg", 'E', PR_FALSE, 0 }, + { "abcdefg", 'F', PR_FALSE, 0 }, + { "abcdefg", 'G', PR_FALSE, 0 }, + { "abcdefg", 'H', PR_FALSE, 0 }, + { "abcdefgabcdefg", 'a', PR_TRUE, 0 }, + { "abcdefgabcdefg", 'b', PR_TRUE, 1 }, + { "abcdefgabcdefg", 'c', PR_TRUE, 2 }, + { "abcdefgabcdefg", 'd', PR_TRUE, 3 }, + { "abcdefgabcdefg", 'e', PR_TRUE, 4 }, + { "abcdefgabcdefg", 'f', PR_TRUE, 5 }, + { "abcdefgabcdefg", 'g', PR_TRUE, 6 }, + { "abcdefgabcdefg", 'h', PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', PR_TRUE, 14 } + }; + + int i; + + printf("Test 015 (PL_strchr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strchr(array[i].str, array[i].chr); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%c -> %.32s, not zero\n", i, array[i].str, + array[i].chr, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%c -> null, not +%lu\n", i, array[i].str, + array[i].chr, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%c -> 0x%x, not 0x%x+%lu\n", i, array[i].str, + array[i].chr, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strrchr */ +PRBool test_016(void) +{ + static struct + { + const char *str; + char chr; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, 'a', PR_FALSE, 0 }, + { (const char *)0, '\0', PR_FALSE, 0 }, + { "abcdefg", 'a', PR_TRUE, 0 }, + { "abcdefg", 'b', PR_TRUE, 1 }, + { "abcdefg", 'c', PR_TRUE, 2 }, + { "abcdefg", 'd', PR_TRUE, 3 }, + { "abcdefg", 'e', PR_TRUE, 4 }, + { "abcdefg", 'f', PR_TRUE, 5 }, + { "abcdefg", 'g', PR_TRUE, 6 }, + { "abcdefg", 'h', PR_FALSE, 0 }, + { "abcdefg", '\0', PR_TRUE, 7 }, + { "abcdefg", 'A', PR_FALSE, 0 }, + { "abcdefg", 'B', PR_FALSE, 0 }, + { "abcdefg", 'C', PR_FALSE, 0 }, + { "abcdefg", 'D', PR_FALSE, 0 }, + { "abcdefg", 'E', PR_FALSE, 0 }, + { "abcdefg", 'F', PR_FALSE, 0 }, + { "abcdefg", 'G', PR_FALSE, 0 }, + { "abcdefg", 'H', PR_FALSE, 0 }, + { "abcdefgabcdefg", 'a', PR_TRUE, 7 }, + { "abcdefgabcdefg", 'b', PR_TRUE, 8 }, + { "abcdefgabcdefg", 'c', PR_TRUE, 9 }, + { "abcdefgabcdefg", 'd', PR_TRUE, 10 }, + { "abcdefgabcdefg", 'e', PR_TRUE, 11 }, + { "abcdefgabcdefg", 'f', PR_TRUE, 12 }, + { "abcdefgabcdefg", 'g', PR_TRUE, 13 }, + { "abcdefgabcdefg", 'h', PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', PR_TRUE, 14 } + }; + + int i; + + printf("Test 016 (PL_strrchr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strrchr(array[i].str, array[i].chr); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%c -> %.32s, not zero\n", i, array[i].str, + array[i].chr, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%c -> null, not +%lu\n", i, array[i].str, + array[i].chr, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%c -> 0x%x, not 0x%x+%lu\n", i, array[i].str, + array[i].chr, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnchr */ +PRBool test_017(void) +{ + static struct + { + const char *str; + char chr; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, 'a', 2, PR_FALSE, 0 }, + { (const char *)0, '\0', 2, PR_FALSE, 0 }, + { "abcdefg", 'a', 5, PR_TRUE, 0 }, + { "abcdefg", 'b', 5, PR_TRUE, 1 }, + { "abcdefg", 'c', 5, PR_TRUE, 2 }, + { "abcdefg", 'd', 5, PR_TRUE, 3 }, + { "abcdefg", 'e', 5, PR_TRUE, 4 }, + { "abcdefg", 'f', 5, PR_FALSE, 0 }, + { "abcdefg", 'g', 5, PR_FALSE, 0 }, + { "abcdefg", 'h', 5, PR_FALSE, 0 }, + { "abcdefg", '\0', 5, PR_FALSE, 0 }, + { "abcdefg", '\0', 15, PR_TRUE, 7 }, + { "abcdefg", 'A', 5, PR_FALSE, 0 }, + { "abcdefg", 'B', 5, PR_FALSE, 0 }, + { "abcdefg", 'C', 5, PR_FALSE, 0 }, + { "abcdefg", 'D', 5, PR_FALSE, 0 }, + { "abcdefg", 'E', 5, PR_FALSE, 0 }, + { "abcdefg", 'F', 5, PR_FALSE, 0 }, + { "abcdefg", 'G', 5, PR_FALSE, 0 }, + { "abcdefg", 'H', 5, PR_FALSE, 0 }, + { "abcdefgabcdefg", 'a', 10, PR_TRUE, 0 }, + { "abcdefgabcdefg", 'b', 10, PR_TRUE, 1 }, + { "abcdefgabcdefg", 'c', 10, PR_TRUE, 2 }, + { "abcdefgabcdefg", 'd', 10, PR_TRUE, 3 }, + { "abcdefgabcdefg", 'e', 10, PR_TRUE, 4 }, + { "abcdefgabcdefg", 'f', 10, PR_TRUE, 5 }, + { "abcdefgabcdefg", 'g', 10, PR_TRUE, 6 }, + { "abcdefgabcdefg", 'h', 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 14, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 15, PR_TRUE, 14 } + }; + + int i; + + printf("Test 017 (PL_strnchr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnchr(array[i].str, array[i].chr, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%c/%lu -> %.32s, not zero\n", i, array[i].str, + array[i].chr, array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%c/%lu -> null, not +%lu\n", i, array[i].str, + array[i].chr, array[i].max, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%c/%lu -> 0x%x, not 0x%x+%lu\n", i, array[i].str, + array[i].chr, array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnrchr */ +PRBool test_018(void) +{ + static struct + { + const char *str; + char chr; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, 'a', 2, PR_FALSE, 0 }, + { (const char *)0, '\0', 2, PR_FALSE, 0 }, + { "abcdefg", 'a', 5, PR_TRUE, 0 }, + { "abcdefg", 'b', 5, PR_TRUE, 1 }, + { "abcdefg", 'c', 5, PR_TRUE, 2 }, + { "abcdefg", 'd', 5, PR_TRUE, 3 }, + { "abcdefg", 'e', 5, PR_TRUE, 4 }, + { "abcdefg", 'f', 5, PR_FALSE, 0 }, + { "abcdefg", 'g', 5, PR_FALSE, 0 }, + { "abcdefg", 'h', 5, PR_FALSE, 0 }, + { "abcdefg", '\0', 5, PR_FALSE, 0 }, + { "abcdefg", '\0', 15, PR_TRUE, 7 }, + { "abcdefg", 'A', 5, PR_FALSE, 0 }, + { "abcdefg", 'B', 5, PR_FALSE, 0 }, + { "abcdefg", 'C', 5, PR_FALSE, 0 }, + { "abcdefg", 'D', 5, PR_FALSE, 0 }, + { "abcdefg", 'E', 5, PR_FALSE, 0 }, + { "abcdefg", 'F', 5, PR_FALSE, 0 }, + { "abcdefg", 'G', 5, PR_FALSE, 0 }, + { "abcdefg", 'H', 5, PR_FALSE, 0 }, + { "abcdefgabcdefg", 'a', 10, PR_TRUE, 7 }, + { "abcdefgabcdefg", 'b', 10, PR_TRUE, 8 }, + { "abcdefgabcdefg", 'c', 10, PR_TRUE, 9 }, + { "abcdefgabcdefg", 'd', 10, PR_TRUE, 3 }, + { "abcdefgabcdefg", 'e', 10, PR_TRUE, 4 }, + { "abcdefgabcdefg", 'f', 10, PR_TRUE, 5 }, + { "abcdefgabcdefg", 'g', 10, PR_TRUE, 6 }, + { "abcdefgabcdefg", 'h', 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 14, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 15, PR_TRUE, 14 } + }; + + int i; + + printf("Test 018 (PL_strnrchr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnrchr(array[i].str, array[i].chr, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%c/%lu -> %.32s, not zero\n", i, array[i].str, + array[i].chr, array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%c/%lu -> null, not +%lu\n", i, array[i].str, + array[i].chr, array[i].max, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%c/%lu -> 0x%x, not 0x%x+%lu\n", i, array[i].str, + array[i].chr, array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strpbrk */ +PRBool test_019(void) +{ + static struct + { + const char *str; + const char *chrs; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "abc", PR_FALSE, 0 }, + { "abc", (const char *)0, PR_FALSE, 0 }, + { "abcdefg", "", PR_FALSE, 0 }, + { "", "aeiou", PR_FALSE, 0 }, + { "abcdefg", "ae", PR_TRUE, 0 }, + { "abcdefg", "ei", PR_TRUE, 4 }, + { "abcdefg", "io", PR_FALSE, 0 }, + { "abcdefg", "bcd", PR_TRUE, 1 }, + { "abcdefg", "cbd", PR_TRUE, 1 }, + { "abcdefg", "dbc", PR_TRUE, 1 }, + { "abcdefg", "ghi", PR_TRUE, 6 }, + { "abcdefg", "AE", PR_FALSE, 0 }, + { "abcdefg", "EI", PR_FALSE, 0 }, + { "abcdefg", "IO", PR_FALSE, 0 }, + { "abcdefg", "BCD", PR_FALSE, 0 }, + { "abcdefg", "CBD", PR_FALSE, 0 }, + { "abcdefg", "DBC", PR_FALSE, 0 }, + { "abcdefg", "GHI", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ae", PR_TRUE, 0 }, + { "abcdefgabcdefg", "ei", PR_TRUE, 4 }, + { "abcdefgabcdefg", "io", PR_FALSE, 0 }, + { "abcdefgabcdefg", "bcd", PR_TRUE, 1 }, + { "abcdefgabcdefg", "cbd", PR_TRUE, 1 }, + { "abcdefgabcdefg", "dbc", PR_TRUE, 1 }, + { "abcdefgabcdefg", "ghi", PR_TRUE, 6 }, + { "abcdefgabcdefg", "AE", PR_FALSE, 0 }, + { "abcdefgabcdefg", "EI", PR_FALSE, 0 }, + { "abcdefgabcdefg", "IO", PR_FALSE, 0 }, + { "abcdefgabcdefg", "BCD", PR_FALSE, 0 }, + { "abcdefgabcdefg", "CBD", PR_FALSE, 0 }, + { "abcdefgabcdefg", "DBC", PR_FALSE, 0 }, + { "abcdefgabcdefg", "GHI", PR_FALSE, 0 } + }; + + int i; + + printf("Test 019 (PL_strpbrk) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strpbrk(array[i].str, array[i].chrs); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not +%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strprbrk */ +PRBool test_020(void) +{ + static struct + { + const char *str; + const char *chrs; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "abc", PR_FALSE, 0 }, + { "abc", (const char *)0, PR_FALSE, 0 }, + { "abcdefg", "", PR_FALSE, 0 }, + { "", "aeiou", PR_FALSE, 0 }, + { "abcdefg", "ae", PR_TRUE, 4 }, + { "abcdefg", "ei", PR_TRUE, 4 }, + { "abcdefg", "io", PR_FALSE, 0 }, + { "abcdefg", "bcd", PR_TRUE, 3 }, + { "abcdefg", "cbd", PR_TRUE, 3 }, + { "abcdefg", "dbc", PR_TRUE, 3 }, + { "abcdefg", "ghi", PR_TRUE, 6 }, + { "abcdefg", "AE", PR_FALSE, 0 }, + { "abcdefg", "EI", PR_FALSE, 0 }, + { "abcdefg", "IO", PR_FALSE, 0 }, + { "abcdefg", "BCD", PR_FALSE, 0 }, + { "abcdefg", "CBD", PR_FALSE, 0 }, + { "abcdefg", "DBC", PR_FALSE, 0 }, + { "abcdefg", "GHI", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ae", PR_TRUE, 11 }, + { "abcdefgabcdefg", "ei", PR_TRUE, 11 }, + { "abcdefgabcdefg", "io", PR_FALSE, 0 }, + { "abcdefgabcdefg", "bcd", PR_TRUE, 10 }, + { "abcdefgabcdefg", "cbd", PR_TRUE, 10 }, + { "abcdefgabcdefg", "dbc", PR_TRUE, 10 }, + { "abcdefgabcdefg", "ghi", PR_TRUE, 13 }, + { "abcdefgabcdefg", "AE", PR_FALSE, 0 }, + { "abcdefgabcdefg", "EI", PR_FALSE, 0 }, + { "abcdefgabcdefg", "IO", PR_FALSE, 0 }, + { "abcdefgabcdefg", "BCD", PR_FALSE, 0 }, + { "abcdefgabcdefg", "CBD", PR_FALSE, 0 }, + { "abcdefgabcdefg", "DBC", PR_FALSE, 0 }, + { "abcdefgabcdefg", "GHI", PR_FALSE, 0 } + }; + + int i; + + printf("Test 020 (PL_strprbrk) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strprbrk(array[i].str, array[i].chrs); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not +%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnpbrk */ +PRBool test_021(void) +{ + static struct + { + const char *str; + const char *chrs; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 3, PR_FALSE, 0 }, + { (const char *)0, "abc", 3, PR_FALSE, 0 }, + { "abc", (const char *)0, 3, PR_FALSE, 0 }, + { "abcdefg", "", 3, PR_FALSE, 0 }, + { "", "aeiou", 3, PR_FALSE, 0 }, + { "abcdefg", "ae", 0, PR_FALSE, 0 }, + { "abcdefg", "ae", 1, PR_TRUE, 0 }, + { "abcdefg", "ae", 4, PR_TRUE, 0 }, + { "abcdefg", "ae", 5, PR_TRUE, 0 }, + { "abcdefg", "ae", 6, PR_TRUE, 0 }, + { "abcdefg", "ei", 4, PR_FALSE, 0 }, + { "abcdefg", "io", 10, PR_FALSE, 0 }, + { "abcdefg", "bcd", 2, PR_TRUE, 1 }, + { "abcdefg", "cbd", 2, PR_TRUE, 1 }, + { "abcdefg", "dbc", 2, PR_TRUE, 1 }, + { "abcdefg", "ghi", 6, PR_FALSE, 0 }, + { "abcdefg", "ghi", 7, PR_TRUE, 6 }, + { "abcdefg", "AE", 9, PR_FALSE, 0 }, + { "abcdefg", "EI", 9, PR_FALSE, 0 }, + { "abcdefg", "IO", 9, PR_FALSE, 0 }, + { "abcdefg", "BCD", 9, PR_FALSE, 0 }, + { "abcdefg", "CBD", 9, PR_FALSE, 0 }, + { "abcdefg", "DBC", 9, PR_FALSE, 0 }, + { "abcdefg", "GHI", 9, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ae", 10, PR_TRUE, 0 }, + { "abcdefgabcdefg", "ei", 10, PR_TRUE, 4 }, + { "abcdefgabcdefg", "io", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "bcd", 10, PR_TRUE, 1 }, + { "abcdefgabcdefg", "cbd", 10, PR_TRUE, 1 }, + { "abcdefgabcdefg", "dbc", 10, PR_TRUE, 1 }, + { "abcdefgabcdefg", "ghi", 10, PR_TRUE, 6 }, + { "abcdefgabcdefg", "AE", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "EI", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "IO", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "BCD", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "CBD", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "DBC", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "GHI", 10, PR_FALSE, 0 } + }; + + int i; + + printf("Test 021 (PL_strnpbrk) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnpbrk(array[i].str, array[i].chrs, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not +%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnprbrk */ +PRBool test_022(void) +{ + static struct + { + const char *str; + const char *chrs; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 3, PR_FALSE, 0 }, + { (const char *)0, "abc", 3, PR_FALSE, 0 }, + { "abc", (const char *)0, 3, PR_FALSE, 0 }, + { "abcdefg", "", 3, PR_FALSE, 0 }, + { "", "aeiou", 3, PR_FALSE, 0 }, + { "abcdefg", "ae", 0, PR_FALSE, 0 }, + { "abcdefg", "ae", 1, PR_TRUE, 0 }, + { "abcdefg", "ae", 4, PR_TRUE, 0 }, + { "abcdefg", "ae", 5, PR_TRUE, 4 }, + { "abcdefg", "ae", 6, PR_TRUE, 4 }, + { "abcdefg", "ei", 4, PR_FALSE, 0 }, + { "abcdefg", "io", 10, PR_FALSE, 0 }, + { "abcdefg", "bcd", 2, PR_TRUE, 1 }, + { "abcdefg", "cbd", 2, PR_TRUE, 1 }, + { "abcdefg", "dbc", 2, PR_TRUE, 1 }, + { "abcdefg", "bcd", 3, PR_TRUE, 2 }, + { "abcdefg", "cbd", 3, PR_TRUE, 2 }, + { "abcdefg", "dbc", 3, PR_TRUE, 2 }, + { "abcdefg", "bcd", 5, PR_TRUE, 3 }, + { "abcdefg", "cbd", 5, PR_TRUE, 3 }, + { "abcdefg", "dbc", 5, PR_TRUE, 3 }, + { "abcdefg", "bcd", 15, PR_TRUE, 3 }, + { "abcdefg", "cbd", 15, PR_TRUE, 3 }, + { "abcdefg", "dbc", 15, PR_TRUE, 3 }, + { "abcdefg", "ghi", 6, PR_FALSE, 0 }, + { "abcdefg", "ghi", 7, PR_TRUE, 6 }, + { "abcdefg", "AE", 9, PR_FALSE, 0 }, + { "abcdefg", "EI", 9, PR_FALSE, 0 }, + { "abcdefg", "IO", 9, PR_FALSE, 0 }, + { "abcdefg", "BCD", 9, PR_FALSE, 0 }, + { "abcdefg", "CBD", 9, PR_FALSE, 0 }, + { "abcdefg", "DBC", 9, PR_FALSE, 0 }, + { "abcdefg", "GHI", 9, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ae", 10, PR_TRUE, 7 }, + { "abcdefgabcdefg", "ei", 10, PR_TRUE, 4 }, + { "abcdefgabcdefg", "io", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "bcd", 10, PR_TRUE, 9 }, + { "abcdefgabcdefg", "cbd", 10, PR_TRUE, 9 }, + { "abcdefgabcdefg", "dbc", 10, PR_TRUE, 9 }, + { "abcdefgabcdefg", "ghi", 10, PR_TRUE, 6 }, + { "abcdefgabcdefg", "AE", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "EI", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "IO", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "BCD", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "CBD", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "DBC", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "GHI", 10, PR_FALSE, 0 } + }; + + int i; + + printf("Test 022 (PL_strnprbrk) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnprbrk(array[i].str, array[i].chrs, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not +%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strstr */ +PRBool test_023(void) +{ + static struct + { + const char *str; + const char *sub; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "blah", PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", PR_TRUE, 0 }, + { "", "blah", PR_FALSE, 0 }, + { "blah-de-blah", "", PR_FALSE, 0 }, + { "abcdefg", "a", PR_TRUE, 0 }, + { "abcdefg", "c", PR_TRUE, 2 }, + { "abcdefg", "e", PR_TRUE, 4 }, + { "abcdefg", "g", PR_TRUE, 6 }, + { "abcdefg", "i", PR_FALSE, 0 }, + { "abcdefg", "ab", PR_TRUE, 0 }, + { "abcdefg", "cd", PR_TRUE, 2 }, + { "abcdefg", "ef", PR_TRUE, 4 }, + { "abcdefg", "gh", PR_FALSE, 0 }, + { "abcdabc", "bc", PR_TRUE, 1 }, + { "abcdefg", "abcdefg", PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", PR_TRUE, 0 }, + { "abcdefgabcdefg", "c", PR_TRUE, 2 }, + { "abcdefgabcdefg", "e", PR_TRUE, 4 }, + { "abcdefgabcdefg", "g", PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", PR_TRUE, 0 }, + { "abcdefgabcdefg", "cd", PR_TRUE, 2 }, + { "abcdefgabcdefg", "ef", PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", PR_TRUE, 1 }, + { "abcdefgabcdefg", "abcdefg", PR_TRUE, 0 }, + { "ABCDEFG", "a", PR_FALSE, 0 }, + { "ABCDEFG", "c", PR_FALSE, 0 }, + { "ABCDEFG", "e", PR_FALSE, 0 }, + { "ABCDEFG", "g", PR_FALSE, 0 }, + { "ABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFG", "ab", PR_FALSE, 0 }, + { "ABCDEFG", "cd", PR_FALSE, 0 }, + { "ABCDEFG", "ef", PR_FALSE, 0 }, + { "ABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABC", "bc", PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "a", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "c", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "e", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "g", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "cd", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ef", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", PR_FALSE, 0 } + }; + + int i; + + printf("Test 023 (PL_strstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strstr(array[i].str, array[i].sub); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strrstr */ +PRBool test_024(void) +{ + static struct + { + const char *str; + const char *sub; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "blah", PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", PR_TRUE, 8 }, + { "", "blah", PR_FALSE, 0 }, + { "blah-de-blah", "", PR_FALSE, 0 }, + { "abcdefg", "a", PR_TRUE, 0 }, + { "abcdefg", "c", PR_TRUE, 2 }, + { "abcdefg", "e", PR_TRUE, 4 }, + { "abcdefg", "g", PR_TRUE, 6 }, + { "abcdefg", "i", PR_FALSE, 0 }, + { "abcdefg", "ab", PR_TRUE, 0 }, + { "abcdefg", "cd", PR_TRUE, 2 }, + { "abcdefg", "ef", PR_TRUE, 4 }, + { "abcdefg", "gh", PR_FALSE, 0 }, + { "abcdabc", "bc", PR_TRUE, 5 }, + { "abcdefg", "abcdefg", PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", PR_TRUE, 7 }, + { "abcdefgabcdefg", "c", PR_TRUE, 9 }, + { "abcdefgabcdefg", "e", PR_TRUE, 11 }, + { "abcdefgabcdefg", "g", PR_TRUE, 13 }, + { "abcdefgabcdefg", "i", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", PR_TRUE, 7 }, + { "abcdefgabcdefg", "cd", PR_TRUE, 9 }, + { "abcdefgabcdefg", "ef", PR_TRUE, 11 }, + { "abcdefgabcdefg", "gh", PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", PR_TRUE, 12 }, + { "abcdefgabcdefg", "abcdefg", PR_TRUE, 7 }, + { "ABCDEFG", "a", PR_FALSE, 0 }, + { "ABCDEFG", "c", PR_FALSE, 0 }, + { "ABCDEFG", "e", PR_FALSE, 0 }, + { "ABCDEFG", "g", PR_FALSE, 0 }, + { "ABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFG", "ab", PR_FALSE, 0 }, + { "ABCDEFG", "cd", PR_FALSE, 0 }, + { "ABCDEFG", "ef", PR_FALSE, 0 }, + { "ABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABC", "bc", PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "a", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "c", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "e", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "g", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "cd", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ef", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", PR_FALSE, 0 } + }; + + int i; + + printf("Test 024 (PL_strrstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strrstr(array[i].str, array[i].sub); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnstr */ +PRBool test_025(void) +{ + static struct + { + const char *str; + const char *sub; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 12, PR_FALSE, 0 }, + { (const char *)0, "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, 12, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 2, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 3, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 4, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 5, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 12, PR_TRUE, 0 }, + { "", "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", "", 12, PR_FALSE, 0 }, + { "abcdefg", "a", 5, PR_TRUE, 0 }, + { "abcdefg", "c", 5, PR_TRUE, 2 }, + { "abcdefg", "e", 5, PR_TRUE, 4 }, + { "abcdefg", "g", 5, PR_FALSE, 0 }, + { "abcdefg", "i", 5, PR_FALSE, 0 }, + { "abcdefg", "ab", 5, PR_TRUE, 0 }, + { "abcdefg", "cd", 5, PR_TRUE, 2 }, + { "abcdefg", "ef", 5, PR_FALSE, 0 }, + { "abcdefg", "gh", 5, PR_FALSE, 0 }, + { "abcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabc", "bc", 7, PR_TRUE, 1 }, + { "abcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", 12, PR_TRUE, 0 }, + { "abcdefgabcdefg", "c", 12, PR_TRUE, 2 }, + { "abcdefgabcdefg", "e", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "g", 12, PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", 12, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", 12, PR_TRUE, 0 }, + { "abcdefgabcdefg", "cd", 12, PR_TRUE, 2 }, + { "abcdefgabcdefg", "ef", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", 12, PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabcabcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabcabcdabc", "bc", 7, PR_TRUE, 1 }, + { "abcdefgabcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefgabcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefgabcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "ABCDEFG", "a", 5, PR_FALSE, 0 }, + { "ABCDEFG", "c", 5, PR_FALSE, 0 }, + { "ABCDEFG", "e", 5, PR_FALSE, 0 }, + { "ABCDEFG", "g", 5, PR_FALSE, 0 }, + { "ABCDEFG", "i", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ab", 5, PR_FALSE, 0 }, + { "ABCDEFG", "cd", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ef", 5, PR_FALSE, 0 }, + { "ABCDEFG", "gh", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 6, PR_FALSE, 0 }, + { "ABCDABC", "bc", 7, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 7, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 8, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "a", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "c", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "e", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "g", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "i", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "cd", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ef", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "gh", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 5, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 6, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 7, PR_FALSE, }, + { "ABCDEFGABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 7, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 8, PR_FALSE, 0 } + }; + + int i; + + printf("Test 025 (PL_strnstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnstr(array[i].str, array[i].sub, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnrstr */ +PRBool test_026(void) +{ + static struct + { + const char *str; + const char *sub; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 12, PR_FALSE, 0 }, + { (const char *)0, "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, 12, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 2, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 3, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 4, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 5, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 11, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 12, PR_TRUE, 8 }, + { "blah-de-blah", "blah", 13, PR_TRUE, 8 }, + { "", "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", "", 12, PR_FALSE, 0 }, + { "abcdefg", "a", 5, PR_TRUE, 0 }, + { "abcdefg", "c", 5, PR_TRUE, 2 }, + { "abcdefg", "e", 5, PR_TRUE, 4 }, + { "abcdefg", "g", 5, PR_FALSE, 0 }, + { "abcdefg", "i", 5, PR_FALSE, 0 }, + { "abcdefg", "ab", 5, PR_TRUE, 0 }, + { "abcdefg", "cd", 5, PR_TRUE, 2 }, + { "abcdefg", "ef", 5, PR_FALSE, 0 }, + { "abcdefg", "gh", 5, PR_FALSE, 0 }, + { "abcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabc", "bc", 7, PR_TRUE, 5 }, + { "abcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", 12, PR_TRUE, 7 }, + { "abcdefgabcdefg", "c", 12, PR_TRUE, 9 }, + { "abcdefgabcdefg", "e", 12, PR_TRUE, 11 }, + { "abcdefgabcdefg", "g", 12, PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", 12, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", 12, PR_TRUE, 7 }, + { "abcdefgabcdefg", "cd", 12, PR_TRUE, 9 }, + { "abcdefgabcdefg", "ef", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", 12, PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", 12, PR_TRUE, 8 }, + { "abcdabcabcdabc", "bc", 13, PR_TRUE, 8 }, + { "abcdabcabcdabc", "bc", 14, PR_TRUE, 12 }, + { "abcdefgabcdefg", "abcdefg", 13, PR_TRUE, 0 }, + { "abcdefgabcdefg", "abcdefg", 14, PR_TRUE, 7 }, + { "abcdefgabcdefg", "abcdefg", 15, PR_TRUE, 7 }, + { "ABCDEFG", "a", 5, PR_FALSE, 0 }, + { "ABCDEFG", "c", 5, PR_FALSE, 0 }, + { "ABCDEFG", "e", 5, PR_FALSE, 0 }, + { "ABCDEFG", "g", 5, PR_FALSE, 0 }, + { "ABCDEFG", "i", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ab", 5, PR_FALSE, 0 }, + { "ABCDEFG", "cd", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ef", 5, PR_FALSE, 0 }, + { "ABCDEFG", "gh", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 6, PR_FALSE, 0 }, + { "ABCDABC", "bc", 7, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 7, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 8, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "a", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "c", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "e", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "g", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "i", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "cd", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ef", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "gh", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 13, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 14, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 13, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 14, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 15, PR_FALSE, 0 } + }; + + int i; + + printf("Test 026 (PL_strnrstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnrstr(array[i].str, array[i].sub, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcasestr */ +PRBool test_027(void) +{ + static struct + { + const char *str; + const char *sub; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "blah", PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", PR_TRUE, 0 }, + { "", "blah", PR_FALSE, 0 }, + { "blah-de-blah", "", PR_FALSE, 0 }, + { "abcdefg", "a", PR_TRUE, 0 }, + { "abcdefg", "c", PR_TRUE, 2 }, + { "abcdefg", "e", PR_TRUE, 4 }, + { "abcdefg", "g", PR_TRUE, 6 }, + { "abcdefg", "i", PR_FALSE, 0 }, + { "abcdefg", "ab", PR_TRUE, 0 }, + { "abcdefg", "cd", PR_TRUE, 2 }, + { "abcdefg", "ef", PR_TRUE, 4 }, + { "abcdefg", "gh", PR_FALSE, 0 }, + { "abcdabc", "bc", PR_TRUE, 1 }, + { "abcdefg", "abcdefg", PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", PR_TRUE, 0 }, + { "abcdefgabcdefg", "c", PR_TRUE, 2 }, + { "abcdefgabcdefg", "e", PR_TRUE, 4 }, + { "abcdefgabcdefg", "g", PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", PR_TRUE, 0 }, + { "abcdefgabcdefg", "cd", PR_TRUE, 2 }, + { "abcdefgabcdefg", "ef", PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", PR_TRUE, 1 }, + { "abcdefgabcdefg", "abcdefg", PR_TRUE, 0 }, + { "ABCDEFG", "a", PR_TRUE, 0 }, + { "ABCDEFG", "c", PR_TRUE, 2 }, + { "ABCDEFG", "e", PR_TRUE, 4 }, + { "ABCDEFG", "g", PR_TRUE, 6 }, + { "ABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFG", "ab", PR_TRUE, 0 }, + { "ABCDEFG", "cd", PR_TRUE, 2 }, + { "ABCDEFG", "ef", PR_TRUE, 4 }, + { "ABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABC", "bc", PR_TRUE, 1 }, + { "ABCDEFG", "abcdefg", PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "a", PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "c", PR_TRUE, 2 }, + { "ABCDEFGABCDEFG", "e", PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "g", PR_TRUE, 6 }, + { "ABCDEFGABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "cd", PR_TRUE, 2 }, + { "ABCDEFGABCDEFG", "ef", PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", PR_TRUE, 1 }, + { "ABCDEFGABCDEFG", "abcdefg", PR_TRUE, 0 } + }; + + int i; + + printf("Test 027 (PL_strcasestr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strcasestr(array[i].str, array[i].sub); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcaserstr */ +PRBool test_028(void) +{ + static struct + { + const char *str; + const char *sub; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "blah", PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", PR_TRUE, 8 }, + { "", "blah", PR_FALSE, 0 }, + { "blah-de-blah", "", PR_FALSE, 0 }, + { "abcdefg", "a", PR_TRUE, 0 }, + { "abcdefg", "c", PR_TRUE, 2 }, + { "abcdefg", "e", PR_TRUE, 4 }, + { "abcdefg", "g", PR_TRUE, 6 }, + { "abcdefg", "i", PR_FALSE, 0 }, + { "abcdefg", "ab", PR_TRUE, 0 }, + { "abcdefg", "cd", PR_TRUE, 2 }, + { "abcdefg", "ef", PR_TRUE, 4 }, + { "abcdefg", "gh", PR_FALSE, 0 }, + { "abcdabc", "bc", PR_TRUE, 5 }, + { "abcdefg", "abcdefg", PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", PR_TRUE, 7 }, + { "abcdefgabcdefg", "c", PR_TRUE, 9 }, + { "abcdefgabcdefg", "e", PR_TRUE, 11 }, + { "abcdefgabcdefg", "g", PR_TRUE, 13 }, + { "abcdefgabcdefg", "i", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", PR_TRUE, 7 }, + { "abcdefgabcdefg", "cd", PR_TRUE, 9 }, + { "abcdefgabcdefg", "ef", PR_TRUE, 11 }, + { "abcdefgabcdefg", "gh", PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", PR_TRUE, 12 }, + { "abcdefgabcdefg", "abcdefg", PR_TRUE, 7 }, + { "ABCDEFG", "a", PR_TRUE, 0 }, + { "ABCDEFG", "c", PR_TRUE, 2 }, + { "ABCDEFG", "e", PR_TRUE, 4 }, + { "ABCDEFG", "g", PR_TRUE, 6 }, + { "ABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFG", "ab", PR_TRUE, 0 }, + { "ABCDEFG", "cd", PR_TRUE, 2 }, + { "ABCDEFG", "ef", PR_TRUE, 4 }, + { "ABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABC", "bc", PR_TRUE, 5 }, + { "ABCDEFG", "abcdefg", PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "a", PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "c", PR_TRUE, 9 }, + { "ABCDEFGABCDEFG", "e", PR_TRUE, 11 }, + { "ABCDEFGABCDEFG", "g", PR_TRUE, 13 }, + { "ABCDEFGABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "cd", PR_TRUE, 9 }, + { "ABCDEFGABCDEFG", "ef", PR_TRUE, 11 }, + { "ABCDEFGABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", PR_TRUE, 12 }, + { "ABCDEFGABCDEFG", "abcdefg", PR_TRUE, 7 } + }; + + int i; + + printf("Test 028 (PL_strcaserstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strcaserstr(array[i].str, array[i].sub); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncasestr */ +PRBool test_029(void) +{ + static struct + { + const char *str; + const char *sub; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 12, PR_FALSE, 0 }, + { (const char *)0, "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, 12, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 2, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 3, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 4, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 5, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 12, PR_TRUE, 0 }, + { "", "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", "", 12, PR_FALSE, 0 }, + { "abcdefg", "a", 5, PR_TRUE, 0 }, + { "abcdefg", "c", 5, PR_TRUE, 2 }, + { "abcdefg", "e", 5, PR_TRUE, 4 }, + { "abcdefg", "g", 5, PR_FALSE, 0 }, + { "abcdefg", "i", 5, PR_FALSE, 0 }, + { "abcdefg", "ab", 5, PR_TRUE, 0 }, + { "abcdefg", "cd", 5, PR_TRUE, 2 }, + { "abcdefg", "ef", 5, PR_FALSE, 0 }, + { "abcdefg", "gh", 5, PR_FALSE, 0 }, + { "abcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabc", "bc", 7, PR_TRUE, 1 }, + { "abcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", 12, PR_TRUE, 0 }, + { "abcdefgabcdefg", "c", 12, PR_TRUE, 2 }, + { "abcdefgabcdefg", "e", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "g", 12, PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", 12, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", 12, PR_TRUE, 0 }, + { "abcdefgabcdefg", "cd", 12, PR_TRUE, 2 }, + { "abcdefgabcdefg", "ef", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", 12, PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabcabcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabcabcdabc", "bc", 7, PR_TRUE, 1 }, + { "abcdefgabcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefgabcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefgabcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "ABCDEFG", "a", 5, PR_TRUE, 0 }, + { "ABCDEFG", "c", 5, PR_TRUE, 2 }, + { "ABCDEFG", "e", 5, PR_TRUE, 4 }, + { "ABCDEFG", "g", 5, PR_FALSE, 0 }, + { "ABCDEFG", "i", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ab", 5, PR_TRUE, 0 }, + { "ABCDEFG", "cd", 5, PR_TRUE, 2 }, + { "ABCDEFG", "ef", 5, PR_FALSE, 0 }, + { "ABCDEFG", "gh", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 5, PR_TRUE, 1 }, + { "ABCDABC", "bc", 6, PR_TRUE, 1 }, + { "ABCDABC", "bc", 7, PR_TRUE, 1 }, + { "ABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 7, PR_TRUE, 0 }, + { "ABCDEFG", "abcdefg", 8, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "a", 12, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "c", 12, PR_TRUE, 2 }, + { "ABCDEFGABCDEFG", "e", 12, PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "g", 12, PR_TRUE, 6 }, + { "ABCDEFGABCDEFG", "i", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", 12, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "cd", 12, PR_TRUE, 2 }, + { "ABCDEFGABCDEFG", "ef", 12, PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "gh", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 5, PR_TRUE, 1 }, + { "ABCDABCABCDABC", "bc", 6, PR_TRUE, 1 }, + { "ABCDABCABCDABC", "bc", 7, PR_TRUE, 1 }, + { "ABCDEFGABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 7, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 8, PR_TRUE, 0 } + }; + + int i; + + printf("Test 029 (PL_strncasestr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strncasestr(array[i].str, array[i].sub, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncaserstr */ +PRBool test_030(void) +{ + static struct + { + const char *str; + const char *sub; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 12, PR_FALSE, 0 }, + { (const char *)0, "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, 12, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 2, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 3, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 4, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 5, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 11, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 12, PR_TRUE, 8 }, + { "blah-de-blah", "blah", 13, PR_TRUE, 8 }, + { "", "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", "", 12, PR_FALSE, 0 }, + { "abcdefg", "a", 5, PR_TRUE, 0 }, + { "abcdefg", "c", 5, PR_TRUE, 2 }, + { "abcdefg", "e", 5, PR_TRUE, 4 }, + { "abcdefg", "g", 5, PR_FALSE, 0 }, + { "abcdefg", "i", 5, PR_FALSE, 0 }, + { "abcdefg", "ab", 5, PR_TRUE, 0 }, + { "abcdefg", "cd", 5, PR_TRUE, 2 }, + { "abcdefg", "ef", 5, PR_FALSE, 0 }, + { "abcdefg", "gh", 5, PR_FALSE, 0 }, + { "abcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabc", "bc", 7, PR_TRUE, 5 }, + { "abcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", 12, PR_TRUE, 7 }, + { "abcdefgabcdefg", "c", 12, PR_TRUE, 9 }, + { "abcdefgabcdefg", "e", 12, PR_TRUE, 11 }, + { "abcdefgabcdefg", "g", 12, PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", 12, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", 12, PR_TRUE, 7 }, + { "abcdefgabcdefg", "cd", 12, PR_TRUE, 9 }, + { "abcdefgabcdefg", "ef", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", 12, PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", 12, PR_TRUE, 8 }, + { "abcdabcabcdabc", "bc", 13, PR_TRUE, 8 }, + { "abcdabcabcdabc", "bc", 14, PR_TRUE, 12 }, + { "abcdefgabcdefg", "abcdefg", 13, PR_TRUE, 0 }, + { "abcdefgabcdefg", "abcdefg", 14, PR_TRUE, 7 }, + { "abcdefgabcdefg", "abcdefg", 15, PR_TRUE, 7 }, + { "ABCDEFG", "a", 5, PR_TRUE, 0 }, + { "ABCDEFG", "c", 5, PR_TRUE, 2 }, + { "ABCDEFG", "e", 5, PR_TRUE, 4 }, + { "ABCDEFG", "g", 5, PR_FALSE, 0 }, + { "ABCDEFG", "i", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ab", 5, PR_TRUE, 0 }, + { "ABCDEFG", "cd", 5, PR_TRUE, 2 }, + { "ABCDEFG", "ef", 5, PR_FALSE, 0 }, + { "ABCDEFG", "gh", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 5, PR_TRUE, 1 }, + { "ABCDABC", "bc", 6, PR_TRUE, 1 }, + { "ABCDABC", "bc", 7, PR_TRUE, 5 }, + { "ABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 7, PR_TRUE, 0 }, + { "ABCDEFG", "abcdefg", 8, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "a", 12, PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "c", 12, PR_TRUE, 9 }, + { "ABCDEFGABCDEFG", "e", 12, PR_TRUE, 11 }, + { "ABCDEFGABCDEFG", "g", 12, PR_TRUE, 6 }, + { "ABCDEFGABCDEFG", "i", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", 12, PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "cd", 12, PR_TRUE, 9 }, + { "ABCDEFGABCDEFG", "ef", 12, PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "gh", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 12, PR_TRUE, 8 }, + { "ABCDABCABCDABC", "bc", 13, PR_TRUE, 8 }, + { "ABCDABCABCDABC", "bc", 14, PR_TRUE, 12 }, + { "ABCDEFGABCDEFG", "abcdefg", 13, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 14, PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "abcdefg", 15, PR_TRUE, 7 } + }; + + int i; + + printf("Test 030 (PL_strncaserstr)..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strncaserstr(array[i].str, array[i].sub, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strtok_r */ +PRBool test_031(void) +{ + static const char *tokens[] = { + "wtc", "relyea", "nelsonb", "jpierre", "nicolson", + "ian.mcgreer", "kirk.erickson", "sonja.mirtitsch", "mhein" + }; + + static const char *seps[] = { + ", ", ",", " ", "\t", ",,,", " ,", " ", " \t\t", "," + }; + + static const char s2[] = ", \t"; + + char string[ 1024 ]; + char *s1; + char *token; + char *lasts; + unsigned int i; + + printf("Test 031 (PL_strtok_r) ..."); fflush(stdout); + + /* Build the string. */ + string[0] = '\0'; + for( i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++ ) + { + PL_strcat(string, tokens[i]); + PL_strcat(string, seps[i]); + } + + /* Scan the string for tokens. */ + i = 0; + s1 = string; + while( (token = PL_strtok_r(s1, s2, &lasts)) != NULL) + { + if( PL_strcmp(token, tokens[i]) != 0 ) + { + printf("FAIL wrong token scanned\n"); + return PR_FALSE; + } + i++; + s1 = NULL; + } + if( i != sizeof(tokens)/sizeof(tokens[0]) ) + { + printf("FAIL wrong number of tokens scanned\n"); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +int +main +( + int argc, + char *argv[] +) +{ + printf("Testing the Portable Library string functions:\n"); + + if( 1 + && test_001() + && test_001() + && test_002() + && test_003() + && test_004() + && test_005() + && test_006() + && test_007() + && test_008() + && test_009() + && test_010() + && test_011() + && test_012() + && test_013() + && test_014() + && test_015() + && test_016() + && test_017() + && test_018() + && test_019() + && test_020() + && test_021() + && test_022() + && test_023() + && test_024() + && test_025() + && test_026() + && test_027() + && test_028() + && test_029() + && test_030() + && test_031() + ) + { + printf("Suite passed.\n"); + return 0; + } + else + { + printf("Suite failed.\n"); + return 1; + } + + /*NOTREACHED*/ +} diff --git a/nsprpub/pkg/Makefile.in b/nsprpub/pkg/Makefile.in new file mode 100644 index 00000000000..d181bf6ffc1 --- /dev/null +++ b/nsprpub/pkg/Makefile.in @@ -0,0 +1,61 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +DIRS = +ifeq ($(OS_TARGET),Linux) +DIRS = linux +endif +ifeq ($(OS_TARGET),SunOS) +DIRS = solaris +endif + +publish:: + +$(LOOP_OVER_DIRS) + +include $(topsrcdir)/config/rules.mk diff --git a/nsprpub/pkg/linux/Makefile.in b/nsprpub/pkg/linux/Makefile.in new file mode 100644 index 00000000000..5a91b052a22 --- /dev/null +++ b/nsprpub/pkg/linux/Makefile.in @@ -0,0 +1,111 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: Makefile.in,v 1.10 2005/11/18 21:50:20 christophe.ravel.bugs%sun.com Exp $" +# + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +NAME = sun-nspr +ifndef RPM_RELEASE +RPM_RELEASE = 1 +endif +TOPDIR = /usr/src/redhat +VERSION = `grep PR_VERSION $(dist_includedir)/prinit.h \ + | sed -e 's/"$$//' -e 's/.*"//' -e 's/ .*//'` + +SPECFILE = $(NAME).spec + +include $(MOD_DEPTH)/config/autoconf.mk + +# Force i386 for non 64 bit build +ifneq ($(USE_64),1) + RPMTARGET = "--target=i386" + RPMLIBDIR = lib +else + RPMLIBDIR = lib64 +endif + +publish: + $(MAKE) clean + mkdir -p SOURCES SRPMS RPMS BUILD + (cd $(dist_libdir) && tar cphf - libnspr4.so libplds4.so libplc4.so) \ + | (mkdir -p opt/sun/private/$(RPMLIBDIR) && cd opt/sun/private/$(RPMLIBDIR) && tar xvfBp -) + (cd $(dist_includedir) && tar cphf - .) \ + | (mkdir -p opt/sun/private/include/nspr && cd opt/sun/private/include/nspr && tar xvfBp -) + (cd opt/sun/private/include/nspr && \ + rm -rf md private obsolete/pralarm.h obsolete/probslet.h obsolete/prsem.h) + tar czvf SOURCES/$(NAME)-$(VERSION).tar.gz opt + echo "%define name $(NAME)" >$(SPECFILE) + echo "%define version $(VERSION)" >>$(SPECFILE) + echo "%define release $(RPM_RELEASE)" >>$(SPECFILE) + echo "%define buildroot `pwd`/$(NAME)-root" >>$(SPECFILE) + echo "%define _topdir `pwd`" >>$(SPECFILE) + echo "%define _unpackaged_files_terminate_build 0" >>$(SPECFILE) + cat $(srcdir)/$(NAME).spec >>$(SPECFILE) + echo "" >>$(SPECFILE) + echo "%files" >>$(SPECFILE) + echo "%defattr(-,root,root)" >>$(SPECFILE) + echo "%dir /opt" >>$(SPECFILE) + echo "%dir /opt/sun" >>$(SPECFILE) + echo "%dir /opt/sun/private" >>$(SPECFILE) + echo "%dir /opt/sun/private/$(RPMLIBDIR)" >>$(SPECFILE) + find opt \( -name "*.so" \) | sed -e "s-^-/-" >>$(SPECFILE) + echo "" >>$(SPECFILE) + echo "%files devel" >>$(SPECFILE) + echo "%defattr(-,root,root)" >>$(SPECFILE) + echo "%dir /opt" >>$(SPECFILE) + echo "%dir /opt/sun" >>$(SPECFILE) + echo "%dir /opt/sun/private" >>$(SPECFILE) + echo "%dir /opt/sun/private/include" >>$(SPECFILE) + echo "%dir /opt/sun/private/include/nspr" >>$(SPECFILE) + echo "%dir /opt/sun/private/include/nspr/obsolete" >>$(SPECFILE) + find opt -type f \( -name "*.h" \) \ + | sed -e "s-^-/-" >>$(SPECFILE) + rpmbuild $(RPMTARGET) -bb $(SPECFILE) + +clean: + rm -rf $(TOPDIR)/BUILD/$(NAME) + rm -rf SOURCES SRPMS RPMS BUILD + rm -rf RPMS SRPMS opt + rm -f $(NAME)-$(VERSION).tar.gz diff --git a/nsprpub/pkg/linux/sun-nspr.spec b/nsprpub/pkg/linux/sun-nspr.spec new file mode 100644 index 00000000000..f914736d97e --- /dev/null +++ b/nsprpub/pkg/linux/sun-nspr.spec @@ -0,0 +1,81 @@ +Summary: Netscape Portable Runtime +Name: %{name} +Vendor: Sun Microsystems, Inc. +Version: %{version} +Release: %{release} +Copyright: Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. Also under other license(s) as shown at the Description field. +Distribution: Sun Java(TM) Enterprise System +URL: http://www.sun.com +Group: System Environment/Base +Source: %{name}-%{version}.tar.gz +ExclusiveOS: Linux +BuildRoot: /var/tmp/%{name}-root + +%description + +NSPR provides platform independence for non-GUI operating system +facilities. These facilities include threads, thread synchronization, +normal file and network I/O, interval timing and calendar time, basic +memory management (malloc and free) and shared library linking. + +See: http://www.mozilla.org/projects/nspr/about-nspr.html + +***** BEGIN LICENSE BLOCK ***** +Version: MPL 1.1/GPL 2.0/LGPL 2.1 + +The contents of this file are subject to the Mozilla Public License Version +1.1 (the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the +License. + +The Original Code is the Netscape security libraries. + +The Initial Developer of the Original Code is +Netscape Communications Corporation. +Portions created by the Initial Developer are Copyright (C) 1994-2000 +the Initial Developer. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms of +either the GNU General Public License Version 2 or later (the "GPL"), or +the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +in which case the provisions of the GPL or the LGPL are applicable instead +of those above. If you wish to allow use of your version of this file only +under the terms of either the GPL or the LGPL, and not to allow others to +use your version of this file under the terms of the MPL, indicate your +decision by deleting the provisions above and replace them with the notice +and other provisions required by the GPL or the LGPL. If you do not delete +the provisions above, a recipient may use your version of this file under +the terms of any one of the MPL, the GPL or the LGPL. + +***** END LICENSE BLOCK ***** + +%package devel +Summary: Development Libraries for the Netscape Portable Runtime +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Header files for doing development with the Netscape Portable Runtime. + +Under "MPL/GPL" license. + +%prep +%setup -c + +%build + +%install +rm -rf $RPM_BUILD_ROOT +mkdir $RPM_BUILD_ROOT +cd $RPM_BUILD_ROOT +tar xvzf $RPM_SOURCE_DIR/%{name}-%{version}.tar.gz + +%clean +rm -rf $RPM_BUILD_ROOT diff --git a/nsprpub/pkg/solaris/Makefile-devl.com b/nsprpub/pkg/solaris/Makefile-devl.com new file mode 100755 index 00000000000..fa47f5b3d78 --- /dev/null +++ b/nsprpub/pkg/solaris/Makefile-devl.com @@ -0,0 +1,66 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: Makefile-devl.com,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# + +MACH = $(shell mach) + +PUBLISH_ROOT = $(DIST) +ifeq ($(MOD_DEPTH),../..) +ROOT = ROOT +else +ROOT = $(subst ../../,,$(MOD_DEPTH))/ROOT +endif + +PKGARCHIVE = $(dist_prefix)/pkgarchive +DATAFILES = copyright +FILES = $(DATAFILES) pkginfo + +PACKAGE = $(shell basename `pwd`) + +PRODUCT_VERSION = "$(MOD_VERSION).$(MOD_MINOR).$(MOD_PATCH)$(MOD_BETA)" +LN = /usr/bin/ln + +CLOBBERFILES = $(FILES) + +include $(topsrcdir)/config/rules.mk + +# vim: ft=make diff --git a/nsprpub/pkg/solaris/Makefile-devl.targ b/nsprpub/pkg/solaris/Makefile-devl.targ new file mode 100755 index 00000000000..da52e3ab870 --- /dev/null +++ b/nsprpub/pkg/solaris/Makefile-devl.targ @@ -0,0 +1,66 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: Makefile-devl.targ,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# + +include $(srcdir)/../proto64.mk + +pkginfo: pkginfo.tmpl ../awk_pkginfo + $(RM) $@; nawk -f ../awk_pkginfo $(srcdir)/$@.tmpl > $@ + +pkg: $(PKGARCHIVE) + cat $(srcdir)/prototype | sed $(sed_proto64) > prototype + cp $(srcdir)/depend . + pkgmk -f prototype -d $(PKGARCHIVE) -r $(ROOT) -o $(PACKAGE) + +$(PKGARCHIVE): + [ -d $(PKGARCHIVE) ] || mkdir -p $(PKGARCHIVE) + +$(DATAFILES): %: $(srcdir)/../common_files/% + $(RM) $@; cp $(srcdir)/../common_files/$@ $@ + +$(MACHDATAFILES): %: $(srcdir)/../common_files/%_$(MACH) + $(RM) $@; cp $(srcdir)/../common_files/$@_$(MACH) $@ + +clobber clean:: + -$(RM) $(CLOBBERFILES) $(CLEANFILES) + +.PHONY: pkg diff --git a/nsprpub/pkg/solaris/Makefile.com b/nsprpub/pkg/solaris/Makefile.com new file mode 100644 index 00000000000..32640abfe4f --- /dev/null +++ b/nsprpub/pkg/solaris/Makefile.com @@ -0,0 +1,69 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: Makefile.com,v 1.8 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# + +MACH = $(shell mach) + +PUBLISH_ROOT = $(DIST) +ifeq ($(MOD_DEPTH),../..) +ROOT = ROOT +else +ROOT = $(subst ../../,,$(MOD_DEPTH))/ROOT +endif + +PKGARCHIVE = $(dist_prefix)/pkgarchive +DATAFILES = copyright +FILES = $(DATAFILES) pkginfo + +PACKAGE = $(shell basename `pwd`) + +PRODUCT_VERSION = $(shell grep PR_VERSION $(dist_includedir)/prinit.h \ + | sed -e 's/"$$//' -e 's/.*"//' -e 's/ .*//') + +LN = /usr/bin/ln +CP = /usr/bin/cp + +CLOBBERFILES = $(FILES) + +include $(topsrcdir)/config/rules.mk + +# vim: ft=make diff --git a/nsprpub/pkg/solaris/Makefile.in b/nsprpub/pkg/solaris/Makefile.in new file mode 100644 index 00000000000..1fa7258661a --- /dev/null +++ b/nsprpub/pkg/solaris/Makefile.in @@ -0,0 +1,121 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: Makefile.in,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +abs_dist_libdir := $(shell (cd $(dist_libdir);pwd)) +abs_dist_includedir := $(shell (cd $(dist_includedir);pwd)) + +%: %.ksh + $(RM) $@ + cp $< $@ + chmod +x $@ + +DIRS = \ + SUNWpr \ + SUNWprd + +include $(srcdir)/Makefile.com + +PROTO = \ + $(ROOT) \ + $(ROOT)/usr/lib/mps \ + $(ROOT)/usr/include/mps + +ifeq ($(MACH), sparc) + PROTO += $(ROOT)/usr/lib/mps/cpu/sparcv8plus +endif + +ifeq ($(USE_64), 1) +ifeq ($(MACH), sparc) +# Sparc + PROTO += $(ROOT)/usr/lib/mps/sparcv9 +else +# AMD64 + PROTO += $(ROOT)/usr/lib/mps/amd64 +endif + abs_dist64_libdir = $(abs_dist_libdir) + abs_dist32_libdir = $(shell echo $(abs_dist_libdir) | sed -e "s|_64_OPT|_OPT|g" -e "s|_64_DBG|_DBG|g") + abs_dist64_includedir = $(abs_dist_includedir) + abs_dist32_includedir = $(shell echo $(abs_dist_includedir) | sed -e "s|_64_OPT|_OPT|g" -e "s|_64_DBG|_DBG|g") +else + abs_dist32_libdir = $(abs_dist_libdir) + abs_dist64_libdir = $(shell echo $(abs_dist_libdir) | sed -e "s|_OPT|_64_OPT|g" -e "s|_DBG|_64_DBG|g") + abs_dist32_includedir = $(abs_dist_includedir) + abs_dist64_includedir = $(shell echo $(abs_dist_includedir) | sed -e "s|_OPT|_64_OPT|g" -e "s|_DBG|_64_DBG|g") +endif + +awk_pkginfo: bld_awk_pkginfo + ./bld_awk_pkginfo -m $(MACH) -p "$(PRODUCT_VERSION)" -o $@ -v $(PRODUCT_VERSION) + +all:: awk_pkginfo $(PROTO) +publish: awk_pkginfo $(PROTO) + +$(LOOP_OVER_DIRS) + +clean clobber:: + $(RM) awk_pkginfo bld_awk_pkginfo + $(RM) -r $(ROOT) + +$(ROOT): + mkdir -p $@ + +$(ROOT)/usr/lib/mps/sparcv9: + mkdir -p $@ + $(CP) -r $(abs_dist64_libdir)/*.so $@ +$(ROOT)/usr/lib/mps/amd64: + mkdir -p $@ + $(CP) -r $(abs_dist64_libdir)/*.so $@ +$(ROOT)/usr/lib/mps: + mkdir -p $@ + $(CP) -r $(abs_dist32_libdir)/*.so $@ +$(ROOT)/usr/lib/mps/cpu/sparcv8plus: + mkdir -p $@ + $(CP) -r $(abs_dist32_libdir)/cpu/sparcv8plus/*.so $@ +$(ROOT)/usr/include/mps: + mkdir -p $@ + $(CP) -r $(abs_dist32_includedir)/* $@ diff --git a/nsprpub/pkg/solaris/Makefile.targ b/nsprpub/pkg/solaris/Makefile.targ new file mode 100644 index 00000000000..ca17a803d5d --- /dev/null +++ b/nsprpub/pkg/solaris/Makefile.targ @@ -0,0 +1,64 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: Makefile.targ,v 1.6 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# + +include $(srcdir)/../proto64.mk + +pkginfo: pkginfo.tmpl ../awk_pkginfo + $(RM) $@; nawk -f ../awk_pkginfo $< > $@ + +pkg: $(PKGARCHIVE) prototype_$(MACH) + cp $(srcdir)/prototype_com . + cat $(srcdir)/prototype_$(MACH) | sed $(sed_proto64) > prototype_$(MACH) + cp $(srcdir)/depend . + pkgmk -f prototype_$(MACH) -d $(PKGARCHIVE) -r $(ROOT) -o $(PACKAGE) + +$(PKGARCHIVE): + [ -d $(PKGARCHIVE) ] || mkdir -p $(PKGARCHIVE) + +$(DATAFILES): %: $(srcdir)/../common_files/% + $(RM) $@; cp $(srcdir)/../common_files/$@ $@ + +clobber clean:: + -$(RM) $(CLOBBERFILES) $(CLEANFILES) + +.PHONY: pkg diff --git a/nsprpub/pkg/solaris/SUNWpr/Makefile.in b/nsprpub/pkg/solaris/SUNWpr/Makefile.in new file mode 100644 index 00000000000..3cd5669d4f3 --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWpr/Makefile.in @@ -0,0 +1,58 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: Makefile.in,v 1.2 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(srcdir)/../Makefile.com + +DATAFILES += + +all:: $(FILES) +publish:: all pkg + +include $(srcdir)/../Makefile.targ diff --git a/nsprpub/pkg/solaris/SUNWpr/depend b/nsprpub/pkg/solaris/SUNWpr/depend new file mode 100644 index 00000000000..f5b1b705816 --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWpr/depend @@ -0,0 +1,64 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +# $Id: depend,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $ +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# see pkginfo(4), PKG parameter +# see pkginfo(4), NAME parameter +# see pkginfo(4), VERSION parameter +# see pkginfo(4), ARCH parameter +# +# () +# () +# ... +# +# ... + +P SUNWcar Core Architecture, (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries diff --git a/nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl b/nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl new file mode 100644 index 00000000000..96520510ef2 --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl @@ -0,0 +1,70 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: pkginfo.tmpl,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWpr" +NAME="Netscape Portable Runtime" +ARCH="ISA" +VERSION="NSPRVERS,REV=0.0.0" +SUNW_PRODNAME="Netscape Portable Runtime" +SUNW_PRODVERS="NSPRVERS" +SUNW_PKGTYPE="usr" +MAXINST="1000" +CATEGORY="system" +DESC="Netscape Portable Runtime Interface" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +#VSTOCK="" +#ISTATES="" +#RSTATES='' +#ULIMIT="" +#ORDER="" +#PSTAMP="" +#INTONLY="" diff --git a/nsprpub/pkg/solaris/SUNWpr/prototype_com b/nsprpub/pkg/solaris/SUNWpr/prototype_com new file mode 100644 index 00000000000..881fdb59ef6 --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWpr/prototype_com @@ -0,0 +1,71 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: prototype_com,v 1.4 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# packaging files +i copyright +i pkginfo +i depend +# +# source locations relative to the prototype file +# +# SUNWpr +# +d none usr 755 root sys +d none usr/lib 755 root bin +d none usr/lib/mps 755 root bin +d none usr/lib/mps/secv1 755 root bin +f none usr/lib/mps/libnspr4.so 755 root bin +f none usr/lib/mps/libplc4.so 755 root bin +f none usr/lib/mps/libplds4.so 755 root bin +s none usr/lib/mps/secv1/libnspr4.so=../libnspr4.so +s none usr/lib/mps/secv1/libplc4.so=../libplc4.so +s none usr/lib/mps/secv1/libplds4.so=../libplds4.so diff --git a/nsprpub/pkg/solaris/SUNWpr/prototype_i386 b/nsprpub/pkg/solaris/SUNWpr/prototype_i386 new file mode 100644 index 00000000000..9cbb7ed16e2 --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWpr/prototype_i386 @@ -0,0 +1,77 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: prototype_i386,v 1.4 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are i386 specific here +# +# source locations relative to the prototype file +# +# +# SUNWpr +# +#64#s none usr/lib/mps/64=amd64 +#64#s none usr/lib/mps/secv1/64=amd64 +#64#d none usr/lib/mps/amd64 755 root bin +#64#d none usr/lib/mps/secv1/amd64 755 root bin +#64#f none usr/lib/mps/amd64/libnspr4.so 755 root bin +#64#f none usr/lib/mps/amd64/libplc4.so 755 root bin +#64#f none usr/lib/mps/amd64/libplds4.so 755 root bin +#64#s none usr/lib/mps/secv1/amd64/libnspr4.so=../../amd64/libnspr4.so +#64#s none usr/lib/mps/secv1/amd64/libplc4.so=../../amd64/libplc4.so +#64#s none usr/lib/mps/secv1/amd64/libplds4.so=../../amd64/libplds4.so + diff --git a/nsprpub/pkg/solaris/SUNWpr/prototype_sparc b/nsprpub/pkg/solaris/SUNWpr/prototype_sparc new file mode 100644 index 00000000000..c141e6c89f9 --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWpr/prototype_sparc @@ -0,0 +1,83 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: prototype_sparc,v 1.4 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWpr +# +d none usr/lib/mps/cpu 755 root bin +d none usr/lib/mps/cpu/sparcv8plus 755 root bin +d none usr/lib/mps/secv1/cpu 755 root bin +d none usr/lib/mps/secv1/cpu/sparcv8plus 755 root bin +f none usr/lib/mps/cpu/sparcv8plus/libnspr_flt4.so 755 root bin +s none usr/lib/mps/secv1/cpu/sparcv8plus/libnspr_flt4.so=../../../cpu/sparcv8plus/libnspr_flt4.so +#64#s none usr/lib/mps/64=sparcv9 +#64#s none usr/lib/mps/secv1/64=sparcv9 +#64#d none usr/lib/mps/sparcv9 755 root bin +#64#d none usr/lib/mps/secv1/sparcv9 755 root bin +#64#f none usr/lib/mps/sparcv9/libnspr4.so 755 root bin +#64#f none usr/lib/mps/sparcv9/libplc4.so 755 root bin +#64#f none usr/lib/mps/sparcv9/libplds4.so 755 root bin +#64#s none usr/lib/mps/secv1/sparcv9/libnspr4.so=../../sparcv9/libnspr4.so +#64#s none usr/lib/mps/secv1/sparcv9/libplc4.so=../../sparcv9/libplc4.so +#64#s none usr/lib/mps/secv1/sparcv9/libplds4.so=../../sparcv9/libplds4.so + diff --git a/nsprpub/pkg/solaris/SUNWprd/Makefile.in b/nsprpub/pkg/solaris/SUNWprd/Makefile.in new file mode 100755 index 00000000000..3c6d0594c0e --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWprd/Makefile.in @@ -0,0 +1,58 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: Makefile.in,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(srcdir)/../Makefile-devl.com + +DATAFILES += + +all:: $(FILES) +publish:: all pkg + +include $(srcdir)/../Makefile-devl.targ diff --git a/nsprpub/pkg/solaris/SUNWprd/depend b/nsprpub/pkg/solaris/SUNWprd/depend new file mode 100755 index 00000000000..fee5a2a2849 --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWprd/depend @@ -0,0 +1,59 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +# $Id: depend,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $ +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# see pkginfo(4), PKG parameter +# see pkginfo(4), NAME parameter +# see pkginfo(4), VERSION parameter +# see pkginfo(4), ARCH parameter +# +# () +# () +# ... +# +# ... + +P SUNWpr Netscape Portable Runtime diff --git a/nsprpub/pkg/solaris/SUNWprd/pkginfo.tmpl b/nsprpub/pkg/solaris/SUNWprd/pkginfo.tmpl new file mode 100755 index 00000000000..6eea9fe876d --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWprd/pkginfo.tmpl @@ -0,0 +1,70 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: pkginfo.tmpl,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWprd" +NAME="Netscape Portable Runtime Development" +ARCH="ISA" +VERSION="NSPRVERS,REV=0.0.0" +SUNW_PRODNAME="Netscape Portable Runtime Development" +SUNW_PRODVERS="NSPRVERS" +SUNW_PKGTYPE="usr" +MAXINST="1000" +CATEGORY="system" +DESC="Netscape Portable Runtime Interface Files for Development" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +#VSTOCK="" +#ISTATES="" +#RSTATES='' +#ULIMIT="" +#ORDER="" +#PSTAMP="" +#INTONLY="" diff --git a/nsprpub/pkg/solaris/SUNWprd/prototype b/nsprpub/pkg/solaris/SUNWprd/prototype new file mode 100755 index 00000000000..ff3356e652c --- /dev/null +++ b/nsprpub/pkg/solaris/SUNWprd/prototype @@ -0,0 +1,115 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: prototype,v 1.4 2006/04/05 20:57:09 wtchang%redhat.com Exp $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# packaging files +i copyright +i pkginfo +i depend +# +# source locations relative to .h 0644 root bine prototype file +# +# SUNWprd +# +d none usr 0755 root sys +d none usr/include 0755 root bin +d none usr/include/mps 0755 root bin +d none usr/include/mps/obsolete 0755 root bin +f none usr/include/mps/obsolete/protypes.h 0644 root bin +f none usr/include/mps/prcpucfg.h 0644 root bin +f none usr/include/mps/nspr.h 0644 root bin +f none usr/include/mps/pratom.h 0644 root bin +f none usr/include/mps/prbit.h 0644 root bin +f none usr/include/mps/prclist.h 0644 root bin +f none usr/include/mps/prcmon.h 0644 root bin +f none usr/include/mps/prcountr.h 0644 root bin +f none usr/include/mps/prcvar.h 0644 root bin +f none usr/include/mps/prdtoa.h 0644 root bin +f none usr/include/mps/prenv.h 0644 root bin +f none usr/include/mps/prerr.h 0644 root bin +f none usr/include/mps/prerror.h 0644 root bin +f none usr/include/mps/prinet.h 0644 root bin +f none usr/include/mps/prinit.h 0644 root bin +f none usr/include/mps/prinrval.h 0644 root bin +f none usr/include/mps/prio.h 0644 root bin +f none usr/include/mps/pripcsem.h 0644 root bin +f none usr/include/mps/prlink.h 0644 root bin +f none usr/include/mps/prlock.h 0644 root bin +f none usr/include/mps/prlog.h 0644 root bin +f none usr/include/mps/prlong.h 0644 root bin +f none usr/include/mps/prmem.h 0644 root bin +f none usr/include/mps/prmon.h 0644 root bin +f none usr/include/mps/prmwait.h 0644 root bin +f none usr/include/mps/prnetdb.h 0644 root bin +f none usr/include/mps/prolock.h 0644 root bin +f none usr/include/mps/prpdce.h 0644 root bin +f none usr/include/mps/prprf.h 0644 root bin +f none usr/include/mps/prproces.h 0644 root bin +f none usr/include/mps/prrng.h 0644 root bin +f none usr/include/mps/prrwlock.h 0644 root bin +f none usr/include/mps/prshm.h 0644 root bin +f none usr/include/mps/prshma.h 0644 root bin +f none usr/include/mps/prsystem.h 0644 root bin +f none usr/include/mps/prthread.h 0644 root bin +f none usr/include/mps/prtime.h 0644 root bin +f none usr/include/mps/prtpool.h 0644 root bin +f none usr/include/mps/prtrace.h 0644 root bin +f none usr/include/mps/prtypes.h 0644 root bin +f none usr/include/mps/prvrsion.h 0644 root bin +f none usr/include/mps/prwin16.h 0644 root bin +f none usr/include/mps/plarenas.h 0644 root bin +f none usr/include/mps/plarena.h 0644 root bin +f none usr/include/mps/plbase64.h 0644 root bin +f none usr/include/mps/plerror.h 0644 root bin +f none usr/include/mps/plgetopt.h 0644 root bin +f none usr/include/mps/plhash.h 0644 root bin +f none usr/include/mps/plresolv.h 0644 root bin +f none usr/include/mps/plstr.h 0644 root bin diff --git a/nsprpub/pkg/solaris/bld_awk_pkginfo.ksh b/nsprpub/pkg/solaris/bld_awk_pkginfo.ksh new file mode 100644 index 00000000000..11063c8eb24 --- /dev/null +++ b/nsprpub/pkg/solaris/bld_awk_pkginfo.ksh @@ -0,0 +1,141 @@ +#!/usr/bin/ksh -p +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: bld_awk_pkginfo.ksh,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# +# Simple script which builds the awk_pkginfo awk script. This awk script +# is used to convert the pkginfo.tmpl files into pkginfo files +# for the build. +# + +usage() +{ + cat <<-EOF +usage: bld_awk_pkginfo -p -m -o [-v ] +EOF +} + +# +# Awk strings +# +# two VERSION patterns: one for Dewey decimal, one for Dewey plus ,REV=n +# the first has one '=' the second has two or more '=' +# +VERSION1="VERSION=[^=]*$" +VERSION2="VERSION=[^=]*=.*$" +PRODVERS="^SUNW_PRODVERS=" +ARCH='ARCH=\"ISA\"' + +# +# parse command line +# +mach="" +prodver="" +awk_script="" +version="NSPRVERS" + +while getopts o:p:m:v: c +do + case $c in + o) + awk_script=$OPTARG + ;; + m) + mach=$OPTARG + ;; + p) + prodver=$OPTARG + ;; + v) + version=$OPTARG + ;; + \?) + usage + exit 1 + ;; + esac +done + +if [[ ( -z $prodver ) || ( -z $mach ) || ( -z $awk_script ) ]] +then + usage + exit 1 +fi + +if [[ -f $awk_script ]] +then + rm -f $awk_script +fi + +# +# Build REV= field based on date +# +rev=$(date "+%Y.%m.%d.%H.%M") + +# +# Build awk script which will process all the +# pkginfo.tmpl files. +# +# the first VERSION pattern is replaced with a leading quotation mark +# +rm -f $awk_script +cat << EOF > $awk_script +/$VERSION1/ { + sub(/\=[^=]*$/,"=\"$rev\"") + print + next + } +/$VERSION2/ { + sub(/\=[^=]*$/,"=$rev\"") + sub(/NSPRVERS/,"$version") + print + next + } +/$PRODVERS/ { + printf "SUNW_PRODVERS=\"%s\"\n", "$prodver" + next + } +/$ARCH/ { + printf "ARCH=\"%s\"\n", "$mach" + next + } +{ print } +EOF diff --git a/nsprpub/pkg/solaris/common_files/copyright b/nsprpub/pkg/solaris/common_files/copyright new file mode 100644 index 00000000000..988939bb182 --- /dev/null +++ b/nsprpub/pkg/solaris/common_files/copyright @@ -0,0 +1,38 @@ +Copyright 2005 Sun Microsystems, Inc. All rights reserved. +Use is subject to license terms. + +***** BEGIN LICENSE BLOCK ***** +Version: MPL 1.1/GPL 2.0/LGPL 2.1 + +The contents of this package are subject to the Mozilla Public License Version +1.1 (the "License"); you may not use this package except in compliance with +the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the +License. + +The Original Code is the Netscape Portable Runtime (NSPR). + +The Initial Developer of the Original Code is +Netscape Communications Corporation. +Portions created by the Initial Developer are Copyright (C) 1998-2000 +the Initial Developer. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms of +either the GNU General Public License Version 2 or later (the "GPL"), or +the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +in which case the provisions of the GPL or the LGPL are applicable instead +of those above. If you wish to allow use of your version of this file only +under the terms of either the GPL or the LGPL, and not to allow others to +use your version of this file under the terms of the MPL, indicate your +decision by deleting the provisions above and replace them with the notice +and other provisions required by the GPL or the LGPL. If you do not delete +the provisions above, a recipient may use your version of this file under +the terms of any one of the MPL, the GPL or the LGPL. + +***** END LICENSE BLOCK ***** diff --git a/nsprpub/pkg/solaris/proto64.mk b/nsprpub/pkg/solaris/proto64.mk new file mode 100644 index 00000000000..c14dc098dee --- /dev/null +++ b/nsprpub/pkg/solaris/proto64.mk @@ -0,0 +1,50 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# +#ident "$Id: proto64.mk,v 1.3 2005/02/25 20:20:52 christophe.ravel.bugs%sun.com Exp $" +# + +ifeq ($(USE_64), 1) + # Remove 64 tag + sed_proto64='s/\#64\#//g' +else + # Strip 64 lines + sed_proto64='/\#64\#/d' +endif diff --git a/nsprpub/pr/.cvsignore b/nsprpub/pr/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/Makefile.in b/nsprpub/pr/Makefile.in new file mode 100644 index 00000000000..e060f195741 --- /dev/null +++ b/nsprpub/pr/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +DIRS = include src + +include $(topsrcdir)/config/rules.mk diff --git a/nsprpub/pr/include/.cvsignore b/nsprpub/pr/include/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/include/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/include/MANIFEST b/nsprpub/pr/include/MANIFEST new file mode 100644 index 00000000000..634968effd8 --- /dev/null +++ b/nsprpub/pr/include/MANIFEST @@ -0,0 +1,52 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +nspr.h +pratom.h +prbit.h +prclist.h +prcmon.h +prcountr.h +prcvar.h +prdtoa.h +prenv.h +prerr.h +prerror.h +prinet.h +prinit.h +prinrval.h +prio.h +pripcsem.h +prlink.h +prlock.h +prlog.h +prlong.h +prmem.h +prmon.h +prmwait.h +prnetdb.h +prolock.h +prpdce.h +prprf.h +prproces.h +prrng.h +prrwlock.h +prshm.h +prshma.h +prsystem.h +prthread.h +prtime.h +prtpool.h +prtrace.h +prtypes.h +prvrsion.h +prwin16.h + +obsolete/protypes.h +obsolete/prsem.h +obsolete/probslet.h + +private/prpriv.h +private/pprio.h +private/pprthred.h diff --git a/nsprpub/pr/include/Makefile.in b/nsprpub/pr/include/Makefile.in new file mode 100644 index 00000000000..5dc9686deeb --- /dev/null +++ b/nsprpub/pr/include/Makefile.in @@ -0,0 +1,59 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +DIRS = md private obsolete + +include $(topsrcdir)/config/config.mk + +HEADERS = $(wildcard $(srcdir)/*.h) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) + +include $(topsrcdir)/config/rules.mk + +export:: $(RELEASE_HEADERS) + $(INSTALL) -m 444 $(RELEASE_HEADERS) $(dist_includedir) diff --git a/nsprpub/pr/include/gencfg.c b/nsprpub/pr/include/gencfg.c new file mode 100644 index 00000000000..e67c13098d4 --- /dev/null +++ b/nsprpub/pr/include/gencfg.c @@ -0,0 +1,309 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#if defined(sgi) +#ifndef IRIX + error - IRIX is not defined +#endif +#endif + +#if defined(__sun) +#if defined(__svr4) || defined(__svr4__) || defined(__SVR4) +#ifndef SOLARIS + error - SOLARIS is not defined +#endif +#else +#ifndef SUNOS4 + error - SUNOS4 is not defined +#endif +#endif +#endif + +#if defined(__hpux) +#ifndef HPUX + error - HPUX is not defined +#endif +#endif + +#if defined(__alpha) +#if !(defined(_WIN32)) && !(defined(OSF1)) && !(defined(__linux)) && !(defined(__FreeBSD__)) + error - None of OSF1, _WIN32, __linux, or __FreeBSD__ is defined +#endif +#endif + +#if defined(_IBMR2) +#ifndef AIX + error - AIX is not defined +#endif +#endif + +#if defined(linux) +#ifndef LINUX + error - LINUX is not defined +#endif +#endif + +#if defined(bsdi) +#ifndef BSDI + error - BSDI is not defined +#endif +#endif + +#if defined(M_UNIX) +#ifndef SCO + error - SCO is not defined +#endif +#endif +#if !defined(M_UNIX) && defined(_USLC_) +#ifndef UNIXWARE + error - UNIXWARE is not defined +#endif +#endif + +#if defined(__APPLE__) +#ifndef DARWIN + error - DARWIN is not defined +#endif +#endif + +#if defined(__NeXT__) +#ifndef NEXTSTEP + error - NEXTSTEP is not defined +#endif +#endif + +/************************************************************************/ + +/* Generate cpucfg.h */ + +#ifdef XP_PC +#ifdef WIN32 +#define INT64 _PRInt64 +#else +#define INT64 long +#endif +#else +#if defined(HPUX) || defined(NECSVR4) || defined(SCO) || defined(UNIXWARE) || defined (NCR) +#define INT64 long +#else +#define INT64 long long +#endif +#endif + +struct align_short { + char c; + short a; +}; +struct align_int { + char c; + int a; +}; +struct align_long { + char c; + long a; +}; +struct align_PRInt64 { + char c; + INT64 a; +}; +struct align_fakelonglong { + char c; + struct { + long hi, lo; + } a; +}; +struct align_float { + char c; + float a; +}; +struct align_double { + char c; + double a; +}; +struct align_pointer { + char c; + void *a; +}; + +#define ALIGN_OF(type) \ + (((char*)&(((struct align_##type *)0)->a)) - ((char*)0)) + +int bpb; + +/* Used if shell doesn't support redirection. By default, assume it does. */ +FILE *stream; + +static int Log2(int n) +{ + int log2 = 0; + + if (n & (n-1)) + log2++; + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; +} + +/* We assume that int's are 32 bits */ +static void do64(void) +{ + union { + int i; + char c[4]; + } u; + + u.i = 0x01020304; + if (u.c[0] == 0x01) { + fprintf(stream, "#undef IS_LITTLE_ENDIAN\n"); + fprintf(stream, "#define IS_BIG_ENDIAN 1\n\n"); + } else { + fprintf(stream, "#define IS_LITTLE_ENDIAN 1\n"); + fprintf(stream, "#undef IS_BIG_ENDIAN\n\n"); + } +} + +static void do32(void) +{ + union { + long i; + char c[4]; + } u; + + u.i = 0x01020304; + if (u.c[0] == 0x01) { + fprintf(stream, "#undef IS_LITTLE_ENDIAN\n"); + fprintf(stream, "#define IS_BIG_ENDIAN 1\n\n"); + } else { + fprintf(stream, "#define IS_LITTLE_ENDIAN 1\n"); + fprintf(stream, "#undef IS_BIG_ENDIAN\n\n"); + } +} + +/* +** Concievably this could actually be used; but there is lots of code out +** there with and's and shift's in it that assumes a byte is 8 bits, so +** forget about porting THIS code to those non 8 bit byte machines. +*/ +static void BitsPerByte(void) +{ + bpb = 8; +} + +int main(int argc, char **argv) +{ + BitsPerByte(); + + /* If we got a command line argument, try to use it as the stream. */ + ++argv; + if(*argv) { + if(!(stream = fopen ( *argv, "wt" ))) { + fprintf(stderr, "Could not write to output file %s.\n", *argv); + return 1; + } + } else { + stream = stdout; + } + + fprintf(stream, "#ifndef nspr_cpucfg___\n"); + fprintf(stream, "#define nspr_cpucfg___\n\n"); + + fprintf(stream, "/* AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n"); + + if (sizeof(long) == 8) { + do64(); + } else { + do32(); + } + fprintf(stream, "#define PR_BYTES_PER_BYTE %d\n", sizeof(char)); + fprintf(stream, "#define PR_BYTES_PER_SHORT %d\n", sizeof(short)); + fprintf(stream, "#define PR_BYTES_PER_INT %d\n", sizeof(int)); + fprintf(stream, "#define PR_BYTES_PER_INT64 %d\n", 8); + fprintf(stream, "#define PR_BYTES_PER_LONG %d\n", sizeof(long)); + fprintf(stream, "#define PR_BYTES_PER_FLOAT %d\n", sizeof(float)); + fprintf(stream, "#define PR_BYTES_PER_DOUBLE %d\n\n", sizeof(double)); + + fprintf(stream, "#define PR_BITS_PER_BYTE %d\n", bpb); + fprintf(stream, "#define PR_BITS_PER_SHORT %d\n", bpb * sizeof(short)); + fprintf(stream, "#define PR_BITS_PER_INT %d\n", bpb * sizeof(int)); + fprintf(stream, "#define PR_BITS_PER_INT64 %d\n", bpb * 8); + fprintf(stream, "#define PR_BITS_PER_LONG %d\n", bpb * sizeof(long)); + fprintf(stream, "#define PR_BITS_PER_FLOAT %d\n", bpb * sizeof(float)); + fprintf(stream, "#define PR_BITS_PER_DOUBLE %d\n\n", + bpb * sizeof(double)); + + fprintf(stream, "#define PR_BITS_PER_BYTE_LOG2 %d\n", Log2(bpb)); + fprintf(stream, "#define PR_BITS_PER_SHORT_LOG2 %d\n", + Log2(bpb * sizeof(short))); + fprintf(stream, "#define PR_BITS_PER_INT_LOG2 %d\n", + Log2(bpb * sizeof(int))); + fprintf(stream, "#define PR_BITS_PER_INT64_LOG2 %d\n", 6); + fprintf(stream, "#define PR_BITS_PER_LONG_LOG2 %d\n", + Log2(bpb * sizeof(long))); + fprintf(stream, "#define PR_BITS_PER_FLOAT_LOG2 %d\n", + Log2(bpb * sizeof(float))); + fprintf(stream, "#define PR_BITS_PER_DOUBLE_LOG2 %d\n\n", + Log2(bpb * sizeof(double))); + + fprintf(stream, "#define PR_ALIGN_OF_SHORT %d\n", ALIGN_OF(short)); + fprintf(stream, "#define PR_ALIGN_OF_INT %d\n", ALIGN_OF(int)); + fprintf(stream, "#define PR_ALIGN_OF_LONG %d\n", ALIGN_OF(long)); + if (sizeof(INT64) < 8) { + /* this machine doesn't actually support PRInt64's */ + fprintf(stream, "#define PR_ALIGN_OF_INT64 %d\n", + ALIGN_OF(fakelonglong)); + } else { + fprintf(stream, "#define PR_ALIGN_OF_INT64 %d\n", ALIGN_OF(PRInt64)); + } + fprintf(stream, "#define PR_ALIGN_OF_FLOAT %d\n", ALIGN_OF(float)); + fprintf(stream, "#define PR_ALIGN_OF_DOUBLE %d\n", ALIGN_OF(double)); + fprintf(stream, "#define PR_ALIGN_OF_POINTER %d\n\n", ALIGN_OF(pointer)); + + fprintf(stream, "#endif /* nspr_cpucfg___ */\n"); + fclose(stream); + + return 0; +} diff --git a/nsprpub/pr/include/md/.cvsignore b/nsprpub/pr/include/md/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/include/md/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/include/md/Makefile.in b/nsprpub/pr/include/md/Makefile.in new file mode 100644 index 00000000000..24a0a9b87bc --- /dev/null +++ b/nsprpub/pr/include/md/Makefile.in @@ -0,0 +1,90 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +# The .cfg files need to be exported and installed to support +# cross-compilation. +CONFIGS = $(wildcard $(srcdir)/*.cfg) + +include $(topsrcdir)/config/rules.mk + +export:: $(MDCPUCFG_H) + $(INSTALL) -m 444 $(CONFIGS) $(dist_includedir)/md + $(INSTALL) -m 444 $(srcdir)/$(MDCPUCFG_H) $(dist_includedir) +ifeq ($(OS_ARCH),OpenVMS) +# On OpenVMS mv updates the file's modified time, so we create a hard link. + cd $(dist_includedir); \ + if test ! -f prcpucfg.h; then \ + dcl set file /enter=prcpucfg.h $(MDCPUCFG_H); \ + fi +else + mv -f $(dist_includedir)/$(MDCPUCFG_H) $(dist_includedir)/prcpucfg.h +endif + +install:: + $(NSINSTALL) -D $(DESTDIR)$(includedir)/md + $(NSINSTALL) -t -m 644 $(CONFIGS) $(DESTDIR)$(includedir)/md + $(NSINSTALL) -t -m 644 $(srcdir)/$(MDCPUCFG_H) $(DESTDIR)$(includedir) +ifeq ($(OS_ARCH),OpenVMS) +# On OpenVMS mv updates the file's modified time, so we create a hard link. + cd $(DESTDIR)$(includedir); \ + if test ! -f prcpucfg.h; then \ + dcl set file /enter=prcpucfg.h $(MDCPUCFG_H); \ + fi +else + mv -f $(DESTDIR)$(includedir)/$(MDCPUCFG_H) $(DESTDIR)$(includedir)/prcpucfg.h +endif + +release:: export + @echo "Copying machine-dependent prcpucfg.h" + @if test -z "$(BUILD_NUMBER)"; then \ + echo "BUILD_NUMBER must be defined"; \ + false; \ + fi + @if test ! -d $(RELEASE_INCLUDE_DIR); then \ + rm -rf $(RELEASE_INCLUDE_DIR); \ + $(NSINSTALL) -D $(RELEASE_INCLUDE_DIR);\ + fi + cp $(srcdir)/$(MDCPUCFG_H) $(RELEASE_INCLUDE_DIR)/prcpucfg.h diff --git a/nsprpub/pr/include/md/_aix.h b/nsprpub/pr/include/md/_aix.h new file mode 100644 index 00000000000..855cb247b35 --- /dev/null +++ b/nsprpub/pr/include/md/_aix.h @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_aix_defs_h___ +#define nspr_aix_defs_h___ + +#include +#if defined(_PR_PTHREADS) || defined(PTHREADS_USER) +#include +#endif + +/* + * To pick up fd_set and the poll events. + */ +#include +#include + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "aix" +#define _PR_SI_SYSNAME "AIX" +#define _PR_SI_ARCHITECTURE "rs6000" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE (2*65536L) +#define _MD_MINIMUM_STACK_SIZE (2*65536L) +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define NEED_TIME_R +#undef HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#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 +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#endif +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY +#define _PR_ACCEPT_INHERIT_NONBLOCK + +/* Timer operations */ +#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) */ + +#ifdef AIX_HAVE_ATOMIC_OP_H +/* The atomic operations */ +#include +#define _PR_HAVE_ATOMIC_OPS +#ifndef IS_64 +#define _PR_HAVE_ATOMIC_CAS +#endif +#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) +#endif /* AIX_HAVE_ATOMIC_OP_H */ + +#define USE_SETJMP + +#include + +#define _MD_GET_SP(_t) (_t)->md.jb[3] +#define _MD_SET_THR_SP(_t, _sp) ((_t)->md.jb[3] = (int) (_sp - 2 * 64)) +#define PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.jb) +#define SAVE_CONTEXT(_th) _setjmp(CONTEXT(_th)) +#define GOTO_CONTEXT(_th) _longjmp(CONTEXT(_th), 1) + +#ifdef PTHREADS_USER +#include "_nspr_pthread.h" +#else + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + (*_main)(); \ + } \ + _MD_GET_SP(_thread) = (int) (_sp - 2 * 64); \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_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); \ + longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + jmp_buf jb; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +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; +}; + +#if !defined(_PR_PTHREADS) +#define _MD_INIT_LOCKS() +#endif + +#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_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) +#endif /* PTHREADS_USER */ + +#ifdef AIX_RENAME_SELECT +#define _MD_SELECT select +#define _MD_POLL poll +#endif + +extern void _MD_aix_map_sendfile_error(int err); + +#endif /* nspr_aix_defs_h___ */ diff --git a/nsprpub/pr/include/md/_aix32.cfg b/nsprpub/pr/include/md/_aix32.cfg new file mode 100644 index 00000000000..6b75e4f64ad --- /dev/null +++ b/nsprpub/pr/include/md/_aix32.cfg @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef AIX +#define AIX +#endif + +#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_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 4 +#define PR_ALIGN_OF_POINTER 4 + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#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 + +/* used by protypes.h only */ +#define _PR_AIX_HAVE_BSD_INT_TYPES + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ diff --git a/nsprpub/pr/include/md/_aix64.cfg b/nsprpub/pr/include/md/_aix64.cfg new file mode 100644 index 00000000000..8b500ab0265 --- /dev/null +++ b/nsprpub/pr/include/md/_aix64.cfg @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef AIX +#define AIX +#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 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 8 + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#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 + +/* used by protypes.h only */ +#define _PR_AIX_HAVE_BSD_INT_TYPES + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ diff --git a/nsprpub/pr/include/md/_beos.cfg b/nsprpub/pr/include/md/_beos.cfg new file mode 100644 index 00000000000..557252f37a2 --- /dev/null +++ b/nsprpub/pr/include/md/_beos.cfg @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_BEOS +#define XP_BEOS +#undef XP_UNIX +#endif + +#ifndef BEOS +#define BEOS +#endif + +#define PR_AF_INET6 5 /* same as AF_INET6 */ + +#ifdef __powerpc__ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#else +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#endif + +#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 + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +/* + * XXX These two macros need to be investigated for different architectures. + */ +#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/nsprpub/pr/include/md/_beos.h b/nsprpub/pr/include/md/_beos.h new file mode 100644 index 00000000000..38dd5fb8a45 --- /dev/null +++ b/nsprpub/pr/include/md/_beos.h @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_beos_defs_h___ +#define nspr_beos_defs_h___ + +#include "prtypes.h" +#include "prio.h" +#include "prthread.h" +#include "prproces.h" +#include "prmem.h" +#include "obsolete/prsem.h" +#include + +#include +#include +#include + +/* + * Internal configuration macros + */ + +#ifdef BONE_VERSION +#define _PR_HAVE_SOCKADDR_LEN +#endif + +#define PR_LINKER_ARCH "beos" +#define _PR_SI_SYSNAME "BEOS" +#ifdef __powerpc__ +#define _PR_SI_ARCHITECTURE "ppc" +#else +#define _PR_SI_ARCHITECTURE "x86" +#endif +#define PR_DLL_SUFFIX ".so" + +#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 _PR_NO_CLOCK_TIMER + +/* + * The Atomic operations + */ + +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC _MD_AtomicInit +#define _MD_ATOMIC_INCREMENT _MD_AtomicIncrement +#define _MD_ATOMIC_ADD _MD_AtomicAdd +#define _MD_ATOMIC_DECREMENT _MD_AtomicDecrement +#define _MD_ATOMIC_SET _MD_AtomicSet + +#define HAVE_CVAR_BUILT_ON_SEM +#define _PR_GLOBAL_THREADS_ONLY +#define _PR_BTHREADS +#define _PR_NEED_FAKE_POLL +#define _PR_HAVE_PEEK_BUFFER +#define _PR_PEEK_BUFFER_MAX (16 * 1024) +#define _PR_FD_NEED_EMULATE_MSG_PEEK(fd) 1 +#define _PR_CONNECT_DOES_NOT_BIND +#define _PR_HAVE_O_APPEND + +/* Define threading functions and objects as native BeOS */ +struct _MDThread { + thread_id tid; /* BeOS thread handle */ + sem_id joinSem; /* sems used to synchronzie joining */ + PRBool is_joining; /* TRUE if someone is currently waiting to + join this thread */ +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +/* + * Lock and Semaphore related definitions + */ + +struct _MDLock { + sem_id semaphoreID; + int32 benaphoreCount; +}; + +struct _MDCVar { + sem_id sem1; + sem_id sem2; + int16 count; +}; + +struct _MDSemaphore { + sem_id sid; +}; + +/* +** CPU-related definitions +*/ +struct _MDCPU { + int8 unused; +}; + +/* +** Process-related definitions +*/ +struct _MDProcess { + pid_t pid; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* +** File- and directory-related definitions +*/ + +#ifndef BONE_VERSION +#define BE_SOCK_SHUTDOWN_READ 0x01 +#define BE_SOCK_SHUTDOWN_WRITE 0x02 +#endif + +struct _MDFileDesc { + PRInt32 osfd; + PRInt32 sock_state; + PRBool accepted_socket; + PRNetAddr peer_addr; +#ifndef BONE_VERSION + PRBool connectValueValid; + int connectReturnValue; + int connectReturnError; +#endif +}; + +struct _MDDir { + DIR *d; +}; + +#define PR_DIRECTORY_SEPARATOR '/' +#define PR_DIRECTORY_SEPARATOR_STR "/" +#define PR_PATH_SEPARATOR ':' +#define PR_PATH_SEPARATOR_STR ":" + +#define GETTIMEOFDAY(tp) gettimeofday((tp), NULL) + +/* --- Memory-mapped files stuff --- not implemented on BeOS */ + +struct _MDFileMap { + PRInt8 unused; +}; + +/* + * Network related definitions. + */ + +#ifndef BONE_VERSION +#define IPPROTO_IP 0 +#define AF_UNIX 2 +#define TCP_NODELAY SO_NONBLOCK +#define SO_LINGER -1 +#define SO_ERROR 4 +#endif + +#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 + +#ifndef BONE_VERSION +/* these aren't actually used. if they are, we're screwed */ +struct protoent { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + int p_proto; /* protocol # */ +}; + +struct protoent* getprotobyname(const char* name); +struct protoent* getprotobynumber(int number); +#endif + +/* + * malloc() related definitions. + */ + +#undef _PR_OVERRIDE_MALLOC + +/* Miscellaneous */ + +#define _MD_ERRNO() (errno) + +#define _MD_CLEANUP_BEFORE_EXIT _MD_cleanup_before_exit +#define _MD_EXIT _MD_exit + +#define _MD_GET_ENV getenv +#define _MD_PUT_ENV putenv + +#define _MD_EARLY_INIT _MD_early_init +#define _MD_FINAL_INIT _MD_final_init + +/* CPU Stuff */ + +#define _MD_INIT_CPUS _MD_init_cpus +#define _MD_WAKEUP_CPUS _MD_wakeup_cpus +#define _MD_START_INTERRUPTS _MD_start_interrupts +#define _MD_STOP_INTERRUPTS _MD_stop_interrupts +#define _MD_DISABLE_CLOCK_INTERRUPTS _MD_disable_clock_interrupts +#define _MD_BLOCK_CLOCK_INTERRUPTS _MD_block_clock_interrupts +#define _MD_UNBLOCK_CLOCK_INTERRUPTS _MD_unblock_clock_interrupts +#define _MD_CLOCK_INTERRUPT _MD_clock_interrupt +#define _MD_INIT_STACK _MD_init_stack +#define _MD_CLEAR_STACK _MD_clear_stack +// #define _MD_GET_INTSOFF _MD_get_intsoff +// #define _MD_SET_INTSOFF _MD_set_intsoff +#define _MD_CURRENT_CPU _MD_current_cpu +#define _MD_SET_CURRENT_CPU _MD_set_current_cpu +#define _MD_INIT_RUNNING_CPU _MD_init_running_cpu +#define _MD_PAUSE_CPU _MD_pause_cpu + +/* Thread stuff */ + +#define _MD_CURRENT_THREAD() PR_GetCurrentThread() +// #define _MD_GET_ATTACHED_THREAD _MD_get_attached_thread +#define _MD_LAST_THREAD _MD_last_thread +#define _MD_SET_CURRENT_THREAD _MD_set_current_THREAD +#define _MD_SET_LAST_THREAD _MD_set_last_thread +#define _MD_INIT_THREAD _MD_init_thread +#define _MD_EXIT_THREAD _MD_exit_thread +#define _MD_INIT_ATTACHED_THREAD _MD_init_attached_thread + +#define _MD_SUSPEND_THREAD _MD_suspend_thread +#define _MD_RESUME_THREAD _MD_resume_thread +#define _MD_SUSPEND_CPU _MD_suspend_cpu +#define _MD_RESUME_CPU _MD_resume_cpu +#define _MD_BEGIN_SUSPEND_ALL _MD_begin_suspend_all +#define _MD_END_SUSPEND_ALL _MD_end_suspend_all +#define _MD_BEGIN_RESUME_ALL _MD_begin_resume_all +#define _MD_END_RESUME_ALL _MD_end_resume_all + +#define _MD_GET_SP _MD_get_sp + +#define _MD_CLEAN_THREAD _MD_clean_thread +#define _MD_CREATE_PRIMORDIAL_USER_THREAD _MD_create_primordial_user_thread +#define _MD_CREATE_USER_THREAD _MD_create_user_thread +#define _MD_INIT_PRIMORDIAL_THREAD _MD_init_primordial_thread +#define _MD_CREATE_THREAD _MD_create_thread +#define _MD_YIELD _MD_yield +#define _MD_SET_PRIORITY _MD_set_priority + +#define _MD_SUSPENDALL _MD_suspendall +#define _MD_RESUMEALL _MD_resumeall + +#define _MD_SWITCH_CONTEXT _MD_switch_context +#define _MD_RESTORE_CONTEXT _MD_restore_context + +#define _MD_WAIT _MD_wait +#define _MD_WAKEUP_WAITER _MD_wakeup_waiter + +#define _MD_SETTHREADAFFINITYMASK _MD_setthreadaffinitymask +#define _MD_GETTHREADAFFINITYMASK _MD_getthreadaffinitymask + +/* Thread Synchronization */ + +#define _MD_INIT_LOCKS _MD_init_locks +#define _MD_NEW_LOCK _MD_new_lock +#define _MD_FREE_LOCK _MD_free_lock +#define _MD_LOCK _MD_lock +#define _MD_TEST_AND_LOCK _MD_test_and_lock +#define _MD_UNLOCK _MD_unlock +#define _MD_IOQ_LOCK _MD_ioq_lock +#define _MD_IOQ_UNLOCK _MD_ioq_unlock +#define _MD_NEW_SEM _MD_new_sem +#define _MD_DESTROY_SEM _MD_destroy_sem +#define _MD_TIMED_WAIT_SEM _MD_timed_wait_sem +#define _MD_WAIT_SEM _MD_wait_sem +#define _MD_POST_SEM _MD_post_sem +// #define _MD_NEW_CV _MD_new_cv +// #define _MD_FREE_CV _MD_free_cv +// #define _MD_WAIT_CV _MD_wait_cv +// #define _MD_NOTIFY_CV _MD_notify_cv +// #define _MD_NOTIFYALL_CV _MD_notifyall_cv + +/* File I/O */ + +/* don't need any I/O initializations */ +#define _MD_INIT_IO() +#define _MD_INIT_FILEDESC(fd) + +#define _MD_OPEN_DIR _MD_open_dir +#define _MD_READ_DIR _MD_read_dir +#define _MD_CLOSE_DIR _MD_close_dir +#define _MD_MAKE_NONBLOCK _MD_make_nonblock +#define _MD_SET_FD_INHERITABLE _MD_set_fd_inheritable +#define _MD_INIT_FD_INHERITABLE _MD_init_fd_inheritable +#define _MD_QUERY_FD_INHERITABLE _MD_query_fd_inheritable +#define _MD_OPEN _MD_open +#define _MD_OPEN_FILE _MD_open +#define _MD_CLOSE_FILE _MD_close_file +#define _MD_READ _MD_read +#define _MD_WRITE _MD_write +#define _MD_WRITEV _MD_writev +#define _MD_LSEEK _MD_lseek +#define _MD_LSEEK64 _MD_lseek64 +#define _MD_FSYNC _MD_fsync +#define _MD_DELETE _MD_delete +#define _MD_GETFILEINFO _MD_getfileinfo +#define _MD_GETFILEINFO64 _MD_getfileinfo64 +#define _MD_GETOPENFILEINFO _MD_getopenfileinfo +#define _MD_GETOPENFILEINFO64 _MD_getopenfileinfo64 +#define _MD_RENAME _MD_rename +#define _MD_ACCESS _MD_access +#define _MD_STAT stat +#define _MD_MKDIR _MD_mkdir +#define _MD_MAKE_DIR _MD_mkdir +#define _MD_RMDIR _MD_rmdir +#define _MD_PR_POLL _MD_pr_poll + +/* Network I/O */ + +#define _MD_CLOSE_SOCKET _MD_close_socket +#define _MD_CONNECT _MD_connect +#define _MD_ACCEPT _MD_accept +#define _MD_BIND _MD_bind +#define _MD_LISTEN _MD_listen +#define _MD_SHUTDOWN _MD_shutdown +#define _MD_RECV _MD_recv +#define _MD_SEND _MD_send +#define _MD_ACCEPT_READ _MD_accept_read +#define _MD_GETSOCKNAME _MD_getsockname +#define _MD_GETPEERNAME _MD_getpeername +#define _MD_GETSOCKOPT _MD_getsockopt +#define _MD_SETSOCKOPT _MD_setsockopt +#define _MD_RECVFROM _MD_recvfrom +#define _MD_SENDTO _MD_sendto +#define _MD_SOCKETPAIR _MD_socketpair +#define _MD_SOCKET _MD_socket +#define _MD_SOCKETAVAILABLE _MD_socketavailable +#define _MD_PIPEAVAILABLE _MD_socketavailable + +#define _MD_GET_SOCKET_ERROR() (errno) +#define _MD_GETHOSTNAME _MD_gethostname + +#define _MD_SELECT select + +/* Process management */ + +#define _MD_CREATE_PROCESS _MD_create_process +#define _MD_DETACH_PROCESS _MD_detach_process +#define _MD_WAIT_PROCESS _MD_wait_process +#define _MD_KILL_PROCESS _MD_kill_process + +/* Atomic data operations */ + +// #define _MD_INIT_ATOMIC _MD_init_atomic +// #define _MD_ATOMIC_INCREMENT _MD_atomic_increment +// #define _MD_ATOMIC_DECREMENT _MD_atomic_decrement +// #define _MD_ATOMIC_SET _MD_atomic_set + +/* memory management */ + +#define _MD_INIT_SEGS _MD_init_segs +#define _MD_ALLOC_SEGMENT _MD_alloc_segment +#define _MD_FREE_SEGMENT _MD_free_segment + +/* Memory mapped file I/O */ + +#define _MD_CREATE_FILE_MAP _MD_create_file_map +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_get_mem_map_alignment +#define _MD_MEM_MAP _MD_mem_map +#define _MD_MEM_UNMAP _MD_mem_unmap +#define _MD_CLOSE_FILE_MAP _MD_close_file_map + +/* Time related */ + +#define _MD_NOW _MD_now +#define _MD_INTERVAL_INIT _MD_interval_init +#define _MD_GET_INTERVAL _MD_get_interval +#define _MD_INTERVAL_PER_SEC _MD_interval_per_sec + +/* File locking */ + +#define _MD_LOCKFILE _MD_lockfile +#define _MD_TLOCKFILE _MD_tlockfile +#define _MD_UNLOCKFILE _MD_unlockfile + +/** + * Prototypes for machine dependent function implementations. (Too bad + * NSPR's MD system blows so much that we have to reiterate every stinking + * thing we implement here in our MD header file.) + */ + +/* Miscellaneous */ + +NSPR_API(void) _MD_cleanup_before_exit(void); +NSPR_API(void) _MD_exit(PRIntn status); + +NSPR_API(char*) _MD_get_env(const char *name); +NSPR_API(PRIntn) _MD_put_env(const char *name); + +NSPR_API(void) _MD_early_init(void); +NSPR_API(void) _MD_final_init(void); + +/* CPU Stuff */ + +NSPR_API(void) _MD_init_cpus(); +NSPR_API(void) _MD_wakeup_cpus(); +NSPR_API(void) _MD_start_interrupts(void); +NSPR_API(void) _MD_stop_interrupts(void); +NSPR_API(void) _MD_disable_clock_interrupts(void); +NSPR_API(void) _MD_block_clock_interrupts(void); +NSPR_API(void) _MD_unblock_clock_interrupts(void); +NSPR_API(void) _MD_clock_interrupt(void); +// NSPR_API(void) _MD_init_stack(PRThreadStack *ts, PRIntn redzone); +// NSPR_API(void) _MD_clear_stack(PRThreadStack* ts); +// NSPR_API(PRInt32) _MD_get_intsoff(void); +// NSPR_API(void) _MD_set_intsoff(PRInt32 _val); +// NSPR_API(_PRCPU*) _MD_current_cpu(void); +// NSPR_API(void) _MD_set_current_cpu(_PRCPU *cpu); +// NSPR_API(void) _MD_init_running_cpu(_PRCPU *cpu); +NSPR_API(PRInt32) _MD_pause_cpu(PRIntervalTime timeout); + +/* Thread stuff */ + +// NSPR_API(PRThread*) _MD_current_thread(void); +NSPR_API(PRThread*) _MD_get_attached_thread(void); +NSPR_API(PRThread*) _MD_last_thread(void); +NSPR_API(void) _MD_set_current_thread(PRThread *thread); +NSPR_API(void) _MD_set_last_thread(PRThread *thread); +NSPR_API(PRStatus) _MD_init_thread(PRThread *thread); +NSPR_API(void) _MD_exit_thread(PRThread *thread); +NSPR_API(PRStatus) _MD_init_attached_thread(PRThread *thread); + +NSPR_API(void) _MD_suspend_thread(PRThread *thread); +NSPR_API(void) _MD_resume_thread(PRThread *thread); +// NSPR_API(void) _MD_suspend_cpu(_PRCPU *cpu); +// NSPR_API(void) _MD_resume_cpu(_PRCPU *cpu); +NSPR_API(void) _MD_begin_suspend_all(void); +NSPR_API(void) _MD_end_suspend_all(void); +NSPR_API(void) _MD_begin_resume_all(void); +NSPR_API(void) _MD_end_resume_all(void); + +NSPR_API(void *) _MD_get_sp(PRThread *thread); + +NSPR_API(void) _MD_clean_thread(PRThread *thread); +NSPR_API(void) _MD_create_primordial_user_thread(PRThread *); +NSPR_API(PRThread*) _MD_create_user_thread(PRUint32 stacksize, void (*start)(void *), void *arg); +NSPR_API(void) _MD_init_primordial_thread(PRThread *thread); +NSPR_API(PRStatus) _MD_create_thread(PRThread *thread, void (*start)(void *), PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize); +NSPR_API(void) _MD_yield(void); +NSPR_API(void) _MD_set_priority(struct _MDThread *md, PRThreadPriority newPri); + +NSPR_API(void) _MD_suspendall(void); +NSPR_API(void) _MD_resumeall(void); + +NSPR_API(void) _MD_init_context(PRThread *thread, char *top, void (*start) (void), PRBool *status); +NSPR_API(void) _MD_switch_context(PRThread *thread); +NSPR_API(void) _MD_restore_context(PRThread *thread); + +NSPR_API(PRStatus) _MD_wait(PRThread *, PRIntervalTime timeout); +NSPR_API(PRStatus) _MD_wakeup_waiter(PRThread *); + +NSPR_API(PRInt32) _MD_setthreadaffinitymask(PRThread *thread, PRUint32 mask ); +NSPR_API(PRInt32) _MD_getthreadaffinitymask(PRThread *thread, PRUint32 *mask); + +/* Thread Synchronization */ + +NSPR_API(void) _MD_init_locks(void); +NSPR_API(PRStatus) _MD_new_lock(struct _MDLock *md); +NSPR_API(void) _MD_free_lock(struct _MDLock *md); +NSPR_API(void) _MD_lock(struct _MDLock *md); +NSPR_API(PRIntn) _MD_test_and_lock(struct _MDLock *md); +NSPR_API(void) _MD_unlock(struct _MDLock *md); +NSPR_API(void) _MD_ioq_lock(void); +NSPR_API(void) _MD_ioq_unlock(void); +NSPR_API(void) _MD_new_sem(struct _MDSemaphore *md, PRUintn value); +NSPR_API(void) _MD_destroy_sem(struct _MDSemaphore *md); +NSPR_API(PRStatus) _MD_timed_wait_sem(struct _MDSemaphore *md, PRIntervalTime timeout); +NSPR_API(PRStatus) _MD_wait_sem(struct _MDSemaphore *md); +NSPR_API(void) _MD_post_sem(struct _MDSemaphore *md); +// NSPR_API(PRInt32) _MD_new_cv(struct _MDCVar *md); +// NSPR_API(void) _MD_free_cv(struct _MDCVar *md); +// NSPR_API(void) _MD_wait_cv(struct _MDCVar *mdCVar, struct _MDLock *mdLock, PRIntervalTime timeout); +// NSPR_API(void) _MD_notify_cv(struct _MDCVar *md, struct _MDLock *lock); +// NSPR_API(void) _MD_notifyall_cv(struct _MDCVar *md, struct _MDLock *lock); + +/* File I/O */ + +// NSPR_API(void) _MD_init_io(void); +NSPR_API(PRStatus) _MD_open_dir(struct _MDDir *md,const char *name); +NSPR_API(char *) _MD_read_dir(struct _MDDir *md, PRIntn flags); +NSPR_API(PRInt32) _MD_close_dir(struct _MDDir *md); +NSPR_API(void) _MD_make_nonblock(PRFileDesc *fd); +NSPR_API(void) _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported); +NSPR_API(void) _MD_query_fd_inheritable(PRFileDesc *fd); +NSPR_API(PRInt32) _MD_open(const char *name, PRIntn osflags, PRIntn mode); +NSPR_API(PRInt32) _MD_close_file(PRInt32 osfd); +NSPR_API(PRInt32) _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount); +NSPR_API(PRInt32) _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount); +NSPR_API(PRInt32) _MD_writev(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_lseek(PRFileDesc *fd, PRInt32 offset, int whence); +NSPR_API(PRInt64) _MD_lseek64(PRFileDesc *fd, PRInt64 offset, int whence); +NSPR_API(PRInt32) _MD_fsync(PRFileDesc *fd); +NSPR_API(PRInt32) _MD_delete(const char *name); +NSPR_API(PRInt32) _MD_getfileinfo(const char *fn, PRFileInfo *info); +NSPR_API(PRInt32) _MD_getfileinfo64(const char *fn, PRFileInfo64 *info); +NSPR_API(PRInt32) _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info); +NSPR_API(PRInt32) _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info); +NSPR_API(PRInt32) _MD_rename(const char *from, const char *to); +NSPR_API(PRInt32) _MD_access(const char *name, PRIntn how); +NSPR_API(PRInt32) _MD_stat(const char *name, struct stat *buf); +NSPR_API(PRInt32) _MD_mkdir(const char *name, PRIntn mode); +NSPR_API(PRInt32) _MD_rmdir(const char *name); +NSPR_API(PRInt32) _MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout); + +/* Network I/O */ +NSPR_API(PRInt32) _MD_close_socket(PRInt32 osfd); +NSPR_API(PRInt32) _MD_connect(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen); +NSPR_API(PRInt32) _MD_listen(PRFileDesc *fd, PRIntn backlog); +NSPR_API(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how); +NSPR_API(PRInt32) _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_accept_read(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout); +// NSPR_API(PRInt32) _MD_fast_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg); +// NSPR_API(PRInt32) _MD_fast_accept_read(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg); +// NSPR_API(void) _MD_update_accept_context(PRInt32 s, PRInt32 ls); +NSPR_API(PRStatus) _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen); +NSPR_API(PRStatus) _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen); +NSPR_API(PRStatus) _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen); +NSPR_API(PRStatus) _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen); +NSPR_API(PRInt32) _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_socketpair(int af, int type, int flags, PRInt32 *osfd); +NSPR_API(PRInt32) _MD_socket(int af, int type, int flags); +NSPR_API(PRInt32) _MD_socketavailable(PRFileDesc *fd); + +// NSPR_API(PRInt32) _MD_get_socket_error(void); +NSPR_API(PRStatus) _MD_gethostname(char *name, PRUint32 namelen); + +/* Process management */ + +NSPR_API(PRProcess *) _MD_create_process(const char *path, char *const *argv, char *const *envp, const PRProcessAttr *attr); +NSPR_API(PRStatus) _MD_detach_process(PRProcess *process); +NSPR_API(PRStatus) _MD_wait_process(PRProcess *process, PRInt32 *exitCode); +NSPR_API(PRStatus) _MD_kill_process(PRProcess *process); + +/* Atomic data operations */ + +// NSPR_API(void) _MD_init_atomic(void); +// NSPR_API(PRInt32) _MD_atomic_increment(PRInt32 *); +// NSPR_API(PRInt32) _MD_atomic_decrement(PRInt32 *); +// NSPR_API(PRInt32) _MD_atomic_set(PRInt32 *, PRInt32); + +/* Memory management */ + +NSPR_API(void) _MD_init_segs(void); +NSPR_API(PRStatus) _MD_alloc_segment(PRSegment *seg, PRUint32 size, void *vaddr); +NSPR_API(void) _MD_free_segment(PRSegment *seg); + +/* Memory mapped file I/O */ + +NSPR_API(PRStatus) _MD_create_file_map(PRFileMap *fmap, PRInt64 size); +NSPR_API(PRInt32) _MD_get_mem_map_alignment(void); +NSPR_API(void *) _MD_mem_map(PRFileMap *fmap, PRInt64 offset, PRUint32 len); +NSPR_API(PRStatus) _MD_mem_unmap(void *addr, PRUint32 size); +NSPR_API(PRStatus) _MD_close_file_map(PRFileMap *fmap); + +/* Time related */ + +NSPR_API(PRTime) _MD_now(void); +NSPR_API(void) _MD_interval_init(void); +NSPR_API(PRIntervalTime) _MD_get_interval(void); +NSPR_API(PRIntervalTime) _MD_interval_per_sec(void); + +/* File locking */ + +NSPR_API(PRStatus) _MD_lockfile(PRInt32 osfd); +NSPR_API(PRStatus) _MD_tlockfile(PRInt32 osfd); +NSPR_API(PRStatus) _MD_unlockfile(PRInt32 osfd); + +#endif /* _nspr_beos_defs_h___*/ diff --git a/nsprpub/pr/include/md/_bsdi.cfg b/nsprpub/pr/include/md/_bsdi.cfg new file mode 100644 index 00000000000..eb933c14f81 --- /dev/null +++ b/nsprpub/pr/include/md/_bsdi.cfg @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef BSDI +#define BSDI +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#if defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#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_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_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#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_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 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#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/nsprpub/pr/include/md/_bsdi.h b/nsprpub/pr/include/md/_bsdi.h new file mode 100644 index 00000000000..b59c9b0f221 --- /dev/null +++ b/nsprpub/pr/include/md/_bsdi.h @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_bsdi_defs_h___ +#define nspr_bsdi_defs_h___ + +/* + * Internal configuration macros + */ + +#include /* for _BSDI_VERSION */ + +#define PR_LINKER_ARCH "bsdi" +#define _PR_SI_SYSNAME "BSDI" +#if defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#else +#error "Unknown CPU architecture" +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define HAVE_BSD_FLOCK +#define NEED_TIME_R +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_NO_LARGE_FILES + +#define USE_SETJMP + +/* BSD/OS 4.3 and newer all have IPv6 support */ +#if _BSDI_VERSION >= 200105 +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#endif + +#ifndef _PR_PTHREADS + +#include + +#if defined(_PR_BSDI_JMPBUF_IS_ARRAY) +#define _MD_GET_SP(_t) (_t)->md.context[2] +#elif defined(_PR_BSDI_JMPBUF_IS_STRUCT) +#define _MD_GET_SP(_t) (_t)->md.context[0].jb_esp +#else +#error "Unknown BSDI jmp_buf type" +#endif + +#define PR_NUM_GCREGS _JBLEN +#define PR_CONTEXT_TYPE jmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (int) (_sp - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_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); \ + longjmp(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; +}; + +/* + * 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; +}; + +#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_CLEAN_THREAD(_thread) + +#endif /* ! _PR_PTHREADS */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit + +#include +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#endif /* nspr_bsdi_defs_h___ */ diff --git a/nsprpub/pr/include/md/_darwin.cfg b/nsprpub/pr/include/md/_darwin.cfg new file mode 100644 index 00000000000..baa57958f08 --- /dev/null +++ b/nsprpub/pr/include/md/_darwin.cfg @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#define PR_AF_INET6 30 /* same as AF_INET6 */ + +#if defined(i386) +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 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_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_DWORD 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 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_ALIGN_OF_WORD 4 + +#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/nsprpub/pr/include/md/_darwin.h b/nsprpub/pr/include/md/_darwin.h new file mode 100644 index 00000000000..3c599fa7fc3 --- /dev/null +++ b/nsprpub/pr/include/md/_darwin.h @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_darwin_defs_h___ +#define nspr_darwin_defs_h___ + +#include "prthread.h" + +#include + +#ifdef XP_MACOSX +#include +#endif + +#define PR_LINKER_ARCH "darwin" +#define _PR_SI_SYSNAME "DARWIN" +#ifdef __i386__ +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__ppc__) +#define _PR_SI_ARCHITECTURE "ppc" +#endif +#define PR_DLL_SUFFIX ".dylib" + +#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_MACH_DYLD +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_HAVE_LARGE_OFF_T +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#define _PR_INET6 +/* + * I'd prefer to use getipnodebyname and getipnodebyaddr but the + * getipnodebyname(3) man page on Mac OS X 10.2 says they are not + * thread-safe. AI_V4MAPPED|AI_ADDRCONFIG doesn't work either. + */ +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +/* + * On Mac OS X 10.2, gethostbyaddr fails with h_errno=NO_RECOVERY + * if you pass an IPv4-mapped IPv6 address to it. + */ +#define _PR_GHBA_DISALLOW_V4MAPPED +#ifdef XP_MACOSX +#if !defined(MAC_OS_X_VERSION_10_3) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 +/* + * socket(AF_INET6) fails with EPROTONOSUPPORT on Mac OS X 10.1. + * IPv6 under OS X 10.2 and below is not complete (see bug 222031). + */ +#define _PR_INET6_PROBE +#endif /* DT < 10.3 */ +#if defined(MAC_OS_X_VERSION_10_2) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_2 +/* Mac OS X 10.2 has inet_ntop and inet_pton. */ +#define _PR_HAVE_INET_NTOP +#endif /* DT >= 10.2 */ +#endif /* XP_MACOSX */ +#define _PR_IPV6_V6ONLY_PROBE +/* The IPV6_V6ONLY socket option is not defined on Mac OS X 10.1. */ +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif + +#if defined(__ppc__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_DarwinPPC_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT(val) _PR_DarwinPPC_AtomicIncrement(val) +extern PRInt32 _PR_DarwinPPC_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT(val) _PR_DarwinPPC_AtomicDecrement(val) +extern PRInt32 _PR_DarwinPPC_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET(val, newval) _PR_DarwinPPC_AtomicSet(val, newval) +extern PRInt32 _PR_DarwinPPC_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD(ptr, val) _PR_DarwinPPC_AtomicAdd(ptr, val) +#elif defined(__i386__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_Darwin_x86_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT(val) _PR_Darwin_x86_AtomicIncrement(val) +extern PRInt32 _PR_Darwin_x86_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT(val) _PR_Darwin_x86_AtomicDecrement(val) +extern PRInt32 _PR_Darwin_x86_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET(val, newval) _PR_Darwin_x86_AtomicSet(val, newval) +extern PRInt32 _PR_Darwin_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD(ptr, val) _PR_Darwin_x86_AtomicAdd(ptr, val) +#endif /* __i386__ */ + +#define USE_SETJMP + +#if !defined(_PR_PTHREADS) + +#include + +#define PR_CONTEXT_TYPE jmp_buf + +#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 +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_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); \ + longjmp(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; +}; + +/* + * 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; +}; + +#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() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#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) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +extern void _MD_YIELD(void); + +#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 + +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, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +/* For writev() */ +#include + +#endif /* nspr_darwin_defs_h___ */ diff --git a/nsprpub/pr/include/md/_dgux.cfg b/nsprpub/pr/include/md/_dgux.cfg new file mode 100644 index 00000000000..4db8ec49d61 --- /dev/null +++ b/nsprpub/pr/include/md/_dgux.cfg @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef DGUX +#define DGUX +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#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 + +#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/nsprpub/pr/include/md/_dgux.h b/nsprpub/pr/include/md/_dgux.h new file mode 100644 index 00000000000..f3f02e82b35 --- /dev/null +++ b/nsprpub/pr/include/md/_dgux.h @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_dgux_defs_h___ +#define nspr_dgux_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "dgux" +#define _PR_SI_SYSNAME "DGUX" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#undef HAVE_STACK_GROWING_UP +#define HAVE_NETCONFIG +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_NEED_STRCASECMP +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _MD_GET_SP(_t) (_t)->md.context[4] +#define _PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_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); \ + _LONGJMP(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures. + * Don't use SVR4 native threads (yet). + */ + +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; +}; + +/* + * 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; +}; + +#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() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#include +#include +#include +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *execptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#define _MD_POLL _poll +#include +#include +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +#endif /* nspr_dgux_defs_h___ */ diff --git a/nsprpub/pr/include/md/_freebsd.cfg b/nsprpub/pr/include/md/_freebsd.cfg new file mode 100644 index 00000000000..76d35420271 --- /dev/null +++ b/nsprpub/pr/include/md/_freebsd.cfg @@ -0,0 +1,337 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef FREEBSD +#define FREEBSD +#endif + +#define PR_AF_INET6 28 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#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(__alpha__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#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 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 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#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 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 + +#elif defined(__ia64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#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 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_ALIGN_OF_WORD 8 + +#elif defined(__amd64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#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 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_ALIGN_OF_WORD 8 + +#else + +#error "Unknown CPU architecture" + +#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/nsprpub/pr/include/md/_freebsd.h b/nsprpub/pr/include/md/_freebsd.h new file mode 100644 index 00000000000..b684ef79f8d --- /dev/null +++ b/nsprpub/pr/include/md/_freebsd.h @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_freebsd_defs_h___ +#define nspr_freebsd_defs_h___ + +#include "prthread.h" + +#if __FreeBSD__ >= 2 +#include /* for __FreeBSD_version */ +#endif +#include + +#define PR_LINKER_ARCH "freebsd" +#define _PR_SI_SYSNAME "FREEBSD" +#if defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__alpha__) +#define _PR_SI_ARCHITECTURE "alpha" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__ia64__) +#define _PR_SI_ARCHITECTURE "ia64" +#elif defined(__amd64__) +#define _PR_SI_ARCHITECTURE "amd64" +#else +#error "Unknown CPU architecture" +#endif +#if defined(__ELF__) +#define PR_DLL_SUFFIX ".so" +#else +#define PR_DLL_SUFFIX ".so.1.0" +#endif + +#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 _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_NO_LARGE_FILES + +#if defined(_PR_PTHREADS) +#if __FreeBSD_version >= 400008 +/* + * libc_r before this version of FreeBSD doesn't have poll(). + * Although libc has poll(), it is not thread-safe so we can't + * use it in the pthreads version. + */ +#define _PR_POLL_AVAILABLE +#endif +#else +#if __FreeBSD_version >= 300000 +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#endif +#endif + +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#if __FreeBSD_version >= 400014 +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#define _PR_IPV6_V6ONLY_PROBE +#endif + +#define USE_SETJMP + +#ifndef _PR_PTHREADS +#include + +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#define _MD_GET_SP(_th) (_th)->md.context[0]._sjb[2] +#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; +}; + +/* + * 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; +}; + +#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() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#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) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +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_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) + +#if defined(_PR_POLL_AVAILABLE) +#include +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) +#endif + +/* freebsd has INADDR_LOOPBACK defined, but in /usr/include/rpc/types.h, and I didn't + want to be including that.. */ +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK (u_long)0x7F000001 +#endif + +/* For writev() */ +#include + +#endif /* nspr_freebsd_defs_h___ */ diff --git a/nsprpub/pr/include/md/_hpux.h b/nsprpub/pr/include/md/_hpux.h new file mode 100644 index 00000000000..2a6f177f415 --- /dev/null +++ b/nsprpub/pr/include/md/_hpux.h @@ -0,0 +1,297 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_xhppa_defs_h___ +#define nspr_xhppa_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "hpux" +#define _PR_SI_SYSNAME "HPUX" +#ifdef __ia64 +#define _PR_SI_ARCHITECTURE "ia64" +#define PR_DLL_SUFFIX ".so" +#else +/* + * _PR_SI_ARCHITECTURE must be "hppa1.1" for backward compatibility. + * It was changed to "hppa" in NSPR 4.6.2, but was changed back in + * NSPR 4.6.4. + */ +#define _PR_SI_ARCHITECTURE "hppa1.1" +#define PR_DLL_SUFFIX ".sl" +#endif + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +/* + * _USE_BIG_FDS increases the size of fd_set from 256 bytes to + * about 7500 bytes. PR_Poll allocates three fd_sets on the + * stack, so it is safer to also increase the default thread + * stack size. + */ +#define _MD_DEFAULT_STACK_SIZE (2*65536L) +#define _MD_MINIMUM_STACK_SIZE (2*65536L) +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define NEED_TIME_R + +#define HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#ifdef IS_64 +#define USE_DLFCN +#else +#define USE_HPSHL +#endif +#ifndef HAVE_STRERROR +#define HAVE_STRERROR +#endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_HAVE_POSIX_SEMAPHORES +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#define _PR_ACCEPT_INHERIT_NONBLOCK + +#if defined(__ia64) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_ia64_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _PR_ia64_AtomicIncrement +extern PRInt32 _PR_ia64_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _PR_ia64_AtomicDecrement +extern PRInt32 _PR_ia64_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _PR_ia64_AtomicAdd +extern PRInt32 _PR_ia64_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _PR_ia64_AtomicSet +#endif + +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#else +#define _PR_INET6_PROBE +#define _PR_HAVE_MD_SOCKADDR_IN6 +/* isomorphic to struct in6_addr on HP-UX B.11.23 */ +struct _md_in6_addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + PRUint32 _S6_u32[4]; + PRUint32 __S6_align; + } _s6_un; +}; +/* isomorphic to struct sockaddr_in6 on HP-UX B.11.23 */ +struct _md_sockaddr_in6 { + PRUint16 sin6_family; + PRUint16 sin6_port; + PRUint32 sin6_flowinfo; + struct _md_in6_addr sin6_addr; + PRUint32 sin6_scope_id; +}; +#endif + +#if !defined(_PR_PTHREADS) + +#include +#include + +#define USE_SETJMP + +#define _MD_GET_SP(_t) (*((int *)((_t)->md.jb) + 1)) +#define PR_NUM_GCREGS _JBLEN +/* Caveat: This makes jmp_buf full of doubles. */ +#define CONTEXT(_th) ((_th)->md.jb) + + /* Stack needs two frames (64 bytes) at the bottom */ \ +#define _MD_SET_THR_SP(_t, _sp) ((_MD_GET_SP(_t)) = (int) (_sp + 64 *2)) +#define SAVE_CONTEXT(_th) _setjmp(CONTEXT(_th)) +#define GOTO_CONTEXT(_th) _longjmp(CONTEXT(_th), 1) + +#if !defined(PTHREADS_USER) + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *(status) = PR_TRUE; \ + if (_setjmp(CONTEXT(_thread))) (*_main)(); \ + /* Stack needs two frames (64 bytes) at the bottom */ \ + (_MD_GET_SP(_thread)) = (int) ((_sp) + 64*2); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_setjmp(CONTEXT(_thread))) { \ + (_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); \ + _longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures. HP-UX has no native threads. */ + +struct _MDThread { + jmp_buf jb; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +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; +}; + +#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) + +#else /* PTHREADS_USER */ + +#include "_nspr_pthread.h" + +#endif /* PTHREADS_USER */ + +#endif /* !defined(_PR_PTHREADS) */ + +#if !defined(PTHREADS_USER) +#define _MD_EARLY_INIT _MD_EarlyInit +#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, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +#include +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) + +#ifdef HPUX11 +extern void _MD_hpux_map_sendfile_error(int err); +#endif /* HPUX11 */ + +#endif /* nspr_xhppa_defs_h___ */ diff --git a/nsprpub/pr/include/md/_hpux32.cfg b/nsprpub/pr/include/md/_hpux32.cfg new file mode 100644 index 00000000000..d79b1a9ffb2 --- /dev/null +++ b/nsprpub/pr/include/md/_hpux32.cfg @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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 PR_AF_INET6 22 /* same as AF_INET6 */ + +#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 8 +#define PR_ALIGN_OF_POINTER 4 + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#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/nsprpub/pr/include/md/_hpux64.cfg b/nsprpub/pr/include/md/_hpux64.cfg new file mode 100644 index 00000000000..f1f829d187b --- /dev/null +++ b/nsprpub/pr/include/md/_hpux64.cfg @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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_AF_INET6 22 /* same as AF_INET6 */ + +#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 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 + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#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/nsprpub/pr/include/md/_irix.h b/nsprpub/pr/include/md/_irix.h new file mode 100644 index 00000000000..c38bb4bc282 --- /dev/null +++ b/nsprpub/pr/include/md/_irix.h @@ -0,0 +1,470 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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 + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "irix" +#define _PR_SI_SYSNAME "IRIX" +#define _PR_SI_ARCHITECTURE "mips" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _PR_NUM_GCREGS 9 +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MIN_STACK_SIZE 16384L + +#undef HAVE_STACK_GROWING_UP +#define HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_MALLOC_SYMBOLS +#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 +#define _PR_HAVE_POSIX_SEMAPHORES +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#define _PR_ACCEPT_INHERIT_NONBLOCK + +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#endif + +/* Initialization entry points */ +NSPR_API(void) _MD_EarlyInit(void); +#define _MD_EARLY_INIT _MD_EarlyInit + +NSPR_API(void) _MD_IrixInit(void); +#define _MD_FINAL_INIT _MD_IrixInit + +#define _MD_INIT_IO() + +/* Timer operations */ +NSPR_API(PRIntervalTime) _MD_IrixGetInterval(void); +#define _MD_GET_INTERVAL _MD_IrixGetInterval + +NSPR_API(PRIntervalTime) _MD_IrixIntervalPerSec(void); +#define _MD_INTERVAL_PER_SEC _MD_IrixIntervalPerSec + +/* GC operations */ +NSPR_API(void *) _MD_GetSP(PRThread *thread); +#define _MD_GET_SP _MD_GetSP + +/* The atomic operations */ +#include +#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) + +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + +/************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * Data region private to each sproc. This region is setup by calling + * mmap(...,MAP_LOCAL,...). The private data is mapped at the same + * address in every sproc, but every sproc gets a private mapping. + * + * Just make sure that this structure fits in a page, as only one page + * is allocated for the private region. + */ +struct sproc_private_data { + struct PRThread *me; + struct _PRCPU *cpu; + struct PRThread *last; + PRUintn intsOff; + int sproc_pid; +}; + +extern char *_nspr_sproc_private; + +#define _PR_PRDA() ((struct sproc_private_data *) _nspr_sproc_private) +#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) +#define _MD_SET_CURRENT_CPU(_cpu) _PR_PRDA()->cpu = (_cpu) +#define _MD_SET_INTSOFF(_val) (_PR_PRDA()->intsOff = _val) +#define _MD_GET_INTSOFF() (_PR_PRDA()->intsOff) + +#define _MD_SET_SPROC_PID(_val) (_PR_PRDA()->sproc_pid = _val) +#define _MD_GET_SPROC_PID() (_PR_PRDA()->sproc_pid) + +NSPR_API(struct PRThread*) _MD_get_attached_thread(void); +NSPR_API(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) { \ + _PR_POST_SEM(_pr_irix_exit_sem); \ + _MD_Wakeup_CPUs(); \ + _exit(0); \ + } \ + } + +#define _MD_ATTACH_THREAD(threadp) + +#define _MD_SAVE_ERRNO(_thread) (_thread)->md.errcode = errno; +#define _MD_RESTORE_ERRNO(_thread) errno = (_thread)->md.errcode; + +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 (_MD_GET_ATTACHED_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _MD_GET_ATTACHED_THREAD())) \ + _PR_INTSOFF(_is); \ + _PR_LOCK(_pr_heapLock); \ + } + +#define _PR_UNLOCK_HEAP() if (_pr_primordialCPU) { \ + _PR_UNLOCK(_pr_heapLock); \ + if (_MD_GET_ATTACHED_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _MD_GET_ATTACHED_THREAD())) \ + _PR_INTSON(_is); \ + } \ + } + +#define _PR_OPEN_POLL_SEM(_sem) usopenpollsema(_sem, 0666) +#define _PR_WAIT_SEM(_sem) uspsema(_sem) +#define _PR_POST_SEM(_sem) usvsema(_sem) + +#define _MD_CVAR_POST_SEM(threadp) usvsema((threadp)->md.cvar_pollsem) + +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +struct _MDLock { + ulock_t lock; + usptr_t *arena; +}; + +/* + * disable pre-emption for the LOCAL threads when calling the arena lock + * routines + */ + +#define _PR_LOCK(lock) { \ + PRIntn _is; \ + PRThread *me = _MD_GET_ATTACHED_THREAD(); \ + if (me && !_PR_IS_NATIVE_THREAD(me)) \ + _PR_INTSOFF(_is); \ + ussetlock(lock); \ + if (me && !_PR_IS_NATIVE_THREAD(me)) \ + _PR_FAST_INTSON(_is); \ + } + +#define _PR_UNLOCK(lock) { \ + PRIntn _is; \ + PRThread *me = _MD_GET_ATTACHED_THREAD(); \ + if (me && !_PR_IS_NATIVE_THREAD(me)) \ + _PR_INTSOFF(_is); \ + usunsetlock(lock); \ + if (me && !_PR_IS_NATIVE_THREAD(me)) \ + _PR_FAST_INTSON(_is); \ + } + +NSPR_API(PRStatus) _MD_NEW_LOCK(struct _MDLock *md); +NSPR_API(void) _MD_FREE_LOCK(struct _MDLock *lockp); + +#define _MD_LOCK(_lockp) _PR_LOCK((_lockp)->lock) +#define _MD_UNLOCK(_lockp) _PR_UNLOCK((_lockp)->lock) +#define _MD_TEST_AND_LOCK(_lockp) (uscsetlock((_lockp)->lock, 1) == 0) + +extern ulock_t _pr_heapLock; + +struct _MDThread { + jmp_buf jb; + usptr_t *pollsem_arena; + usema_t *cvar_pollsem; + PRInt32 cvar_pollsemfd; + PRInt32 cvar_pollsem_select; /* acquire sem by calling select */ + PRInt32 cvar_wait; /* if 1, thread is waiting on cvar Q */ + PRInt32 id; + PRInt32 suspending_id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDSemaphore { + usema_t *sem; +}; + +struct _MDCVar { + ulock_t mdcvar_lock; +}; + +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; + struct _MDCPU_Unix md_unix; +}; + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + int *jb = (_thread)->md.jb; \ + *status = PR_TRUE; \ + (void) setjmp(jb); \ + (_thread)->md.jb[JB_SP] = (int) ((_sp) - 64); \ + (_thread)->md.jb[JB_PC] = (int) _main; \ + _thread->no_sched = 0; \ + PR_END_MACRO + +/* +** Switch away from the current thread context by saving its state and +** calling the thread scheduler. Reload cpu when we come back from the +** context switch because it might have changed. +* +* XXX RUNQ lock needed before clearing _PR_NO_SCHED flag, because the +* thread may be unr RUNQ? +*/ +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + PR_ASSERT(_thread->no_sched); \ + if (!setjmp(_thread->md.jb)) { \ + _MD_SAVE_ERRNO(_thread) \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } else { \ + PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \ + _MD_LAST_THREAD()->no_sched = 0; \ + } \ + PR_END_MACRO + +/* +** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or +** initialized by _MD_INIT_CONTEXT. +*/ +#define _MD_RESTORE_CONTEXT(_newThread) \ + PR_BEGIN_MACRO \ + int *jb = (_newThread)->md.jb; \ + _MD_RESTORE_ERRNO(_newThread) \ + _MD_SET_CURRENT_THREAD(_newThread); \ + _newThread->no_sched = 1; \ + longjmp(jb, 1); \ + PR_END_MACRO + +NSPR_API(PRStatus) _MD_InitThread(struct PRThread *thread, + PRBool wakeup_parent); +NSPR_API(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_InitAttachedThread(thread, PR_FALSE) + +NSPR_API(void) _MD_ExitThread(struct PRThread *thread); +#define _MD_EXIT_THREAD _MD_ExitThread + +NSPR_API(void) _MD_SuspendThread(struct PRThread *thread); +#define _MD_SUSPEND_THREAD _MD_SuspendThread + +NSPR_API(void) _MD_ResumeThread(struct PRThread *thread); +#define _MD_RESUME_THREAD _MD_ResumeThread + +NSPR_API(void) _MD_SuspendCPU(struct _PRCPU *thread); +#define _MD_SUSPEND_CPU _MD_SuspendCPU + +NSPR_API(void) _MD_ResumeCPU(struct _PRCPU *thread); +#define _MD_RESUME_CPU _MD_ResumeCPU + +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_RESUME_ALL() + +NSPR_API(void) _MD_InitLocks(void); +#define _MD_INIT_LOCKS _MD_InitLocks + +NSPR_API(void) _MD_CleanThread(struct PRThread *thread); +#define _MD_CLEAN_THREAD _MD_CleanThread + +#define _MD_YIELD() sginap(0) + +/* The _PR_MD_WAIT_LOCK and _PR_MD_WAKEUP_WAITER functions put to sleep and + * awaken a thread which is waiting on a lock or cvar. + */ +NSPR_API(PRStatus) _MD_wait(struct PRThread *, PRIntervalTime timeout); +#define _MD_WAIT _MD_wait + +NSPR_API(void) _PR_MD_primordial_cpu(); +NSPR_API(void) _PR_MD_WAKEUP_PRIMORDIAL_CPU(); + +NSPR_API(PRStatus) _MD_WakeupWaiter(struct PRThread *); +#define _MD_WAKEUP_WAITER _MD_WakeupWaiter + +NSPR_API(void ) _MD_exit(PRIntn status); +#define _MD_EXIT _MD_exit + +#include "prthread.h" + +NSPR_API(void) _MD_SetPriority(struct _MDThread *thread, + PRThreadPriority newPri); +#define _MD_SET_PRIORITY _MD_SetPriority + +NSPR_API(PRStatus) _MD_CreateThread( + struct PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +#define _MD_CREATE_THREAD _MD_CreateThread + +extern void _MD_CleanupBeforeExit(void); +#define _MD_CLEANUP_BEFORE_EXIT _MD_CleanupBeforeExit + +NSPR_API(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, + fd_set *exceptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#include +#include +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + + +#define HAVE_THREAD_AFFINITY 1 + +NSPR_API(PRInt32) _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask); +#define _MD_GETTHREADAFFINITYMASK _MD_GetThreadAffinityMask + +NSPR_API(void) _MD_InitRunningCPU(struct _PRCPU *cpu); +#define _MD_INIT_RUNNING_CPU _MD_InitRunningCPU + +#endif /* defined(_PR_PTHREADS) */ + +#endif /* _LANGUAGE_ASSEMBLY */ + +#endif /* nspr_irix_defs_h___ */ diff --git a/nsprpub/pr/include/md/_irix32.cfg b/nsprpub/pr/include/md/_irix32.cfg new file mode 100644 index 00000000000..88e0ceedc60 --- /dev/null +++ b/nsprpub/pr/include/md/_irix32.cfg @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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 PR_AF_INET6 24 /* same as AF_INET6 */ + +#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_BYTES_PER_WORD_LOG2 2 +#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 + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define _PR_POLL_BACKCOMPAT + +#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/nsprpub/pr/include/md/_irix64.cfg b/nsprpub/pr/include/md/_irix64.cfg new file mode 100644 index 00000000000..ba51eca30e2 --- /dev/null +++ b/nsprpub/pr/include/md/_irix64.cfg @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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_AF_INET6 24 /* same as AF_INET6 */ + +#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 + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#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/nsprpub/pr/include/md/_linux.cfg b/nsprpub/pr/include/md/_linux.cfg new file mode 100644 index 00000000000..d02ab21f0c2 --- /dev/null +++ b/nsprpub/pr/include/md/_linux.cfg @@ -0,0 +1,718 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file is used by not only Linux but also other glibc systems + * such as GNU/Hurd and GNU/k*BSD. + */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#if !defined(LINUX) && defined(__linux__) +#define LINUX +#endif + +#ifdef __FreeBSD_kernel__ +#define PR_AF_INET6 28 /* same as AF_INET6 */ +#else +#define PR_AF_INET6 10 /* same as AF_INET6 */ +#endif + +#ifdef __powerpc64__ + +#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_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_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) + +#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 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 PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#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_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__ia64__) + +#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_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__x86_64__) + +#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_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mc68000__) + +#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 2 +#define PR_ALIGN_OF_LONG 2 +#define PR_ALIGN_OF_INT64 2 +#define PR_ALIGN_OF_FLOAT 2 +#define PR_ALIGN_OF_DOUBLE 2 +#define PR_ALIGN_OF_POINTER 2 +#define PR_ALIGN_OF_WORD 2 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#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 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 PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#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_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips__) + +#ifdef __MIPSEB__ +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#elif defined(__MIPSEL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown MIPS endianness." +#endif + +#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 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 PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__arm__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#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_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__hppa__) + +#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 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 PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390x__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_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_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN + +#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_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#endif + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#if PR_ALIGN_OF_DOUBLE == 8 +#define HAVE_ALIGNED_DOUBLES +#endif +#if PR_ALIGN_OF_INT64 == 8 +#define HAVE_ALIGNED_LONGLONGS +#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/nsprpub/pr/include/md/_linux.h b/nsprpub/pr/include/md/_linux.h new file mode 100644 index 00000000000..583997165af --- /dev/null +++ b/nsprpub/pr/include/md/_linux.h @@ -0,0 +1,625 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file is used by not only Linux but also other glibc systems + * such as GNU/Hurd and GNU/k*BSD. + */ + +#ifndef nspr_linux_defs_h___ +#define nspr_linux_defs_h___ + +#include "prthread.h" + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "linux" +#define _PR_SI_SYSNAME "LINUX" +#ifdef __powerpc64__ +#define _PR_SI_ARCHITECTURE "ppc64" +#elif defined(__powerpc__) +#define _PR_SI_ARCHITECTURE "ppc" +#elif defined(__alpha) +#define _PR_SI_ARCHITECTURE "alpha" +#elif defined(__ia64__) +#define _PR_SI_ARCHITECTURE "ia64" +#elif defined(__x86_64__) +#define _PR_SI_ARCHITECTURE "x86-64" +#elif defined(__mc68000__) +#define _PR_SI_ARCHITECTURE "m68k" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__mips__) +#define _PR_SI_ARCHITECTURE "mips" +#elif defined(__arm__) +#define _PR_SI_ARCHITECTURE "arm" +#elif defined(__hppa__) +#define _PR_SI_ARCHITECTURE "hppa" +#elif defined(__s390x__) +#define _PR_SI_ARCHITECTURE "s390x" +#elif defined(__s390__) +#define _PR_SI_ARCHITECTURE "s390" +#else +#error "Unknown CPU architecture" +#endif +#define PR_DLL_SUFFIX ".so" + +#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 + +/* + * Elf linux supports dl* functions + */ +#define HAVE_DLL +#define USE_DLFCN + +#ifdef __FreeBSD_kernel__ +#define _PR_HAVE_SOCKADDR_LEN +#endif + +#if defined(__i386__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_x86_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _PR_x86_AtomicIncrement +extern PRInt32 _PR_x86_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _PR_x86_AtomicDecrement +extern PRInt32 _PR_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _PR_x86_AtomicAdd +extern PRInt32 _PR_x86_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _PR_x86_AtomicSet +#endif + +#if defined(__ia64__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_ia64_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _PR_ia64_AtomicIncrement +extern PRInt32 _PR_ia64_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _PR_ia64_AtomicDecrement +extern PRInt32 _PR_ia64_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _PR_ia64_AtomicAdd +extern PRInt32 _PR_ia64_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _PR_ia64_AtomicSet +#endif + +#if defined(__x86_64__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_x86_64_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _PR_x86_64_AtomicIncrement +extern PRInt32 _PR_x86_64_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _PR_x86_64_AtomicDecrement +extern PRInt32 _PR_x86_64_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _PR_x86_64_AtomicAdd +extern PRInt32 _PR_x86_64_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _PR_x86_64_AtomicSet +#endif + +#if defined(__powerpc__) && !defined(__powerpc64__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_ppc_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _PR_ppc_AtomicIncrement +extern PRInt32 _PR_ppc_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _PR_ppc_AtomicDecrement +extern PRInt32 _PR_ppc_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _PR_ppc_AtomicAdd +extern PRInt32 _PR_ppc_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _PR_ppc_AtomicSet +#endif + +#if defined(__alpha) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_ADD(ptr, i) ({ \ + PRInt32 __atomic_tmp, __atomic_ret; \ + __asm__ __volatile__( \ + "1: ldl_l %[ret], %[val] \n" \ + " addl %[ret], %[inc], %[tmp] \n" \ + " addl %[ret], %[inc], %[ret] \n" \ + " stl_c %[tmp], %[val] \n" \ + " beq %[tmp], 2f \n" \ + ".subsection 2 \n" \ + "2: br 1b \n" \ + ".previous" \ + : [ret] "=&r" (__atomic_ret), \ + [tmp] "=&r" (__atomic_tmp), \ + [val] "=m" (*ptr) \ + : [inc] "Ir" (i), "m" (*ptr)); \ + __atomic_ret; \ +}) +#define _MD_ATOMIC_INCREMENT(ptr) _MD_ATOMIC_ADD(ptr, 1) +#define _MD_ATOMIC_DECREMENT(ptr) ({ \ + PRInt32 __atomic_tmp, __atomic_ret; \ + __asm__ __volatile__( \ + "1: ldl_l %[ret], %[val] \n" \ + " subl %[ret], 1, %[tmp] \n" \ + " subl %[ret], 1, %[ret] \n" \ + " stl_c %[tmp], %[val] \n" \ + " beq %[tmp], 2f \n" \ + ".subsection 2 \n" \ + "2: br 1b \n" \ + ".previous" \ + : [ret] "=&r" (__atomic_ret), \ + [tmp] "=&r" (__atomic_tmp), \ + [val] "=m" (*ptr) \ + : "m" (*ptr)); \ + __atomic_ret; \ +}) +#define _MD_ATOMIC_SET(ptr, n) ({ \ + PRInt32 __atomic_tmp, __atomic_ret; \ + __asm__ __volatile__( \ + "1: ldl_l %[ret], %[val] \n" \ + " mov %[newval], %[tmp] \n" \ + " stl_c %[tmp], %[val] \n" \ + " beq %[tmp], 2f \n" \ + ".subsection 2 \n" \ + "2: br 1b \n" \ + ".previous" \ + : [ret] "=&r" (__atomic_ret), \ + [tmp] "=&r"(__atomic_tmp), \ + [val] "=m" (*ptr) \ + : [newval] "Ir" (n), "m" (*ptr)); \ + __atomic_ret; \ +}) +#endif + +#if defined(__arm__) && defined(_PR_ARM_KUSER) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() + +/* + * The kernel provides this helper function at a fixed address with a fixed + * ABI signature, directly callable from user space. + * + * Definition: + * Atomically store newval in *ptr if *ptr is equal to oldval. + * Return zero if *ptr was changed or non-zero if no exchange happened. + */ +typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr); +#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) + +#define _MD_ATOMIC_INCREMENT(ptr) _MD_ATOMIC_ADD(ptr, 1) +#define _MD_ATOMIC_DECREMENT(ptr) _MD_ATOMIC_ADD(ptr, -1) + +static inline PRInt32 _MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 n) +{ + PRInt32 ov, nv; + volatile PRInt32 *vp = ptr; + + do { + ov = *vp; + nv = ov + n; + } while (__kernel_cmpxchg(ov, nv, vp)); + + return nv; +} + +static inline PRInt32 _MD_ATOMIC_SET(PRInt32 *ptr, PRInt32 nv) +{ + PRInt32 ov; + volatile PRInt32 *vp = ptr; + + do { + ov = *vp; + } while (__kernel_cmpxchg(ov, nv, vp)); + + return ov; +} +#endif + +#define USE_SETJMP +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _PR_POLL_AVAILABLE +#endif +#undef _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#if defined(__alpha) || defined(__ia64__) +#define _PR_HAVE_LARGE_OFF_T +#elif (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) +#define _PR_HAVE_OFF64_T +#else +#define _PR_NO_LARGE_FILES +#endif +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#endif +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY +#if (__GLIBC__ >= 2) && defined(_PR_PTHREADS) +#define _PR_HAVE_GETHOST_R +#define _PR_HAVE_GETHOST_R_INT +#endif + +#ifdef _PR_PTHREADS + +extern void _MD_CleanupBeforeExit(void); +#define _MD_CLEANUP_BEFORE_EXIT _MD_CleanupBeforeExit + +#else /* ! _PR_PTHREADS */ + +#include + +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#ifdef __powerpc__ +/* + * PowerPC based MkLinux + * + * On the PowerPC, the new style jmp_buf isn't used until glibc + * 2.1. + */ +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_GPR1] +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__misc[0] +#endif /* glibc 2.1 or later */ +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +/* aix = 64, macos = 70 */ +#define PR_NUM_GCREGS 64 + +#elif defined(__alpha) +/* Alpha based Linux */ + +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_SP] +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE long int +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE __ptr_t +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +/* XXX not sure if this is correct, or maybe it should be 17? */ +#define PR_NUM_GCREGS 9 + +#elif defined(__ia64__) + +#define _MD_GET_SP(_t) ((long *)((_t)->md.context[0].__jmpbuf)[0]) +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE long int + +#define PR_NUM_GCREGS _JBLEN + +#elif defined(__mc68000__) +/* m68k based Linux */ + +/* + * On the m68k, glibc still uses the old style sigjmp_buf, even + * in glibc 2.0.7. + */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE int +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE __ptr_t +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +/* XXX not sure if this is correct, or maybe it should be 17? */ +#define PR_NUM_GCREGS 9 + +#elif defined(__sparc__) +/* Sparc */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +/* + * You need glibc2-2.0.7-25 or later. The libraries that came with + * Red Hat 5.1 are not new enough, but they are in 5.2. + */ +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_SP] +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[JB_FP] = val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[JB_FP]) +#define _MD_SP_TYPE int +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__fp +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE __ptr_t +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +#elif defined(__i386__) +/* Intel based Linux */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_SP] +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[JB_BP] = val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[JB_BP]) +#define _MD_SP_TYPE int +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[0].__bp = val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) &((_t)->md.context[0].__jmpbuf[0].__bp) +#define _MD_SP_TYPE __ptr_t +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ +#define PR_NUM_GCREGS 6 + +#elif defined(__mips__) +/* Linux/MIPS */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[0].__fp = (val)) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[0].__fp) +#define _MD_SP_TYPE __ptr_t +#else +#error "Linux/MIPS pre-glibc2 not supported yet" +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +#elif defined(__arm__) +/* ARM/Linux */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[20] +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[19] = (val)) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[19]) +#define _MD_SP_TYPE __ptr_t +#else +#error "ARM/Linux pre-glibc2 not supported yet" +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +#else + +#error "Unknown CPU architecture" + +#endif /*__powerpc__*/ + +/* +** Initialize a thread context to run "_main()" when started +*/ +#ifdef __powerpc__ + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread), 1)) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 128); \ + _thread->md.sp = _MD_GET_SP_PTR(_thread); \ + _thread->md.fp = _MD_GET_FP_PTR(_thread); \ + _MD_SET_FP(_thread, 0); \ +} + +#elif defined(__mips__) + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + (void) sigsetjmp(CONTEXT(_thread), 1); \ + _thread->md.context[0].__jmpbuf[0].__pc = (__ptr_t) _main; \ + _MD_GET_SP(_thread) = (_MD_SP_TYPE) ((_sp) - 64); \ + _thread->md.sp = _MD_GET_SP_PTR(_thread); \ + _thread->md.fp = _MD_GET_FP_PTR(_thread); \ + _MD_SET_FP(_thread, 0); \ +} + +#else + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread), 1)) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (_MD_SP_TYPE) ((_sp) - 64); \ + _thread->md.sp = _MD_GET_SP_PTR(_thread); \ + _thread->md.fp = _MD_GET_FP_PTR(_thread); \ + _MD_SET_FP(_thread, 0); \ +} + +#endif /*__powerpc__*/ + +#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; + void *sp; + void *fp; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#include /* for FD_SETSIZE */ +#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; +}; + +#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() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#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) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +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_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 __select + +#ifdef _PR_POLL_AVAILABLE +#include +extern int __syscall_poll(struct pollfd *ufds, unsigned long int nfds, + int timeout); +#define _MD_POLL __syscall_poll +#endif + +/* For writev() */ +#include + +extern void _MD_linux_map_sendfile_error(int err); + +#endif /* nspr_linux_defs_h___ */ diff --git a/nsprpub/pr/include/md/_macos.h b/nsprpub/pr/include/md/_macos.h new file mode 100644 index 00000000000..dbcab4090b7 --- /dev/null +++ b/nsprpub/pr/include/md/_macos.h @@ -0,0 +1,725 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prmacos_h___ +#define prmacos_h___ + +// +// This file contains all changes and additions which need to be made to the NSPR runtime +// for the Macintosh platform (specifically the Metrowerks environment). This file should +// only be incluced in Macintosh builds. +// + +#define PR_DLL_SUFFIX "" +#define _PR_LOCAL_THREADS_ONLY +#define _PR_NO_PREEMPT 1 +#define _PR_HAVE_ATOMIC_OPS 1 + +#include "prinit.h" +#include "prio.h" +#include "prlong.h" +#include "prlock.h" +#include "prcvar.h" +#include "prsem.h" +#include "prthread.h" +#include "prtime.h" +#include "prproces.h" + +#if !defined(MAC_NSPR_STANDALONE) +#include "macstdlibextras.h" +#endif + +#include +#include + +#include +#include +#include + +#define _PR_HAVE_PEEK_BUFFER +#define _PR_PEEK_BUFFER_MAX (16 * 1024) +#define _PR_FD_NEED_EMULATE_MSG_PEEK(fd) 1 + +struct _MDProcess { + PRInt8 notused; +}; + +struct _MDThread { + jmp_buf jb; + int osErrCode; + PRLock * asyncIOLock; + PRCondVar * asyncIOCVar; + PRBool missedIONotify; + PRBool missedAsyncNotify; + PRBool asyncNotifyPending; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +struct _MDCPU { + AbsoluteTime lastThreadSwitch; + AbsoluteTime lastWakeUpProcess; + PRBool trackScheduling; +}; + +typedef struct _MDSocketCallerInfo { + PRThread * thread; + void * cookie; +} _MDSocketCallerInfo; + +struct _MDFileDesc { + PRInt32 osfd; + PRPackedBool orderlyDisconnect; + PRPackedBool readReady; + PRPackedBool writeReady; + PRPackedBool exceptReady; + PRLock * miscLock; + + /* Server sockets: listen bit tells the notifier func what to do */ + PRBool doListen; + + /* stored error for non-blocking connects, as a Unix-style error code */ + OTReason disconnectError; + + _MDSocketCallerInfo misc; + _MDSocketCallerInfo read; + _MDSocketCallerInfo write; +}; + +/* +** Iinitialization Related definitions +*/ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _MD_FinalInit + +/* +** Interrupts Related definitions +*/ + +#define _MD_GET_INTSOFF() (_pr_intsOff) + +#define _MD_INTSOFF(_is) \ + PR_BEGIN_MACRO \ + ENTER_CRITICAL_REGION(); \ + (_is) = _PR_MD_GET_INTSOFF(); \ + _PR_MD_SET_INTSOFF(1); \ + LEAVE_CRITICAL_REGION(); \ + PR_END_MACRO + +#if TARGET_CARBON +extern void _MD_SetIntsOff(PRInt32 ints); +#define _MD_SET_INTSOFF(_val) _MD_SetIntsOff(_val) +#else /* not TARGET_CARBON */ +#define _MD_SET_INTSOFF(_val) (_pr_intsOff = _val) +#endif /* TARGET_CARBON */ + +#define _MD_START_INTERRUPTS _MD_StartInterrupts +#define _MD_STOP_INTERRUPTS _MD_StopInterrupts +#define _MD_BLOCK_CLOCK_INTERRUPTS() +#define _MD_UNBLOCK_CLOCK_INTERRUPTS() +#define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() + +/* +** CPU Related definitions +*/ + +#define _MD_PAUSE_CPU _MD_PauseCPU +#define _MD_CLEANUP_BEFORE_EXIT() +#define _MD_EXIT(status) exit(status) +#define _MD_INIT_CPUS() +#define _MD_INIT_RUNNING_CPU(cpu) _MD_InitRunningCPU(cpu) + +/* +** Process Related definitions +*/ + +extern struct PRProcess * _MD_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); +#define _MD_CREATE_PROCESS _MD_CreateProcess + +extern PRStatus _MD_DetachProcess(PRProcess *process); +#define _MD_DETACH_PROCESS _MD_DetachProcess + +extern PRStatus _MD_WaitProcess(PRProcess *process, PRInt32 *exitCode); +#define _MD_WAIT_PROCESS _MD_WaitProcess + +extern PRStatus _MD_KillProcess(PRProcess *process); +#define _MD_KILL_PROCESS _MD_KillProcess + +/* +** Memory Segments Related definitions +*/ + +#define _MD_INIT_SEGS() + +/* +** Thread Stacks Debugging Related definitions +*/ + +#define _MD_INIT_STACK _MD_InitStack +#define _MD_CLEAR_STACK _MD_ClearStack + +/* +** Locks Related definitions +*/ + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) (PR_SUCCESS) +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) + +/* +** Thread Related definitions +*/ + +NSPR_API(PRThread *) PR_GetPrimaryThread(); + +#if defined(powerc) || defined(__powerc) +#define _MD_GET_PC(_t) (*((PRUint32 *)((_t)->md.jb))) +#define _MD_GET_SP(_t) (*((PRUint32 *)((_t)->md.jb) + 2)) +#define _MD_GET_TOC(_t) (*((PRUint32 *)((_t)->md.jb) + 3)) +#define INIT_STACKPTR(stackTop) ((unsigned char*)stackTop - 128) +#define PR_NUM_GCREGS 70 +#else +#define _MD_GET_PC(_t) (*((PRUint32 *)((_t)->md.jb) + 6)) +#define _MD_GET_SP(_t) (*((PRUint32 *)((_t)->md.jb) + 12)) +#define INIT_STACKPTR(stackTop) ((unsigned char*)stackTop - 4) +#define PR_NUM_GCREGS 13 +#endif + +#define _MD_DEFAULT_STACK_SIZE (58 * 1024) +#define _MD_MINIMUM_STACK_SIZE (58 * 1024) + +/* +** Initialize the thread machine dependent data structure +*/ +extern PRStatus _MD_InitThread(PRThread *thread); +#define _MD_INIT_THREAD _MD_InitThread + +/* +** Clean-up the thread machine dependent data structure +*/ +#define _MD_CLEAN_THREAD(_thread) \ + PR_BEGIN_MACRO \ + PR_DestroyCondVar(_thread->md.asyncIOCVar); \ + PR_DestroyLock(_thread->md.asyncIOLock); \ + PR_END_MACRO + + +/* +** Initialize the thread context preparing it to execute _main. +** *sp = 0 zeros out the sp for the first stack frame so that +** stack walking code can find the top of the stack. +*/ +#if defined(powerc) || defined(__powerc) +#define _MD_INIT_CONTEXT(_thread, _sp, _main, _status) \ + PR_BEGIN_MACRO \ + unsigned char *sp; \ + unsigned long *tvect; \ + long **jb = (_thread)->md.jb; \ + *((PRBool *)_status) = PR_TRUE; \ + (void) setjmp(jb); \ + sp = INIT_STACKPTR(_sp); \ + *sp = 0; \ + (_MD_GET_SP(_thread)) = (long) sp; \ + tvect = (unsigned long *)_main; \ + (_MD_GET_PC(_thread)) = (int) *tvect; \ + (_MD_GET_TOC(_thread)) = (int) *(tvect+1); \ + _thread->no_sched = 0; \ + PR_END_MACRO +#else +#define _MD_INIT_CONTEXT(_thread, _sp, _main, _status) \ + PR_BEGIN_MACRO \ + unsigned char *sp; \ + long **jb = (_thread)->md.jb; \ + *((PRBool *)_status) = PR_TRUE; \ + (void) setjmp(jb); \ + sp = INIT_STACKPTR(_sp); \ + (_MD_GET_SP(_thread)) = (long) sp; \ + (_MD_GET_PC(_thread)) = (int) _main; \ + _thread->no_sched = 0; \ + PR_END_MACRO +#endif + +/* +** Switch away from the current thread context by saving its state and +** calling the thread scheduler. Reload cpu when we come back from the +** context switch because it might have changed. +*/ +/* ResetTimer(); before _PR_Schedule() */ + + +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + PR_ASSERT(_thread->no_sched); \ + if (!setjmp(_thread->md.jb)) { \ + _MD_SET_LAST_THREAD(_thread); \ + if (_PR_MD_CURRENT_CPU()->md.trackScheduling) \ + _PR_MD_CURRENT_CPU()->md.lastThreadSwitch = UpTime(); \ + _PR_Schedule(); \ + } else { \ + PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \ + _MD_LAST_THREAD()->no_sched = 0; \ + } \ + PR_END_MACRO + +/* +** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or +** initialized by _MD_INIT_CONTEXT. +*/ +#define _MD_RESTORE_CONTEXT(_newThread) \ + PR_BEGIN_MACRO \ + long **jb = (_newThread)->md.jb; \ + _MD_SET_CURRENT_THREAD(_newThread); \ + _newThread->no_sched = 1; \ + longjmp(jb, 1); \ + PR_END_MACRO + + +#define _MD_ERRNO() _MD_CURRENT_THREAD()->md.osErrCode + +extern PRStatus _MD_wait(PRThread *thread, PRIntervalTime timeout); +#define _MD_WAIT _MD_wait + +/* +** Combined thread model related definitions +*/ + +#define _MD_CREATE_THREAD(a,b,c,d,e,f) (PR_SUCCESS) +#define _MD_WAKEUP_WAITER(a) +#define _MD_SET_PRIORITY(a,b) + +/* +** File I/O Related definitions +*/ + +extern PRInt32 _PR_MD_WRITE_SYNC(PRFileDesc *fd, void *buf, PRInt32 amount); +#define _PR_MD_WRITE_SYNC _MD_WRITE_SYNC + +struct _MDDir { + short ioVRefNum; + long ioDirID; + short ioFDirIndex; + char *currentEntryName; +}; + +#define PR_DIRECTORY_SEPARATOR '/' +#define PR_DIRECTORY_SEPARATOR_STR "/" +#define PR_PATH_SEPARATOR ':' +#define PR_PATH_SEPARATOR_STR ":" + +typedef enum IOOperation { + READ_ASYNC, + WRITE_ASYNC +} IOOperation; + + +#define _MD_INIT_IO() + +#define _MD_OPEN _MD_Open +#define _MD_OPEN_FILE _MD_Open +#define _MD_CLOSE_FILE FSClose +#define _MD_READ(fd,buf,amount) ReadWriteProc(fd,buf,amount,READ_ASYNC) +#define _MD_WRITE(fd,buf,amount) ReadWriteProc(fd,buf,amount,WRITE_ASYNC) +#define _MD_WRITE_SYNC(fd,buf,amount) WriteSyncProc(fd,buf,amount) +#define _MD_GET_FILE_ERROR() _PR_MD_CURRENT_THREAD()->md.osErrCode +#define _MD_LSEEK _MD_LSeek +#define _MD_FSYNC _MD_FSync + +/* to be implemented */ +#define _MD_LSEEK64(a,b,c) LL_ZERO +#define _MD_GETOPENFILEINFO64(fd,info) -1 +#define _MD_GETFILEINFO64(fd,info) -1 + +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* +** File Manipulation definitions +*/ + +#define _MD_RENAME _MD_Rename +#define _MD_ACCESS _MD_Access + +#define _MD_GETFILEINFO _MD_GetFileInfo +#define _MD_GETOPENFILEINFO _MD_GetOpenFileInfo + +#define _MD_STAT _MD_Stat + +#define _MD_DELETE _MD_Delete + +extern PRStatus _MD_LockFile(PRInt32 osfd); +#define _MD_LOCKFILE _MD_LockFile +extern PRStatus _MD_TLockFile(PRInt32 osfd); +#define _MD_TLOCKFILE _MD_TLockFile +extern PRStatus _MD_UnlockFile(PRInt32 osfd); +#define _MD_UNLOCKFILE _MD_UnlockFile + +/* +** Directory enumeration related definitions +*/ + +extern PRStatus _MD_OpenDir(struct _MDDir *md,const char *name); +#define _MD_OPEN_DIR _MD_OpenDir + +extern char* _MD_ReadDir(struct _MDDir *md,PRIntn flags); +#define _MD_READ_DIR _MD_ReadDir + +#define _MD_CLOSE_DIR _MD_CloseDir + +#define _MD_MKDIR _MD_MkDir +#define _MD_MAKE_DIR _MD_MkDir +#define _MD_RMDIR _MD_Delete + +/* +** Pipe I/O Related definitions (not implemented) +*/ + +#define _MD_PIPEAVAILABLE(fd) -1 + +/* +** Socket I/O Related definitions +*/ + +#if UNIVERSAL_INTERFACES_VERSION >= 0x0330 +/* In Universal Interfaces 3.3 and later, these are enums. */ +#define IP_TTL IP_TTL +#define IP_TOS IP_TOS +#define IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +#define IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP +#define IP_MULTICAST_IF IP_MULTICAST_IF +#define IP_MULTICAST_TTL IP_MULTICAST_TTL +#define IP_MULTICAST_LOOP IP_MULTICAST_LOOP +#define TCP_NODELAY TCP_NODELAY +#define TCP_MAXSEG TCP_MAXSEG +#endif + +#define _MD_SOCKET _MD_socket +#define _MD_BIND _MD_bind +#define _MD_LISTEN _MD_listen +#define _MD_GETSOCKNAME _MD_getsockname + +extern PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen); +#define _MD_GETSOCKOPT _MD_getsockopt + +extern PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen); +#define _MD_SETSOCKOPT _MD_setsockopt + +#define _MD_SOCKETAVAILABLE _MD_socketavailable +#define _MD_ACCEPT _MD_accept +#define _MD_CONNECT _MD_connect +#define _MD_SEND _MD_send +#define _MD_RECV _MD_recv +#define _MD_CLOSE_SOCKET _MD_closesocket +#define _MD_SENDTO _MD_sendto +#define _MD_RECVFROM _MD_recvfrom +#define _MD_PR_POLL _MD_poll +#define _MD_INIT_FILEDESC _MD_initfiledesc +#define _MD_FREE_FILEDESC _MD_freefiledesc +#define _MD_MAKE_NONBLOCK _MD_makenonblock +#define _MD_INIT_FD_INHERITABLE _MD_initfdinheritable +#define _MD_QUERY_FD_INHERITABLE _MD_queryfdinheritable + +#define _MD_GET_SOCKET_ERROR() _PR_MD_CURRENT_THREAD()->md.osErrCode + +#define _PR_MD_MAP_SELECT_ERROR(x) (x) +/* +** Netdb Related definitions +*/ +extern PRStatus _MD_gethostname(char *name, int namelen); +#define _MD_GETHOSTNAME _MD_gethostname +#define _PR_GET_HOST_ADDR_AS_NAME + +/* + XXX _MD_WRITEV, _MD_SHUTDOWN & _MD_GETPEERNAME not done yet!!! +*/ +#define _MD_WRITEV _MD_writev +#define _MD_SHUTDOWN _MD_shutdown +#define _MD_GETPEERNAME _MD_getpeername + + +#ifdef OLD_MACSOCK_LIBRARY +#define _MD_SOCKET macsock_socket +#define _MD_LISTEN macsock_listen +#define _MD_SEND(fd,buf,amount,flags,timeout) macsock_send(fd->secret->md.osfd,buf,amount,flags) +#define _MD_SENDTO(fd,buf,amount,flags,addr,addrlen,timeout) macsock_sendto(fd->secret->md.osfd,buf,amount,flags,(struct sockaddr *)addr,addrlen) +#define _MD_RECV(fd,buf,amount,flags,timeout) macsock_recv(fd->secret->md.osfd,buf,amount,flags) +#define _MD_RECVFROM(fd,buf,amount,flags,addr,addrlen,timeout) macsock_recvfrom(fd->secret->md.osfd,buf,amount,flags,(struct sockaddr *)addr,addrlen) +#define _MD_CLOSE_SOCKET macsock_close +#define _MD_SHUTDOWN(a,b) (0) + +#define _MD_ACCEPT(fd,addr,addrlen,timeout) macsock_accept(fd->secret->md.osfd,(struct sockaddr *)addr,addrlen) +#define _MD_CONNECT(fd,name,namelen,timeout) macsock_connect(fd->secret->md.osfd,(struct sockaddr *)name,namelen) +#define _MD_BIND(fd,name,namelen) macsock_bind(fd->secret->md.osfd,(struct sockaddr *)name,namelen) +#define _MD_GETSOCKNAME(fd,name,namelen) macsock_getsockname(fd->secret->md.osfd,(struct sockaddr *)name,namelen) +#define _MD_GETPEERNAME(fd,name,namelen) macsock_getpeername(fd->secret->md.osfd,(struct sockaddr *)name,namelen) +#define _MD_GETSOCKOPT(fd,level,optname,optval,optlen) macsock_getsockopt(fd->secret->md.osfd,level,optname,optval,optlen) +#define _MD_SETSOCKOPT(fd,level,optname,optval,optlen) macsock_setsockopt(fd->secret->md.osfd,level,optname,optval,optlen) +#define _MD_SOCKETAVAILABLE(fd,bytes) macsock_socketavailable(fd->secret->md.osfd,bytes) +#endif + +/* +** Memory Segements Related definitions +*/ + +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT _MD_AllocSegment +#define _MD_FREE_SEGMENT _MD_FreeSegment + +/* +** Time Related definitions +*/ + +#define _MD_GET_INTERVAL _MD_GetInterval +#define _MD_INTERVAL_PER_SEC() PR_MSEC_PER_SEC +#define _MD_INTERVAL_INIT() + +/* +** Environemnt Related definitions +*/ + +extern char *_MD_GetEnv(const char *name); +#define _MD_GET_ENV _MD_GetEnv + +extern int _MD_PutEnv(const char *variableCopy); +#define _MD_PUT_ENV _MD_PutEnv + +/* +** Following is old stuff to be looked at. +*/ + +#define GCPTR +#define CALLBACK +typedef int (*FARPROC)(); + + +#define MAX_NON_PRIMARY_TIME_SLICES 6 + +extern long gTimeSlicesOnNonPrimaryThread; +extern struct PRThread *gPrimaryThread; + +// Errors not found in the Mac StdCLib +#define EACCES 13 // Permission denied +#define ENOENT -43 // No such file or directory +#define _OS_INVALID_FD_VALUE -1 + +#define STDERR_FILENO 2 + +#if !defined(MAC_NSPR_STANDALONE) +#define PATH_SEPARATOR ':' +#define PATH_SEPARATOR_STR ":" +#define DIRECTORY_SEPARATOR '/' +#define DIRECTORY_SEPARATOR_STR "/" +#endif + +#define UNIX_THIS_DIRECTORY_STR "./" +#define UNIX_PARENT_DIRECTORY_STR "../" + + +// Alias a few names +#define getenv PR_GetEnv +#define putenv _MD_PutEnv + +#if defined(MAC_NSPR_STANDALONE) +typedef unsigned char (*MemoryCacheFlusherProc)(size_t size); +typedef void (*PreAllocationHookProc)(void); + +extern char *strdup(const char *source); + +extern void InstallPreAllocationHook(PreAllocationHookProc newHook); +extern void InstallMemoryCacheFlusher(MemoryCacheFlusherProc newFlusher); +#endif + +extern char *PR_GetDLLSearchPath(void); + +#if defined(MAC_NSPR_STANDALONE) +extern int strcmp(const char *str1, const char *str2); +extern int strcasecmp(const char *str1, const char *str2); +#endif + +extern void MapFullToPartialMacFile(char *); +extern char *MapPartialToFullMacFile(const char *); + +extern void ResetTimer(void); +extern void PR_PeriodicIdle(void); +extern void ActivateTimer(void); +extern void DeactivateTimer(void); +extern void PR_InitMemory(void); + +extern struct hostent *gethostbyaddr(const void *addr, int addrlen, int type); + +extern short GetVolumeRefNumFromName(const char *); + +#include // Needed to get FILE typedef +extern FILE *_OS_FOPEN(const char *filename, const char *mode); +// +// Macintosh only private parts. +// + +#define dprintTrace ";dprintf;doTrace" +#define dprintNoTrace ";dprintf" +extern void dprintf(const char *format, ...); + + +// Entry into the memory system's cache flushing +#if defined(MAC_NSPR_STANDALONE) +extern PRUint8 CallCacheFlushers(size_t blockSize); +#endif + +#if defined(MAC_NSPR_STANDALONE) +extern void* reallocSmaller(void* block, size_t newSize); +#endif + + +/* +** PR_GetSystemInfo related definitions +*/ +#define _PR_SI_SYSNAME "MacOS" +#define _PR_SI_ARCHITECTURE "PowerPC" + +/* + * Memory-mapped files + */ + +struct _MDFileMap { + PRInt8 unused; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +extern void SetLogFileTypeCreator(const char *logFile); +extern int _MD_mac_get_nonblocking_connect_error(PRFileDesc* fd); + + +/* + * Critical section support + */ + +#define MAC_CRITICAL_REGIONS TARGET_CARBON + +#if MAC_CRITICAL_REGIONS + +extern void InitCriticalRegion(); +extern void TermCriticalRegion(); + +extern void EnterCritialRegion(); +extern void LeaveCritialRegion(); + +#define INIT_CRITICAL_REGION() InitCriticalRegion() +#define TERM_CRITICAL_REGION() TermCriticalRegion() + +#define ENTER_CRITICAL_REGION() EnterCritialRegion() +#define LEAVE_CRITICAL_REGION() LeaveCritialRegion() + +#else + +#define INIT_CRITICAL_REGION() +#define TERM_CRITICAL_REGION() + +#define ENTER_CRITICAL_REGION() +#define LEAVE_CRITICAL_REGION() + +#endif + + + +/* + * CPU Idle support + */ + +extern void InitIdleSemaphore(); +extern void TermIdleSemaphore(); + +extern void WaitOnIdleSemaphore(); +extern void SignalIdleSemaphore(); + + +/* + * Atomic operations + */ +#ifdef _PR_HAVE_ATOMIC_OPS + +extern PRInt32 _MD_AtomicSet(PRInt32 *val, PRInt32 newval); + +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_INCREMENT(val) OTAtomicAdd32(1, (SInt32 *)val) +#define _MD_ATOMIC_ADD(ptr, val) OTAtomicAdd32(val, (SInt32 *)ptr) +#define _MD_ATOMIC_DECREMENT(val) OTAtomicAdd32(-1, (SInt32 *)val) +#define _MD_ATOMIC_SET(val, newval) _MD_AtomicSet(val, newval) + +#endif /* _PR_HAVE_ATOMIC_OPS */ + + +#endif /* prmacos_h___ */ diff --git a/nsprpub/pr/include/md/_ncr.cfg b/nsprpub/pr/include/md/_ncr.cfg new file mode 100644 index 00000000000..c8a32bfbf49 --- /dev/null +++ b/nsprpub/pr/include/md/_ncr.cfg @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef NCR +#define NCR +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef 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 + +#define _PR_POLL_BACKCOMPAT + +#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/nsprpub/pr/include/md/_ncr.h b/nsprpub/pr/include/md/_ncr.h new file mode 100644 index 00000000000..d094c2ee50d --- /dev/null +++ b/nsprpub/pr/include/md/_ncr.h @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_unixware_defs_h___ +#define nspr_unixware_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "ncr" +#define _PR_SI_SYSNAME "NCR" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define HAVE_DLL +#define USE_DLFCN +#define _PR_RECV_BROKEN /* recv doesn't work on Unix Domain Sockets */ + +#if !defined (HAVE_STRERROR) +#define HAVE_STRERROR +#endif + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_NO_LARGE_FILES + +#undef HAVE_STACK_GROWING_UP +#define HAVE_NETCONFIG +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define NEED_LOCALTIME_R +#define NEED_GMTIME_R +#define NEED_ASCTIME_R +#define NEED_STRTOK_R +#define NEED_CTIME_R +#define _PR_NEED_STRCASECMP + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _MD_GET_SP(_t) (_t)->md.context[4] +#define _PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_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); \ + _LONGJMP(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures. + * Don't use SVR4 native threads (yet). + */ + +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; +}; + +/* + * 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; +}; + +#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() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#include +#include +#include +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *execptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +#endif /* nspr_ncr_defs_h */ diff --git a/nsprpub/pr/include/md/_nec.cfg b/nsprpub/pr/include/md/_nec.cfg new file mode 100644 index 00000000000..558a5251cb5 --- /dev/null +++ b/nsprpub/pr/include/md/_nec.cfg @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef NEC +#define NEC +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef 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_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 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#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/nsprpub/pr/include/md/_nec.h b/nsprpub/pr/include/md/_nec.h new file mode 100644 index 00000000000..ed7e8a36df0 --- /dev/null +++ b/nsprpub/pr/include/md/_nec.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_nec_defs_h___ +#define nspr_nec_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "nec" +#define _PR_SI_SYSNAME "NEC" +#define _PR_SI_ARCHITECTURE "mips" +#define PR_DLL_SUFFIX ".so" + +#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 NEED_TIME_R +#define NEED_STRFTIME_LOCK +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ST_ATIM_UNION + +#include +#include + +#define PR_NUM_GCREGS NGREG +#define PR_CONTEXT_TYPE ucontext_t + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[CXT_SP] + +/* +** Initialize the thread context preparing it to execute "e(o,a)" +*/ +#define _MD_INIT_CONTEXT(thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + getcontext(CONTEXT(thread)); \ + CONTEXT(thread)->uc_stack.ss_sp = (char*) (thread)->stack->stackBottom; \ + CONTEXT(thread)->uc_stack.ss_size = (thread)->stack->stackSize; \ + _MD_GET_SP(thread) = (greg_t) _sp - 64; \ + makecontext(CONTEXT(thread), _main, 0); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!getcontext(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + ucontext_t *uc = CONTEXT(_thread); \ + uc->uc_mcontext.gregs[CXT_V0] = 1; \ + uc->uc_mcontext.gregs[CXT_A3] = 0; \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + setcontext(uc); \ +} + +/* 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; +}; + +/* + * 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; +}; + +#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_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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_CLEAN_THREAD(_thread) + +#define _MD_SELECT _select +#define _MD_POLL _poll + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#endif /* nspr_nec_defs_h___ */ diff --git a/nsprpub/pr/include/md/_netbsd.cfg b/nsprpub/pr/include/md/_netbsd.cfg new file mode 100644 index 00000000000..cb4e6262227 --- /dev/null +++ b/nsprpub/pr/include/md/_netbsd.cfg @@ -0,0 +1,289 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef NETBSD +#define NETBSD +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) || defined(__arm32__) || defined(__MIPSEL__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#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__) || defined(__MIPSEB__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#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 HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#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 +#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_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/nsprpub/pr/include/md/_netbsd.h b/nsprpub/pr/include/md/_netbsd.h new file mode 100644 index 00000000000..db25bd89389 --- /dev/null +++ b/nsprpub/pr/include/md/_netbsd.h @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_netbsd_defs_h___ +#define nspr_netbsd_defs_h___ + +#include +#include /* for __NetBSD_Version__ */ + +#define PR_LINKER_ARCH "netbsd" +#define _PR_SI_SYSNAME "NetBSD" +#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_v9__) +#define _PR_SI_ARCHITECTURE "sparc64" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__mips__) +#define _PR_SI_ARCHITECTURE "mips" +#elif defined(__arm32__) || defined(__arm__) || defined(__armel__) \ + || defined(__armeb__) +#define _PR_SI_ARCHITECTURE "arm" +#endif + +#if defined(__ELF__) +#define PR_DLL_SUFFIX ".so" +#else +#define PR_DLL_SUFFIX ".so.1.0" +#endif + +#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 _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#if __NetBSD_Version__ >= 105000000 +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#endif + +#if __NetBSD_Version__ >= 106370000 +/* NetBSD 1.6ZK */ +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_INT +#endif + +#define USE_SETJMP + +#ifndef _PR_PTHREADS +#include + +#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(__mips__) +#define JB_SP_INDEX 4 +#elif defined(__alpha__) +#define JB_SP_INDEX 34 +#elif defined(__arm32__) +/* + * On the arm32, the jmpbuf regs underwent a name change 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; +}; + +/* + * 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; +}; + +#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) +#if defined(_PR_POLL_AVAILABLE) +#include +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) +#endif + +#if NetBSD1_3 == 1L +typedef unsigned int nfds_t; +#endif + +#endif /* nspr_netbsd_defs_h___ */ diff --git a/nsprpub/pr/include/md/_nextstep.cfg b/nsprpub/pr/include/md/_nextstep.cfg new file mode 100644 index 00000000000..ce623cb95d1 --- /dev/null +++ b/nsprpub/pr/include/md/_nextstep.cfg @@ -0,0 +1,255 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef NEXTSTEP +#define NEXTSTEP +#endif + +/* Platform specific +*/ +#if defined(__sparc__) + +/* Check these +*/ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 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 +/* Taken from _solaris.cfg +*/ +#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 +/* Taken from _solaris.cfg +*/ +#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 +/* Taken from _solaris.cfg +*/ +#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 + +#define PR_WORDS_PER_DWORD_LOG2 1 + +#elif defined(__m68k__) + +/* Check these +*/ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 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_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 2 +#define PR_ALIGN_OF_LONG 2 +#define PR_ALIGN_OF_INT64 2 +#define PR_ALIGN_OF_FLOAT 2 +#define PR_ALIGN_OF_DOUBLE 2 +#define PR_ALIGN_OF_POINTER 2 + +#define PR_WORDS_PER_DWORD_LOG2 1 + +#elif defined(__i386__) + +/* Check these +*/ +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 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_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 +#define PR_WORDS_PER_DWORD_LOG2 1 +#endif /* defined(__somearch__) */ + + +#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/nsprpub/pr/include/md/_nextstep.h b/nsprpub/pr/include/md/_nextstep.h new file mode 100644 index 00000000000..e7e4c055ab5 --- /dev/null +++ b/nsprpub/pr/include/md/_nextstep.h @@ -0,0 +1,299 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_nextstep_defs_h___ +#define nspr_nextstep_defs_h___ + +#include "prthread.h" + +#include +#include + +/* syscall() is not declared in NEXTSTEP's syscall.h ... +*/ +extern int syscall(int number, ...); + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "nextstep" +#define _PR_SI_SYSNAME "NEXTSTEP" +#if defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__m68k__) +#define _PR_SI_ARCHITECTURE "m68k" +#elif defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#else +error Unknown NEXTSTEP architecture +#endif +#define PR_DLL_SUFFIX ".so" + +#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_WEAK_MALLOC_SYMBOLS + +#define HAVE_DLL +#define USE_MACH_DYLD +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_NO_LARGE_FILES + +#define USE_SETJMP + +#ifndef _PR_PTHREADS + +#include + +#define PR_CONTEXT_TYPE jmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +/* balazs.pataki@sztaki.hu: +** __sparc__ is checked +** __m68k__ is checked +** __i386__ is a guess (one of the two defines should work) +*/ +#if defined(__sparc__) +#define _MD_GET_SP(_th) (_th)->md.context[2] +#elif defined(__m68k__) +#define _MD_GET_SP(_th) (_th)->md.context[2] +#elif defined(__i386__) +/* One of this two must be OK ... try using sc_onstack +*/ +#define _MD_GET_SP(_th) (((struct sigcontext *) (_th)->md.context)->sc_onstack) +//#define _MD_GET_SP(_th) (_th)->md.context[0].sc_esp +#else +error Unknown NEXTSTEP architecture +#endif + +#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 (setjmp(CONTEXT(_thread))) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (int) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_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); \ + longjmp(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; +}; + +/* + * 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; +}; + +#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() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#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) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +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_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) + +/* For writev() */ +#include + +/* signal.h */ +/* balazs.pataki@sztaki.hu: this is stolen from sunos4.h. The things is that +** NEXTSTEP doesn't support these flags for `struct sigaction's sa_flags, so +** I have to fake them ... +*/ +#define SA_RESTART 0 + +/* mmap */ +/* balazs.pataki@sztaki.hu: NEXTSTEP doesn't have mmap, at least not +** publically. We have sys/mman.h, but it doesn't declare mmap(), and +** PROT_NONE is also missing. syscall.h has entries for mmap, munmap, and +** mprotect so I wrap these in nextstep.c as mmap(), munmap() and mprotect() +** and pray for it to work. +** +*/ +caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, + int fildes, off_t off); +int munmap(caddr_t addr, size_t len); +int mprotect(caddr_t addr, size_t len, int prot); + +/* my_mmap() is implemented in nextstep.c and is based on map_fd() of mach. +*/ +caddr_t my_mmap(caddr_t addr, size_t len, int prot, int flags, + int fildes, off_t off); +int my_munmap(caddr_t addr, size_t len); + + +/* string.h +*/ +/* balazs.pataki@sztaki.hu: this is missing so implemenetd in nextstep.c ... +*/ +char *strdup(const char *s1); + +/* unistd.h +*/ +/* balazs.pataki@sztaki.hu: these functions are hidden, though correctly +** implemented in NEXTSTEP. Here I give the declaration for them to be used +** by prmalloc.c, and I have a wrapped syscall() version of them in nextstep.c +*/ +int brk(void *endds); +void *sbrk(int incr); + +#endif /* nspr_nextstep_defs_h___ */ diff --git a/nsprpub/pr/include/md/_nspr_pthread.h b/nsprpub/pr/include/md/_nspr_pthread.h new file mode 100644 index 00000000000..b7a0481ee52 --- /dev/null +++ b/nsprpub/pr/include/md/_nspr_pthread.h @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_pthread_defs_h___ +#define nspr_pthread_defs_h___ + +#include +#include "prthread.h" + +#if defined(PTHREADS_USER) +/* +** Thread Local Storage +*/ +extern pthread_key_t current_thread_key; +extern pthread_key_t current_cpu_key; +extern pthread_key_t last_thread_key; +extern pthread_key_t intsoff_key; + +#define _MD_CURRENT_THREAD() \ + ((struct PRThread *) pthread_getspecific(current_thread_key)) +#define _MD_CURRENT_CPU() \ + ((struct _PRCPU *) pthread_getspecific(current_cpu_key)) +#define _MD_LAST_THREAD() \ + ((struct PRThread *) pthread_getspecific(last_thread_key)) + +#define _MD_SET_CURRENT_THREAD(newval) \ + pthread_setspecific(current_thread_key, (void *)newval) + +#define _MD_SET_CURRENT_CPU(newval) \ + pthread_setspecific(current_cpu_key, (void *)newval) + +#define _MD_SET_LAST_THREAD(newval) \ + pthread_setspecific(last_thread_key, (void *)newval) + +#define _MD_SET_INTSOFF(_val) +#define _MD_GET_INTSOFF() 1 + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + if (SAVE_CONTEXT(_thread)) { \ + (*_main)(); \ + } \ + _MD_SET_THR_SP(_thread, _sp); \ + _thread->no_sched = 0; \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + PR_ASSERT(_thread->no_sched); \ + if (!SAVE_CONTEXT(_thread)) { \ + (_thread)->md.errcode = errno; \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } else { \ + (_MD_LAST_THREAD())->no_sched = 0; \ + } \ + PR_END_MACRO + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + _thread->no_sched = 1; \ + GOTO_CONTEXT(_thread); \ + PR_END_MACRO + + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + jmp_buf jb; + int id; + int errcode; + pthread_t pthread; + pthread_mutex_t pthread_mutex; + pthread_cond_t pthread_cond; + int wait; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + pthread_mutex_t mutex; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + pthread_mutex_t mutex; +}; + +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; + struct _MDCPU_Unix md_unix; +}; + +/* +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +*/ + +extern pthread_mutex_t _pr_heapLock; + +#define _PR_LOCK(lock) pthread_mutex_lock(lock) + +#define _PR_UNLOCK(lock) pthread_mutex_unlock(lock) + + +#define _PR_LOCK_HEAP() { \ + if (_pr_primordialCPU) { \ + _PR_LOCK(_pr_heapLock); \ + } + +#define _PR_UNLOCK_HEAP() if (_pr_primordialCPU) { \ + _PR_UNLOCK(_pr_heapLock); \ + } \ + } + +NSPR_API(PRStatus) _MD_NEW_LOCK(struct _MDLock *md); +NSPR_API(void) _MD_FREE_LOCK(struct _MDLock *lockp); + +#define _MD_LOCK(_lockp) _PR_LOCK(&(_lockp)->mutex) +#define _MD_UNLOCK(_lockp) _PR_UNLOCK(&(_lockp)->mutex) + +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() +#define _MD_CHECK_FOR_EXIT() + +NSPR_API(PRStatus) _MD_InitThread(struct PRThread *thread); +#define _MD_INIT_THREAD _MD_InitThread +#define _MD_INIT_ATTACHED_THREAD _MD_InitThread + +NSPR_API(void) _MD_ExitThread(struct PRThread *thread); +#define _MD_EXIT_THREAD _MD_ExitThread + +NSPR_API(void) _MD_SuspendThread(struct PRThread *thread); +#define _MD_SUSPEND_THREAD _MD_SuspendThread + +NSPR_API(void) _MD_ResumeThread(struct PRThread *thread); +#define _MD_RESUME_THREAD _MD_ResumeThread + +NSPR_API(void) _MD_SuspendCPU(struct _PRCPU *thread); +#define _MD_SUSPEND_CPU _MD_SuspendCPU + +NSPR_API(void) _MD_ResumeCPU(struct _PRCPU *thread); +#define _MD_RESUME_CPU _MD_ResumeCPU + +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_RESUME_ALL() + +NSPR_API(void) _MD_EarlyInit(void); +#define _MD_EARLY_INIT _MD_EarlyInit + +#define _MD_FINAL_INIT _PR_UnixInit + +NSPR_API(void) _MD_InitLocks(void); +#define _MD_INIT_LOCKS _MD_InitLocks + +NSPR_API(void) _MD_CleanThread(struct PRThread *thread); +#define _MD_CLEAN_THREAD _MD_CleanThread + +NSPR_API(PRStatus) _MD_CreateThread( + struct PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +#define _MD_CREATE_THREAD _MD_CreateThread + +extern void _MD_CleanupBeforeExit(void); +#define _MD_CLEANUP_BEFORE_EXIT _MD_CleanupBeforeExit + +NSPR_API(void) _MD_InitRunningCPU(struct _PRCPU *cpu); +#define _MD_INIT_RUNNING_CPU _MD_InitRunningCPU + +/* The _PR_MD_WAIT_LOCK and _PR_MD_WAKEUP_WAITER functions put to sleep and + * awaken a thread which is waiting on a lock or cvar. + */ +NSPR_API(PRStatus) _MD_wait(struct PRThread *, PRIntervalTime timeout); +#define _MD_WAIT _MD_wait + +NSPR_API(PRStatus) _MD_WakeupWaiter(struct PRThread *); +#define _MD_WAKEUP_WAITER _MD_WakeupWaiter + +NSPR_API(void) _MD_SetPriority(struct _MDThread *thread, + PRThreadPriority newPri); +#define _MD_SET_PRIORITY _MD_SetPriority + +#endif /* PTHREADS_USER */ + +#endif /* nspr_pthread_defs_h___ */ diff --git a/nsprpub/pr/include/md/_nto.cfg b/nsprpub/pr/include/md/_nto.cfg new file mode 100644 index 00000000000..b664b7f9e3a --- /dev/null +++ b/nsprpub/pr/include/md/_nto.cfg @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef NTO +#define NTO +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#ifdef __i386__ + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1L +#define PR_BYTES_PER_SHORT 2L +#define PR_BYTES_PER_INT 4L +#define PR_BYTES_PER_INT64 8L +#define PR_BYTES_PER_LONG 4L +#define PR_BYTES_PER_FLOAT 4L +#define PR_BYTES_PER_DOUBLE 8L +#define PR_BYTES_PER_WORD 4L +#define PR_BYTES_PER_DWORD 8L + +#define PR_BITS_PER_BYTE 8L +#define PR_BITS_PER_SHORT 16L +#define PR_BITS_PER_INT 32L +#define PR_BITS_PER_INT64 64L +#define PR_BITS_PER_LONG 32L +#define PR_BITS_PER_FLOAT 32L +#define PR_BITS_PER_DOUBLE 64L +#define PR_BITS_PER_WORD 32L + +#define PR_BITS_PER_BYTE_LOG2 3L +#define PR_BITS_PER_SHORT_LOG2 4L +#define PR_BITS_PER_INT_LOG2 5L +#define PR_BITS_PER_INT64_LOG2 6L +#define PR_BITS_PER_LONG_LOG2 5L +#define PR_BITS_PER_FLOAT_LOG2 5L +#define PR_BITS_PER_DOUBLE_LOG2 6L +#define PR_BITS_PER_WORD_LOG2 5L + +#define PR_ALIGN_OF_SHORT 2L +#define PR_ALIGN_OF_INT 4L +#define PR_ALIGN_OF_LONG 4L +#define PR_ALIGN_OF_INT64 4L +#define PR_ALIGN_OF_FLOAT 4L +#define PR_ALIGN_OF_DOUBLE 4L +#define PR_ALIGN_OF_POINTER 4L +#define PR_ALIGN_OF_WORD 4L + +#define PR_BYTES_PER_WORD_LOG2 2L +#define PR_BYTES_PER_DWORD_LOG2 3L +#define PR_WORDS_PER_DWORD_LOG2 1L + +#else + +#error Undefined CPU Architecture + +#endif + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#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/nsprpub/pr/include/md/_nto.h b/nsprpub/pr/include/md/_nto.h new file mode 100644 index 00000000000..97f4d38fae9 --- /dev/null +++ b/nsprpub/pr/include/md/_nto.h @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_nto_defs_h___ +#define nspr_nto_defs_h___ + +/* +** Internal configuration macros +*/ +#define PR_LINKER_ARCH "nto" +#define _PR_SI_SYSNAME "NTO" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MINIMUM_STACK_SIZE 131072L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#undef _PR_POLL_AVAILABLE +#undef _PR_USE_POLL +#define _PR_HAVE_SOCKADDR_LEN +#undef HAVE_BSD_FLOCK +#define HAVE_FCNTL_FILE_LOCKING +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#define _PR_HAVE_POSIX_SEMAPHORES + +#undef FD_SETSIZE +#define FD_SETSIZE 4096 +#include +#include +#include + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_NEED_STRCASECMP + +#ifndef HAVE_STRERROR +#define HAVE_STRERROR +#endif + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _PR_NUM_GCREGS _JBLEN +#define _MD_GET_SP(_t) (_t)->md.context[7] + +#define CONTEXT(_th) ((_th)->md.context) + + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_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); \ + _LONGJMP(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; +}; + +/* +** 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 +}; + +#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; +}; + +#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_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* +** We wrapped the select() call. _MD_SELECT refers to the built-in, +** unwrapped version. +*/ +#define _MD_SELECT select + +#define SA_RESTART 0 + +#endif /* nspr_nto_defs_h___ */ diff --git a/nsprpub/pr/include/md/_openbsd.cfg b/nsprpub/pr/include/md/_openbsd.cfg new file mode 100644 index 00000000000..dbd7b54535a --- /dev/null +++ b/nsprpub/pr/include/md/_openbsd.cfg @@ -0,0 +1,385 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef OPENBSD +#define OPENBSD +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) || defined(__arm__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#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(__amd64__) + +#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_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#elif defined(__sparc_v9__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#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(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#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 HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#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 +#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_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/nsprpub/pr/include/md/_openbsd.h b/nsprpub/pr/include/md/_openbsd.h new file mode 100644 index 00000000000..8719fe7802b --- /dev/null +++ b/nsprpub/pr/include/md/_openbsd.h @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_openbsd_defs_h___ +#define nspr_openbsd_defs_h___ + +#include + +#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(__amd64__) +#define _PR_SI_ARCHITECTURE "amd64" +#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(__arm__) +#define _PR_SI_ARCHITECTURE "arm" +#endif + +#define PR_DLL_SUFFIX ".so" + +#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 _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE + +#define USE_SETJMP + +#ifndef _PR_PTHREADS +#include + +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#if defined(__i386__) || defined(__sparc__) || defined(__m68k__) +#define JB_SP_INDEX 2 +#elif defined(__powerpc__) +#define JB_SP_INDEX 1 +#elif defined(__alpha__) +#define JB_SP_INDEX 34 +#elif defined(__amd64__) +#define JB_SP_INDEX 6 +#elif defined(__arm__) +#define JB_SP_INDEX 23 +#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; +}; + +/* + * 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; +}; + +#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) +#include +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) + +#if OpenBSD1_3 == 1L +typedef unsigned int nfds_t; +#endif + +#endif /* nspr_openbsd_defs_h___ */ diff --git a/nsprpub/pr/include/md/_openvms.cfg b/nsprpub/pr/include/md/_openvms.cfg new file mode 100644 index 00000000000..ee8a446a033 --- /dev/null +++ b/nsprpub/pr/include/md/_openvms.cfg @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef VMS +#define VMS +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#ifdef IS_64 +#undef IS_64 +#endif + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#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_BYTES_PER_WORD_LOG2 2 +#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_POLL_BACKCOMPAT + +#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/nsprpub/pr/include/md/_openvms.h b/nsprpub/pr/include/md/_openvms.h new file mode 100644 index 00000000000..c2f3dc68f4e --- /dev/null +++ b/nsprpub/pr/include/md/_openvms.h @@ -0,0 +1,333 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** This is the OpenVMS machine dependant configuration file. It is based +** on the OSF/1 machine dependant file. +*/ + +#ifndef nspr_openvms_defs_h___ +#define nspr_openvms_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "OpenVMS" +#define _PR_SI_SYSNAME "OpenVMS" +#ifdef __alpha +#define _PR_SI_ARCHITECTURE "alpha" +#else +#define _PR_SI_ARCHITECTURE "vax" +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 131072L +#define _MD_MINIMUM_STACK_SIZE 131072L + +/* +** This is not defined on OpenVMS. I believe its only used in GC code, and +** isn't that only used in Java? Anyway, for now, let's keep the compiler +** happy. +*/ +#define SA_RESTART 0 + +/* +** OpenVMS doesn't have these in socket.h. +** Does in later versions! +*/ +#if 0 +struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; +#endif + +/* + * 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 + +#undef HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#undef HAVE_BSD_FLOCK + +#define NEED_TIME_R + +#define HAVE_DLL +#define USE_DLFCN + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_NO_LARGE_FILES +#define _PR_STRICT_ADDR_LEN +#define _PR_NEED_SECRET_AF + +/* IPv6 support */ +#ifdef _SOCKADDR_LEN +#define _PR_HAVE_SOCKADDR_LEN +#endif +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#else +#define AF_INET6 26 +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x00000002 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#define AI_V4MAPPED 0x00000010 +#define AI_ALL 0x00000008 +#define AI_ADDRCONFIG 0x00000020 +#endif + +#define _PR_HAVE_MD_SOCKADDR_IN6 +/* if we have a quadword field defined in the structure, then its length */ +/* will be a multiple of 8, and connect() won't accept 32 (it wants 28) */ +struct _md_in6_addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + PRUint32 _S6_u32[4]; + } _S6_un; +}; +struct _md_sockaddr_in6 { + PRUint16 sin6_family; + PRUint16 sin6_port; + PRUint32 sin6_flowinfo; + struct _md_in6_addr sin6_addr; + PRUint32 sin6_scope_id; +}; + +#undef USE_SETJMP + +#include + +/* + * A jmp_buf is actually a struct sigcontext. The sc_sp field of + * struct sigcontext is the stack pointer. + */ +#define _MD_GET_SP(_t) (((struct sigcontext *) (_t)->md.context)->sc_sp) +#define PR_NUM_GCREGS _JBLEN +#define CONTEXT(_th) ((_th)->md.context) + +/* +** I am ifdef'ing these out because that's the way they are in FT. +*/ +#ifndef __VMS + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + (*_main)(); \ + } \ + _MD_GET_SP(_thread) = (long) ((_sp) - 64); \ + _MD_GET_SP(_thread) &= ~15; \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_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); \ + longjmp(CONTEXT(_thread), 1); \ +} + +#endif /* __VMS */ + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + jmp_buf 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; +}; + +/* + * 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; +}; + +#ifndef _PR_PTHREADS +#define _MD_INIT_LOCKS() +#endif +#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() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +extern PRIntervalTime _PR_UNIX_GetInterval(void); +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +void _MD_EarlyInit(void); +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#ifdef _VMS_NOT_YET +NSPR_API(void) _PR_InitThreads( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs); +#endif +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* The following defines unwrapped versions of select() and poll(). */ +extern int __select (int, fd_set *, fd_set *, fd_set *, struct timeval *); +#define _MD_SELECT __select + +#ifndef __VMS +#define _MD_POLL __poll +extern int __poll(struct pollfd filedes[], unsigned int nfds, int timeout); +#endif + +#ifdef __VMS +NSPR_API(void) _PR_InitCPUs(void); +NSPR_API(void) _PR_MD_START_INTERRUPTS(void); +#endif + +/* + * Atomic operations + */ +#include +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_ADD(ptr,val) (__ATOMIC_ADD_LONG(ptr,val) + val) +#define _MD_ATOMIC_INCREMENT(val) (__ATOMIC_INCREMENT_LONG(val) + 1) +#define _MD_ATOMIC_DECREMENT(val) (__ATOMIC_DECREMENT_LONG(val) - 1) +#define _MD_ATOMIC_SET(val, newval) __ATOMIC_EXCH_LONG(val, newval) + +extern int thread_suspend(PRThread *thr_id); +extern int thread_resume(PRThread *thr_id); + +#endif /* nspr_openvms_defs_h___ */ diff --git a/nsprpub/pr/include/md/_os2.cfg b/nsprpub/pr/include/md/_os2.cfg new file mode 100644 index 00000000000..950f8ed47e2 --- /dev/null +++ b/nsprpub/pr/include/md/_os2.cfg @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_PC +#define XP_PC +#endif + +#ifndef XP_OS2 +#define XP_OS2 +#endif + +#ifndef OS2 +#define OS2 +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#ifdef NO_LONG_LONG +#undef HAVE_LONG_LONG +#else +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG 1 +#endif +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#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_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 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 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_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 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 2 + +#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/nsprpub/pr/include/md/_os2.h b/nsprpub/pr/include/md/_os2.h new file mode 100644 index 00000000000..f26fc5b797d --- /dev/null +++ b/nsprpub/pr/include/md/_os2.h @@ -0,0 +1,587 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_os2_defs_h___ +#define nspr_os2_defs_h___ + +#ifndef NO_LONG_LONG +#define INCL_LONGLONG +#endif +#define INCL_DOS +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#define INCL_WIN +#define INCL_WPS +#include +#include + +#include "prio.h" + +#include + +#ifdef XP_OS2_VACPP +/* TODO RAMSEMs need to be written for GCC/EMX */ +#define USE_RAMSEM +#endif + +#ifdef USE_RAMSEM +#pragma pack(4) + +#pragma pack(2) +typedef struct _RAMSEM +{ + ULONG ulTIDPID; + ULONG hevSem; + ULONG cLocks; + USHORT cWaiting; + USHORT cPosts; +} RAMSEM, *PRAMSEM; + +typedef struct _CRITICAL_SECTION +{ + ULONG ulReserved[4]; /* Same size as RAMSEM */ +} CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION; +#pragma pack(4) + +APIRET _Optlink SemRequest486(PRAMSEM, ULONG); +APIRET _Optlink SemReleasex86(PRAMSEM, ULONG); +#endif + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "os2" +#define _PR_SI_SYSNAME "OS2" +#define _PR_SI_ARCHITECTURE "x86" /* XXXMB hardcode for now */ + +#define HAVE_DLL +#define _PR_GLOBAL_THREADS_ONLY +#undef HAVE_THREAD_AFFINITY +#define _PR_HAVE_THREADSAFE_GETHOST +#define _PR_HAVE_ATOMIC_OPS + +#define HANDLE unsigned long +#define HINSTANCE HMODULE + +/* --- Common User-Thread/Native-Thread Definitions --------------------- */ + +/* --- Globals --- */ +extern struct PRLock *_pr_schedLock; + +/* --- Typedefs --- */ +typedef void (*FiberFunc)(void *); + +#define PR_NUM_GCREGS 8 +typedef PRInt32 PR_CONTEXT_TYPE[PR_NUM_GCREGS]; +#define GC_VMBASE 0x40000000 +#define GC_VMLIMIT 0x00FFFFFF +typedef int (*FARPROC)(); + +#define _MD_MAGIC_THREAD 0x22222222 +#define _MD_MAGIC_THREADSTACK 0x33333333 +#define _MD_MAGIC_SEGMENT 0x44444444 +#define _MD_MAGIC_DIR 0x55555555 +#define _MD_MAGIC_CV 0x66666666 + +struct _MDSemaphore { + HEV sem; +}; + +struct _MDCPU { + int unused; +}; + +struct _MDThread { + HEV blocked_sema; /* Threads block on this when waiting + * for IO or CondVar. + */ + PRBool inCVWaitQueue; /* PR_TRUE if the thread is in the + * wait queue of some cond var. + * PR_FALSE otherwise. */ + TID handle; /* OS/2 thread handle */ + void *sp; /* only valid when suspended */ + PRUint32 magic; /* for debugging */ + PR_CONTEXT_TYPE gcContext; /* Thread context for GC */ + struct PRThread *prev, *next; /* used by the cvar wait queue to + * chain the PRThread structures + * together */ +}; + +struct _MDThreadStack { + PRUint32 magic; /* for debugging */ +}; + +struct _MDSegment { + PRUint32 magic; /* for debugging */ +}; + +#undef PROFILE_LOCKS + +struct _MDDir { + HDIR d_hdl; + union { + FILEFINDBUF3 small; + FILEFINDBUF3L large; + } d_entry; + PRBool firstEntry; /* Is this the entry returned + * by FindFirstFile()? */ + PRUint32 magic; /* for debugging */ +}; + +struct _MDCVar { + PRUint32 magic; + struct PRThread *waitHead, *waitTail; /* the wait queue: a doubly- + * linked list of threads + * waiting on this condition + * variable */ + PRIntn nwait; /* number of threads in the + * wait queue */ +}; + +#define _MD_CV_NOTIFIED_LENGTH 6 +typedef struct _MDNotified _MDNotified; +struct _MDNotified { + PRIntn length; /* # of used entries in this + * structure */ + struct { + struct _MDCVar *cv; /* the condition variable notified */ + PRIntn times; /* and the number of times notified */ + struct PRThread *notifyHead; /* list of threads to wake up */ + } cv[_MD_CV_NOTIFIED_LENGTH]; + _MDNotified *link; /* link to another of these, or NULL */ +}; + +struct _MDLock { +#ifdef USE_RAMSEM + CRITICAL_SECTION mutex; /* this is recursive on NT */ +#else + HMTX mutex; /* this is recursive on NT */ +#endif + + /* + * When notifying cvars, there is no point in actually + * waking up the threads waiting on the cvars until we've + * released the lock. So, we temporarily record the cvars. + * When doing an unlock, we'll then wake up the waiting threads. + */ + struct _MDNotified notified; /* array of conditions notified */ +#ifdef PROFILE_LOCKS + PRInt32 hitcount; + PRInt32 misscount; +#endif +}; + +struct _MDFileDesc { + PRInt32 osfd; /* The osfd can come from one of three spaces: + * - For stdin, stdout, and stderr, we are using + * the libc file handle (0, 1, 2), which is an int. + * - For files and pipes, we are using OS/2 handles, + * which is a void*. + * - For sockets, we are using int + */ +}; + +struct _MDProcess { + PID pid; +}; + +/* --- Misc stuff --- */ +#define _MD_GET_SP(thread) (thread)->md.gcContext[6] + +/* --- IO stuff --- */ + +#define _MD_OPEN (_PR_MD_OPEN) +#define _MD_OPEN_FILE (_PR_MD_OPEN) +#define _MD_READ (_PR_MD_READ) +#define _MD_WRITE (_PR_MD_WRITE) +#define _MD_WRITEV (_PR_MD_WRITEV) +#define _MD_LSEEK (_PR_MD_LSEEK) +#define _MD_LSEEK64 (_PR_MD_LSEEK64) +extern PRInt32 _MD_CloseFile(PRInt32 osfd); +#define _MD_CLOSE_FILE _MD_CloseFile +#define _MD_GETFILEINFO (_PR_MD_GETFILEINFO) +#define _MD_GETFILEINFO64 (_PR_MD_GETFILEINFO64) +#define _MD_GETOPENFILEINFO (_PR_MD_GETOPENFILEINFO) +#define _MD_GETOPENFILEINFO64 (_PR_MD_GETOPENFILEINFO64) +#define _MD_STAT (_PR_MD_STAT) +#define _MD_RENAME (_PR_MD_RENAME) +#define _MD_ACCESS (_PR_MD_ACCESS) +#define _MD_DELETE (_PR_MD_DELETE) +#define _MD_MKDIR (_PR_MD_MKDIR) +#define _MD_MAKE_DIR (_PR_MD_MKDIR) +#define _MD_RMDIR (_PR_MD_RMDIR) +#define _MD_LOCKFILE (_PR_MD_LOCKFILE) +#define _MD_TLOCKFILE (_PR_MD_TLOCKFILE) +#define _MD_UNLOCKFILE (_PR_MD_UNLOCKFILE) + +/* --- Socket IO stuff --- */ + +/* The ones that don't map directly may need to be re-visited... */ +#ifdef XP_OS2_VACPP +#define EPIPE EBADF +#define EIO ECONNREFUSED +#endif +#define _MD_EACCES EACCES +#define _MD_EADDRINUSE EADDRINUSE +#define _MD_EADDRNOTAVAIL EADDRNOTAVAIL +#define _MD_EAFNOSUPPORT EAFNOSUPPORT +#define _MD_EAGAIN EWOULDBLOCK +#define _MD_EALREADY EALREADY +#define _MD_EBADF EBADF +#define _MD_ECONNREFUSED ECONNREFUSED +#define _MD_ECONNRESET ECONNRESET +#define _MD_EFAULT SOCEFAULT +#define _MD_EINPROGRESS EINPROGRESS +#define _MD_EINTR EINTR +#define _MD_EINVAL EINVAL +#define _MD_EISCONN EISCONN +#define _MD_ENETUNREACH ENETUNREACH +#define _MD_ENOENT ENOENT +#define _MD_ENOTCONN ENOTCONN +#define _MD_ENOTSOCK ENOTSOCK +#define _MD_EOPNOTSUPP EOPNOTSUPP +#define _MD_EWOULDBLOCK EWOULDBLOCK +#define _MD_GET_SOCKET_ERROR() sock_errno() +#ifndef INADDR_LOOPBACK /* For some reason this is not defined in OS2 tcpip */ +/* #define INADDR_LOOPBACK INADDR_ANY */ +#endif + +#define _MD_INIT_FILEDESC(fd) +extern void _MD_MakeNonblock(PRFileDesc *f); +#define _MD_MAKE_NONBLOCK _MD_MakeNonblock +#define _MD_INIT_FD_INHERITABLE (_PR_MD_INIT_FD_INHERITABLE) +#define _MD_QUERY_FD_INHERITABLE (_PR_MD_QUERY_FD_INHERITABLE) +#define _MD_SHUTDOWN (_PR_MD_SHUTDOWN) +#define _MD_LISTEN _PR_MD_LISTEN +extern PRInt32 _MD_CloseSocket(PRInt32 osfd); +#define _MD_CLOSE_SOCKET _MD_CloseSocket +#define _MD_SENDTO (_PR_MD_SENDTO) +#define _MD_RECVFROM (_PR_MD_RECVFROM) +#ifdef XP_OS2_VACPP +#define _MD_SOCKETPAIR(s, type, proto, sv) -1 +#else +#define _MD_SOCKETPAIR (_PR_MD_SOCKETPAIR) +#endif +#define _MD_GETSOCKNAME (_PR_MD_GETSOCKNAME) +#define _MD_GETPEERNAME (_PR_MD_GETPEERNAME) +#define _MD_GETSOCKOPT (_PR_MD_GETSOCKOPT) +#define _MD_SETSOCKOPT (_PR_MD_SETSOCKOPT) + +#define _MD_FSYNC _PR_MD_FSYNC +#define _MD_SET_FD_INHERITABLE (_PR_MD_SET_FD_INHERITABLE) + +#ifdef _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_INCREMENT _PR_MD_ATOMIC_INCREMENT +#define _MD_ATOMIC_ADD _PR_MD_ATOMIC_ADD +#define _MD_ATOMIC_DECREMENT _PR_MD_ATOMIC_DECREMENT +#define _MD_ATOMIC_SET _PR_MD_ATOMIC_SET +#endif + +#define _MD_INIT_IO (_PR_MD_INIT_IO) +#define _MD_PR_POLL (_PR_MD_PR_POLL) + +#define _MD_SOCKET (_PR_MD_SOCKET) +extern PRInt32 _MD_SocketAvailable(PRFileDesc *fd); +#define _MD_SOCKETAVAILABLE _MD_SocketAvailable +#define _MD_PIPEAVAILABLE _MD_SocketAvailable +#define _MD_CONNECT (_PR_MD_CONNECT) +extern PRInt32 _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, + PRIntervalTime timeout); +#define _MD_ACCEPT _MD_Accept +#define _MD_BIND (_PR_MD_BIND) +#define _MD_RECV (_PR_MD_RECV) +#define _MD_SEND (_PR_MD_SEND) + +/* --- Scheduler stuff --- */ +/* #define _MD_PAUSE_CPU _PR_MD_PAUSE_CPU */ +#define _MD_PAUSE_CPU + +/* --- DIR stuff --- */ +#define PR_DIRECTORY_SEPARATOR '\\' +#define PR_DIRECTORY_SEPARATOR_STR "\\" +#define PR_PATH_SEPARATOR ';' +#define PR_PATH_SEPARATOR_STR ";" +#define _MD_ERRNO() errno +#define _MD_OPEN_DIR (_PR_MD_OPEN_DIR) +#define _MD_CLOSE_DIR (_PR_MD_CLOSE_DIR) +#define _MD_READ_DIR (_PR_MD_READ_DIR) + +/* --- Segment stuff --- */ +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT(seg, size, vaddr) 0 +#define _MD_FREE_SEGMENT(seg) + +/* --- Environment Stuff --- */ +#define _MD_GET_ENV (_PR_MD_GET_ENV) +#define _MD_PUT_ENV (_PR_MD_PUT_ENV) + +/* --- Threading Stuff --- */ +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_INIT_THREAD (_PR_MD_INIT_THREAD) +#define _MD_INIT_ATTACHED_THREAD (_PR_MD_INIT_THREAD) +#define _MD_CREATE_THREAD (_PR_MD_CREATE_THREAD) +#define _MD_YIELD (_PR_MD_YIELD) +#define _MD_SET_PRIORITY (_PR_MD_SET_PRIORITY) +#define _MD_CLEAN_THREAD (_PR_MD_CLEAN_THREAD) +#define _MD_SETTHREADAFFINITYMASK (_PR_MD_SETTHREADAFFINITYMASK) +#define _MD_GETTHREADAFFINITYMASK (_PR_MD_GETTHREADAFFINITYMASK) +#define _MD_EXIT_THREAD (_PR_MD_EXIT_THREAD) +#define _MD_SUSPEND_THREAD (_PR_MD_SUSPEND_THREAD) +#define _MD_RESUME_THREAD (_PR_MD_RESUME_THREAD) +#define _MD_SUSPEND_CPU (_PR_MD_SUSPEND_CPU) +#define _MD_RESUME_CPU (_PR_MD_RESUME_CPU) +#define _MD_WAKEUP_CPUS (_PR_MD_WAKEUP_CPUS) +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_END_RESUME_ALL() + +/* --- Lock stuff --- */ +#define _PR_LOCK _MD_LOCK +#define _PR_UNLOCK _MD_UNLOCK + +#ifdef USE_RAMSEM +#define _MD_NEW_LOCK (_PR_MD_NEW_LOCK) +#define _MD_FREE_LOCK(lock) (DosCloseEventSem(((PRAMSEM)(&((lock)->mutex)))->hevSem)) +#define _MD_LOCK(lock) (SemRequest486(&((lock)->mutex), -1)) +#define _MD_TEST_AND_LOCK(lock) (SemRequest486(&((lock)->mutex), -1),0) +#define _MD_UNLOCK(lock) \ + PR_BEGIN_MACRO \ + if (0 != (lock)->notified.length) { \ + md_UnlockAndPostNotifies((lock), NULL, NULL); \ + } else { \ + SemReleasex86( &(lock)->mutex, 0 ); \ + } \ + PR_END_MACRO +#else +#define _MD_NEW_LOCK (_PR_MD_NEW_LOCK) +#define _MD_FREE_LOCK(lock) (DosCloseMutexSem((lock)->mutex)) +#define _MD_LOCK(lock) (DosRequestMutexSem((lock)->mutex, SEM_INDEFINITE_WAIT)) +#define _MD_TEST_AND_LOCK(lock) (DosRequestMutexSem((lock)->mutex, SEM_INDEFINITE_WAIT),0) +#define _MD_UNLOCK (_PR_MD_UNLOCK) +#endif + +/* --- lock and cv waiting --- */ +#define _MD_WAIT (_PR_MD_WAIT) +#define _MD_WAKEUP_WAITER (_PR_MD_WAKEUP_WAITER) + +/* --- CVar ------------------- */ +#define _MD_WAIT_CV (_PR_MD_WAIT_CV) +#define _MD_NEW_CV (_PR_MD_NEW_CV) +#define _MD_FREE_CV (_PR_MD_FREE_CV) +#define _MD_NOTIFY_CV (_PR_MD_NOTIFY_CV ) +#define _MD_NOTIFYALL_CV (_PR_MD_NOTIFYALL_CV) + + /* XXXMB- the IOQ stuff is certainly not working correctly yet. */ +/* extern struct _MDLock _pr_ioq_lock; */ +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + + +/* --- Initialization stuff --- */ +#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) +#define _MD_FINAL_INIT() +#define _MD_INIT_CPUS() +#define _MD_INIT_RUNNING_CPU(cpu) + +struct PRProcess; +struct PRProcessAttr; + +#define _MD_CREATE_PROCESS _PR_CreateOS2Process +extern struct PRProcess * _PR_CreateOS2Process( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _PR_DetachOS2Process +extern PRStatus _PR_DetachOS2Process(struct PRProcess *process); + +/* --- Wait for a child process to terminate --- */ +#define _MD_WAIT_PROCESS _PR_WaitOS2Process +extern PRStatus _PR_WaitOS2Process(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _PR_KillOS2Process +extern PRStatus _PR_KillOS2Process(struct PRProcess *process); + +#define _MD_CLEANUP_BEFORE_EXIT() +#define _MD_EXIT (_PR_MD_EXIT) +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + PR_END_MACRO +#define _MD_SWITCH_CONTEXT +#define _MD_RESTORE_CONTEXT + +/* --- Intervals --- */ +#define _MD_INTERVAL_INIT (_PR_MD_INTERVAL_INIT) +#define _MD_GET_INTERVAL (_PR_MD_GET_INTERVAL) +#define _MD_INTERVAL_PER_SEC (_PR_MD_INTERVAL_PER_SEC) +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/* --- Native-Thread Specific Definitions ------------------------------- */ + +typedef struct __NSPR_TLS +{ + struct PRThread *_pr_thread_last_run; + struct PRThread *_pr_currentThread; + struct _PRCPU *_pr_currentCPU; +} _NSPR_TLS; + +extern _NSPR_TLS* pThreadLocalStorage; +NSPR_API(void) _PR_MD_ENSURE_TLS(void); + +#define _MD_GET_ATTACHED_THREAD() pThreadLocalStorage->_pr_currentThread +extern struct PRThread * _MD_CURRENT_THREAD(void); +#define _MD_SET_CURRENT_THREAD(_thread) _PR_MD_ENSURE_TLS(); pThreadLocalStorage->_pr_currentThread = (_thread) + +#define _MD_LAST_THREAD() pThreadLocalStorage->_pr_thread_last_run +#define _MD_SET_LAST_THREAD(_thread) _PR_MD_ENSURE_TLS(); pThreadLocalStorage->_pr_thread_last_run = (_thread) + +#define _MD_CURRENT_CPU() pThreadLocalStorage->_pr_currentCPU +#define _MD_SET_CURRENT_CPU(_cpu) _PR_MD_ENSURE_TLS(); pThreadLocalStorage->_pr_currentCPU = (_cpu) + +/* lth. #define _MD_SET_INTSOFF(_val) (_pr_ints_off = (_val)) */ +/* lth. #define _MD_GET_INTSOFF() _pr_ints_off */ +/* lth. #define _MD_INCREMENT_INTSOFF() (_pr_ints_off++) */ +/* lth. #define _MD_DECREMENT_INTSOFF() (_pr_ints_off--) */ + +/* --- Scheduler stuff --- */ +#define LOCK_SCHEDULER() 0 +#define UNLOCK_SCHEDULER() 0 +#define _PR_LockSched() 0 +#define _PR_UnlockSched() 0 + +/* --- Initialization stuff --- */ +#define _MD_INIT_LOCKS() + +/* --- Stack stuff --- */ +#define _MD_INIT_STACK(stack, redzone) +#define _MD_CLEAR_STACK(stack) + +/* --- Memory-mapped files stuff --- not implemented on OS/2 */ + +struct _MDFileMap { + PRInt8 unused; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +/* Some stuff for setting up thread contexts */ +typedef ULONG DWORD, *PDWORD; + +/* The following definitions and two structures are new in OS/2 Warp 4.0. + */ +#ifndef CONTEXT_CONTROL +#define CONTEXT_CONTROL 0x00000001 +#define CONTEXT_INTEGER 0x00000002 +#define CONTEXT_SEGMENTS 0x00000004 +#define CONTEXT_FLOATING_POINT 0x00000008 +#define CONTEXT_FULL 0x0000000F + +#pragma pack(2) +typedef struct _FPREG { + ULONG losig; /* Low 32-bits of the significand. */ + ULONG hisig; /* High 32-bits of the significand. */ + USHORT signexp; /* Sign and exponent. */ +} FPREG; +typedef struct _CONTEXTRECORD { + ULONG ContextFlags; + ULONG ctx_env[7]; + FPREG ctx_stack[8]; + ULONG ctx_SegGs; /* GS register. */ + ULONG ctx_SegFs; /* FS register. */ + ULONG ctx_SegEs; /* ES register. */ + ULONG ctx_SegDs; /* DS register. */ + ULONG ctx_RegEdi; /* EDI register. */ + ULONG ctx_RegEsi; /* ESI register. */ + ULONG ctx_RegEax; /* EAX register. */ + ULONG ctx_RegEbx; /* EBX register. */ + ULONG ctx_RegEcx; /* ECX register. */ + ULONG ctx_RegEdx; /* EDX register. */ + ULONG ctx_RegEbp; /* EBP register. */ + ULONG ctx_RegEip; /* EIP register. */ + ULONG ctx_SegCs; /* CS register. */ + ULONG ctx_EFlags; /* EFLAGS register. */ + ULONG ctx_RegEsp; /* ESP register. */ + ULONG ctx_SegSs; /* SS register. */ +} CONTEXTRECORD, *PCONTEXTRECORD; +#pragma pack() +#endif + +extern APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD); + +/* +#define _pr_tid (((PTIB2)_getTIBvalue(offsetof(TIB, tib_ptib2)))->tib2_ultid) +#define _pr_current_Thread (_system_tls[_pr_tid-1].__pr_current_thread) +*/ + +/* Some simple mappings of Windows API's to OS/2 API's to make our lives a + * little bit easier. Only add one here if it is a DIRECT mapping. We are + * not emulating anything. Just mapping. + */ +#define FreeLibrary(x) DosFreeModule((HMODULE)x) +#define OutputDebugString(x) + +extern int _MD_os2_get_nonblocking_connect_error(int osfd); + +#endif /* nspr_os2_defs_h___ */ diff --git a/nsprpub/pr/include/md/_os2_errors.h b/nsprpub/pr/include/md/_os2_errors.h new file mode 100644 index 00000000000..628b058a3a9 --- /dev/null +++ b/nsprpub/pr/include/md/_os2_errors.h @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_os2_errors_h___ +#define nspr_os2_errors_h___ + +#include "md/_os2.h" +#ifndef assert + #include +#endif + +NSPR_API(void) _MD_os2_map_default_error(PRInt32 err); +#define _PR_MD_MAP_DEFAULT_ERROR _MD_os2_map_default_error + +NSPR_API(void) _MD_os2_map_opendir_error(PRInt32 err); +#define _PR_MD_MAP_OPENDIR_ERROR _MD_os2_map_opendir_error + +NSPR_API(void) _MD_os2_map_closedir_error(PRInt32 err); +#define _PR_MD_MAP_CLOSEDIR_ERROR _MD_os2_map_closedir_error + +NSPR_API(void) _MD_os2_readdir_error(PRInt32 err); +#define _PR_MD_MAP_READDIR_ERROR _MD_os2_readdir_error + +NSPR_API(void) _MD_os2_map_delete_error(PRInt32 err); +#define _PR_MD_MAP_DELETE_ERROR _MD_os2_map_delete_error + +NSPR_API(void) _MD_os2_map_stat_error(PRInt32 err); +#define _PR_MD_MAP_STAT_ERROR _MD_os2_map_stat_error + +NSPR_API(void) _MD_os2_map_fstat_error(PRInt32 err); +#define _PR_MD_MAP_FSTAT_ERROR _MD_os2_map_fstat_error + +NSPR_API(void) _MD_os2_map_rename_error(PRInt32 err); +#define _PR_MD_MAP_RENAME_ERROR _MD_os2_map_rename_error + +NSPR_API(void) _MD_os2_map_access_error(PRInt32 err); +#define _PR_MD_MAP_ACCESS_ERROR _MD_os2_map_access_error + +NSPR_API(void) _MD_os2_map_mkdir_error(PRInt32 err); +#define _PR_MD_MAP_MKDIR_ERROR _MD_os2_map_mkdir_error + +NSPR_API(void) _MD_os2_map_rmdir_error(PRInt32 err); +#define _PR_MD_MAP_RMDIR_ERROR _MD_os2_map_rmdir_error + +NSPR_API(void) _MD_os2_map_read_error(PRInt32 err); +#define _PR_MD_MAP_READ_ERROR _MD_os2_map_read_error + +NSPR_API(void) _MD_os2_map_transmitfile_error(PRInt32 err); +#define _PR_MD_MAP_TRANSMITFILE_ERROR _MD_os2_map_transmitfile_error + +NSPR_API(void) _MD_os2_map_write_error(PRInt32 err); +#define _PR_MD_MAP_WRITE_ERROR _MD_os2_map_write_error + +NSPR_API(void) _MD_os2_map_lseek_error(PRInt32 err); +#define _PR_MD_MAP_LSEEK_ERROR _MD_os2_map_lseek_error + +NSPR_API(void) _MD_os2_map_fsync_error(PRInt32 err); +#define _PR_MD_MAP_FSYNC_ERROR _MD_os2_map_fsync_error + +NSPR_API(void) _MD_os2_map_close_error(PRInt32 err); +#define _PR_MD_MAP_CLOSE_ERROR _MD_os2_map_close_error + +NSPR_API(void) _MD_os2_map_socket_error(PRInt32 err); +#define _PR_MD_MAP_SOCKET_ERROR _MD_os2_map_socket_error + +NSPR_API(void) _MD_os2_map_recv_error(PRInt32 err); +#define _PR_MD_MAP_RECV_ERROR _MD_os2_map_recv_error + +NSPR_API(void) _MD_os2_map_recvfrom_error(PRInt32 err); +#define _PR_MD_MAP_RECVFROM_ERROR _MD_os2_map_recvfrom_error + +NSPR_API(void) _MD_os2_map_send_error(PRInt32 err); +#define _PR_MD_MAP_SEND_ERROR _MD_os2_map_send_error + +NSPR_API(void) _MD_os2_map_sendto_error(PRInt32 err); +#define _PR_MD_MAP_SENDTO_ERROR _MD_os2_map_sendto_error + +NSPR_API(void) _MD_os2_map_writev_error(int err); +#define _PR_MD_MAP_WRITEV_ERROR _MD_os2_map_writev_error + +NSPR_API(void) _MD_os2_map_accept_error(PRInt32 err); +#define _PR_MD_MAP_ACCEPT_ERROR _MD_os2_map_accept_error + +NSPR_API(void) _MD_os2_map_acceptex_error(PRInt32 err); +#define _PR_MD_MAP_ACCEPTEX_ERROR _MD_os2_map_acceptex_error + +NSPR_API(void) _MD_os2_map_connect_error(PRInt32 err); +#define _PR_MD_MAP_CONNECT_ERROR _MD_os2_map_connect_error + +NSPR_API(void) _MD_os2_map_bind_error(PRInt32 err); +#define _PR_MD_MAP_BIND_ERROR _MD_os2_map_bind_error + +NSPR_API(void) _MD_os2_map_listen_error(PRInt32 err); +#define _PR_MD_MAP_LISTEN_ERROR _MD_os2_map_listen_error + +NSPR_API(void) _MD_os2_map_shutdown_error(PRInt32 err); +#define _PR_MD_MAP_SHUTDOWN_ERROR _MD_os2_map_shutdown_error + +#ifndef XP_OS2_VACPP +NSPR_API(void) _MD_os2_map_socketpair_error(int err); +#define _PR_MD_MAP_SOCKETPAIR_ERROR _MD_os2_map_socketpair_error +#endif + +NSPR_API(void) _MD_os2_map_getsockname_error(PRInt32 err); +#define _PR_MD_MAP_GETSOCKNAME_ERROR _MD_os2_map_getsockname_error + +NSPR_API(void) _MD_os2_map_getpeername_error(PRInt32 err); +#define _PR_MD_MAP_GETPEERNAME_ERROR _MD_os2_map_getpeername_error + +NSPR_API(void) _MD_os2_map_getsockopt_error(PRInt32 err); +#define _PR_MD_MAP_GETSOCKOPT_ERROR _MD_os2_map_getsockopt_error + +NSPR_API(void) _MD_os2_map_setsockopt_error(PRInt32 err); +#define _PR_MD_MAP_SETSOCKOPT_ERROR _MD_os2_map_setsockopt_error + +NSPR_API(void) _MD_os2_map_open_error(PRInt32 err); +#define _PR_MD_MAP_OPEN_ERROR _MD_os2_map_open_error + +NSPR_API(void) _MD_os2_map_gethostname_error(PRInt32 err); +#define _PR_MD_MAP_GETHOSTNAME_ERROR _MD_os2_map_gethostname_error + +NSPR_API(void) _MD_os2_map_select_error(PRInt32 err); +#define _PR_MD_MAP_SELECT_ERROR _MD_os2_map_select_error + +NSPR_API(void) _MD_os2_map_lockf_error(int err); +#define _PR_MD_MAP_LOCKF_ERROR _MD_os2_map_lockf_error + +#endif /* nspr_os2_errors_h___ */ diff --git a/nsprpub/pr/include/md/_osf1.cfg b/nsprpub/pr/include/md/_osf1.cfg new file mode 100644 index 00000000000..dcd8d308e8b --- /dev/null +++ b/nsprpub/pr/include/md/_osf1.cfg @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef OSF1 +#define OSF1 +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#ifndef IS_64 +#define IS_64 +#endif + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#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 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_POLL_BACKCOMPAT + +#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/nsprpub/pr/include/md/_osf1.h b/nsprpub/pr/include/md/_osf1.h new file mode 100644 index 00000000000..9767b8731f3 --- /dev/null +++ b/nsprpub/pr/include/md/_osf1.h @@ -0,0 +1,255 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_osf1_defs_h___ +#define nspr_osf1_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "osf" +#define _PR_SI_SYSNAME "OSF" +#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 +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#define HAVE_BSD_FLOCK + +#define NEED_TIME_R +#define USE_DLFCN + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_HAVE_LARGE_OFF_T +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#else +#define AF_INET6 26 +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x00000002 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#define AI_V4MAPPED 0x00000010 +#define AI_ALL 0x00000008 +#define AI_ADDRCONFIG 0x00000020 +#endif +#define _PR_HAVE_POSIX_SEMAPHORES +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY + +#define USE_SETJMP + +#include + +/* + * A jmp_buf is actually a struct sigcontext. The sc_sp field of + * struct sigcontext is the stack pointer. + */ +#define _MD_GET_SP(_t) (((struct sigcontext *) (_t)->md.context)->sc_sp) +#define PR_NUM_GCREGS _JBLEN +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + (*_main)(); \ + } \ + _MD_GET_SP(_thread) = (long) ((_sp) - 64); \ + _MD_GET_SP(_thread) &= ~15; \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_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); \ + longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + jmp_buf 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; +}; + +/* + * 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; +}; + +#ifndef _PR_PTHREADS +#define _MD_INIT_LOCKS() +#endif +#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() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* The following defines unwrapped versions of select() and poll(). */ +#include +extern int __select (int, fd_set *, fd_set *, fd_set *, struct timeval *); +#define _MD_SELECT __select + +#include +#define _MD_POLL __poll +extern int __poll(struct pollfd filedes[], unsigned int nfds, int timeout); + +/* + * Atomic operations + */ +#ifdef OSF1_HAVE_MACHINE_BUILTINS_H +#include +#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 /* OSF1_HAVE_MACHINE_BUILTINS_H */ + +#endif /* nspr_osf1_defs_h___ */ diff --git a/nsprpub/pr/include/md/_pcos.h b/nsprpub/pr/include/md/_pcos.h new file mode 100644 index 00000000000..64bd8405d9f --- /dev/null +++ b/nsprpub/pr/include/md/_pcos.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prpcos_h___ +#define prpcos_h___ + +#define PR_DLL_SUFFIX ".dll" + +#include + +#define DIRECTORY_SEPARATOR '\\' +#define DIRECTORY_SEPARATOR_STR "\\" +#define PATH_SEPARATOR ';' + +#ifdef WIN16 +#define GCPTR __far +#else +#define GCPTR +#endif + +/* +** Routines for processing command line arguments +*/ +PR_BEGIN_EXTERN_C +#ifndef XP_OS2_EMX +extern char *optarg; +extern int optind; +extern int getopt(int argc, char **argv, char *spec); +#endif +PR_END_EXTERN_C + + +/* +** Definitions of directory structures amd functions +** These definitions are from: +** +*/ +#ifdef XP_OS2_EMX +#include +#endif +#include +#include +#include /* O_BINARY */ + +#ifdef OS2 +extern PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen); +#define _MD_GETHOSTNAME _MD_OS2GetHostName +#else +extern PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen); +#define _MD_GETHOSTNAME _MD_WindowsGetHostName +extern PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen); +#define _MD_GETSYSINFO _MD_WindowsGetSysInfo +#endif + +#endif /* prpcos_h___ */ diff --git a/nsprpub/pr/include/md/_pth.h b/nsprpub/pr/include/md/_pth.h new file mode 100644 index 00000000000..46c8670dd06 --- /dev/null +++ b/nsprpub/pr/include/md/_pth.h @@ -0,0 +1,304 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_pth_defs_h_ +#define nspr_pth_defs_h_ + +/* +** Appropriate definitions of entry points not used in a pthreads world +*/ +#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 + * changes and small differences, so macros usually do the trick + */ +#ifdef _PR_DCETHREADS +#define _PT_PTHREAD_MUTEXATTR_INIT pthread_mutexattr_create +#define _PT_PTHREAD_MUTEXATTR_DESTROY pthread_mutexattr_delete +#define _PT_PTHREAD_MUTEX_INIT(m, a) pthread_mutex_init(&(m), a) +#define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (0 == pthread_mutex_trylock(&(m))) +#define _PT_PTHREAD_CONDATTR_INIT pthread_condattr_create +#define _PT_PTHREAD_COND_INIT(m, a) pthread_cond_init(&(m), a) +#define _PT_PTHREAD_CONDATTR_DESTROY pthread_condattr_delete + +/* Notes about differences between DCE threads and pthreads 10: + * 1. pthread_mutex_trylock returns 1 when it locks the mutex + * 0 when it does not. The latest pthreads has a set of errno-like + * return values. + * 2. return values from pthread_cond_timedwait are different. + * + * + * + */ +#elif defined(BSDI) +/* + * Mutex and condition attributes are not supported. The attr + * argument to pthread_mutex_init() and pthread_cond_init() must + * be passed as NULL. + * + * The memset calls in _PT_PTHREAD_MUTEX_INIT and _PT_PTHREAD_COND_INIT + * are to work around BSDI's using a single bit to indicate a mutex + * or condition variable is initialized. This entire BSDI section + * will go away when BSDI releases updated threads libraries for + * BSD/OS 3.1 and 4.0. + */ +#define _PT_PTHREAD_MUTEXATTR_INIT(x) 0 +#define _PT_PTHREAD_MUTEXATTR_DESTROY(x) /* */ +#define _PT_PTHREAD_MUTEX_INIT(m, a) (memset(&(m), 0, sizeof(m)), \ + pthread_mutex_init(&(m), NULL)) +#define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (EBUSY == pthread_mutex_trylock(&(m))) +#define _PT_PTHREAD_CONDATTR_INIT(x) 0 +#define _PT_PTHREAD_CONDATTR_DESTROY(x) /* */ +#define _PT_PTHREAD_COND_INIT(m, a) (memset(&(m), 0, sizeof(m)), \ + pthread_cond_init(&(m), NULL)) +#else +#define _PT_PTHREAD_MUTEXATTR_INIT pthread_mutexattr_init +#define _PT_PTHREAD_MUTEXATTR_DESTROY pthread_mutexattr_destroy +#define _PT_PTHREAD_MUTEX_INIT(m, a) pthread_mutex_init(&(m), &(a)) +#if defined(FREEBSD) +#define _PT_PTHREAD_MUTEX_IS_LOCKED(m) pt_pthread_mutex_is_locked(&(m)) +#else +#define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (EBUSY == pthread_mutex_trylock(&(m))) +#endif +#if defined(DARWIN) +#define _PT_PTHREAD_CONDATTR_INIT(x) 0 +#else +#define _PT_PTHREAD_CONDATTR_INIT pthread_condattr_init +#endif +#define _PT_PTHREAD_CONDATTR_DESTROY pthread_condattr_destroy +#define _PT_PTHREAD_COND_INIT(m, a) pthread_cond_init(&(m), &(a)) +#endif + +/* The pthreads standard does not specify an invalid value for the + * pthread_t handle. (0 is usually an invalid pthread identifier + * but there are exceptions, for example, DG/UX.) These macros + * define a way to set the handle to or compare the handle with an + * invalid identifier. These macros are not portable and may be + * more of a problem as we adapt to more pthreads implementations. + * They are only used in the PRMonitor functions. Do not use them + * in new code. + * + * Unfortunately some of our clients depend on certain properties + * of our PRMonitor implementation, preventing us from replacing + * it by a portable implementation. + * - High-performance servers like the fact that PR_EnterMonitor + * only calls PR_Lock and PR_ExitMonitor only calls PR_Unlock. + * (A portable implementation would use a PRLock and a PRCondVar + * to implement the recursive lock in a monitor and call both + * PR_Lock and PR_Unlock in PR_EnterMonitor and PR_ExitMonitor.) + * Unfortunately this forces us to read the monitor owner field + * without holding a lock. + * - One way to make it safe to read the monitor owner field + * without holding a lock is to make that field a PRThread* + * (one should be able to read a pointer with a single machine + * instruction). However, PR_GetCurrentThread calls calloc if + * it is called by a thread that was not created by NSPR. The + * malloc tracing tools in the Mozilla client use PRMonitor for + * locking in their malloc, calloc, and free functions. If + * PR_EnterMonitor calls any of these functions, infinite + * recursion ensues. + */ +#if defined(_PR_DCETHREADS) +#define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t) \ + memset(&(t), 0, sizeof(pthread_t)) +#define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t) \ + (!memcmp(&(t), &pt_zero_tid, sizeof(pthread_t))) +#define _PT_PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st) +#elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(SOLARIS) \ + || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \ + || defined(HPUX) || defined(FREEBSD) \ + || defined(NETBSD) || defined(OPENBSD) || defined(BSDI) \ + || defined(VMS) || defined(NTO) || defined(DARWIN) \ + || defined(UNIXWARE) || defined(RISCOS) +#ifdef __GNU__ +/* Hurd pthreads don't have an invalid value for pthread_t. -- rmh */ +#error Using Hurd pthreads +#endif +#define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t) (t) = 0 +#define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t) (t) == 0 +#define _PT_PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st) +#else +#error "pthreads is not supported for this architecture" +#endif + +#if defined(_PR_DCETHREADS) +#define _PT_PTHREAD_ATTR_INIT pthread_attr_create +#define _PT_PTHREAD_ATTR_DESTROY pthread_attr_delete +#define _PT_PTHREAD_CREATE(t, a, f, r) pthread_create(t, a, f, r) +#define _PT_PTHREAD_KEY_CREATE pthread_keycreate +#define _PT_PTHREAD_ATTR_SETSCHEDPOLICY pthread_attr_setsched +#define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) \ + (*(s) = pthread_attr_getstacksize(*(a)), 0) +#define _PT_PTHREAD_GETSPECIFIC(k, r) \ + pthread_getspecific((k), (pthread_addr_t *) &(r)) +#elif defined(_PR_PTHREADS) +#define _PT_PTHREAD_ATTR_INIT pthread_attr_init +#define _PT_PTHREAD_ATTR_DESTROY pthread_attr_destroy +#define _PT_PTHREAD_CREATE(t, a, f, r) pthread_create(t, &a, f, r) +#define _PT_PTHREAD_KEY_CREATE pthread_key_create +#define _PT_PTHREAD_ATTR_SETSCHEDPOLICY pthread_attr_setschedpolicy +#define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) pthread_attr_getstacksize(a, s) +#define _PT_PTHREAD_GETSPECIFIC(k, r) (r) = pthread_getspecific(k) +#else +#error "Cannot determine pthread strategy" +#endif + +#if defined(_PR_DCETHREADS) +#define _PT_PTHREAD_EXPLICIT_SCHED _PT_PTHREAD_DEFAULT_SCHED +#endif + +/* + * pthread_mutex_trylock returns different values in DCE threads and + * pthreads. + */ +#if defined(_PR_DCETHREADS) +#define PT_TRYLOCK_SUCCESS 1 +#define PT_TRYLOCK_BUSY 0 +#else +#define PT_TRYLOCK_SUCCESS 0 +#define PT_TRYLOCK_BUSY EBUSY +#endif + +/* + * These platforms don't have sigtimedwait() + */ +#if (defined(AIX) && !defined(AIX4_3_PLUS)) \ + || defined(LINUX) || defined(__GNU__)|| defined(__GLIBC__) \ + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ + || defined(BSDI) || defined(VMS) || defined(UNIXWARE) \ + || defined(DARWIN) +#define PT_NO_SIGTIMEDWAIT +#endif + +#if defined(OSF1) || defined(VMS) +#define PT_PRIO_MIN PRI_OTHER_MIN +#define PT_PRIO_MAX PRI_OTHER_MAX +#elif defined(IRIX) +#include +#define PT_PRIO_MIN PX_PRIO_MIN +#define PT_PRIO_MAX PX_PRIO_MAX +#elif defined(AIX) +#include +#include +#ifndef PTHREAD_CREATE_JOINABLE +#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED +#endif +#define PT_PRIO_MIN DEFAULT_PRIO +#define PT_PRIO_MAX DEFAULT_PRIO +#elif defined(HPUX) + +#if defined(_PR_DCETHREADS) +#define PT_PRIO_MIN PRI_OTHER_MIN +#define PT_PRIO_MAX PRI_OTHER_MAX +#else /* defined(_PR_DCETHREADS) */ +#include +#define PT_PRIO_MIN sched_get_priority_min(SCHED_OTHER) +#define PT_PRIO_MAX sched_get_priority_max(SCHED_OTHER) +#endif /* defined(_PR_DCETHREADS) */ + +#elif defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \ + || defined(FREEBSD) +#define PT_PRIO_MIN sched_get_priority_min(SCHED_OTHER) +#define PT_PRIO_MAX sched_get_priority_max(SCHED_OTHER) +#elif defined(NTO) +/* + * Neutrino has functions that return the priority range but + * they return invalid numbers, so I just hard coded these here + * for now. Jerry.Kirk@Nexarecorp.com + */ +#define PT_PRIO_MIN 0 +#define PT_PRIO_MAX 30 +#elif defined(SOLARIS) +/* + * Solaris doesn't seem to have macros for the min/max priorities. + * The range of 0-127 is mentioned in the pthread_setschedparam(3T) + * man pages, and pthread_setschedparam indeed allows 0-127. However, + * pthread_attr_setschedparam does not allow 0; it allows 1-127. + */ +#define PT_PRIO_MIN 1 +#define PT_PRIO_MAX 127 +#elif defined(OPENBSD) +#define PT_PRIO_MIN 0 +#define PT_PRIO_MAX 31 +#elif defined(NETBSD) \ + || defined(BSDI) || defined(DARWIN) || defined(UNIXWARE) \ + || defined(RISCOS) /* XXX */ +#define PT_PRIO_MIN 0 +#define PT_PRIO_MAX 126 +#else +#error "pthreads is not supported for this architecture" +#endif + +/* + * The _PT_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 _PT_PTHREAD_YIELD() pthread_yield() +#elif defined(OSF1) || defined(VMS) +/* + * sched_yield can't be called from a signal handler. Must use + * the _np version. + */ +#define _PT_PTHREAD_YIELD() pthread_yield_np() +#elif defined(AIX) +extern int (*_PT_aix_yield_fcn)(); +#define _PT_PTHREAD_YIELD() (*_PT_aix_yield_fcn)() +#elif defined(IRIX) +#include +#define _PT_PTHREAD_YIELD() \ + PR_BEGIN_MACRO \ + struct timespec onemillisec = {0}; \ + onemillisec.tv_nsec = 1000000L; \ + nanosleep(&onemillisec,NULL); \ + PR_END_MACRO +#elif defined(HPUX) || defined(SOLARIS) \ + || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \ + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ + || defined(BSDI) || defined(NTO) || defined(DARWIN) \ + || defined(UNIXWARE) || defined(RISCOS) +#define _PT_PTHREAD_YIELD() sched_yield() +#else +#error "Need to define _PT_PTHREAD_YIELD for this platform" +#endif + +#endif /* nspr_pth_defs_h_ */ diff --git a/nsprpub/pr/include/md/_qnx.cfg b/nsprpub/pr/include/md/_qnx.cfg new file mode 100644 index 00000000000..7c5fc3e89ea --- /dev/null +++ b/nsprpub/pr/include/md/_qnx.cfg @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef QNX +#define QNX +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef 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_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 1 +#define PR_ALIGN_OF_INT 1 +#define PR_ALIGN_OF_LONG 1 +#define PR_ALIGN_OF_INT64 1 +#define PR_ALIGN_OF_FLOAT 1 +#define PR_ALIGN_OF_DOUBLE 1 +#define PR_ALIGN_OF_POINTER 1 +#define PR_ALIGN_OF_WORD 1 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 +#define PR_WORDS_PER_DWORD_LOG2 1 + +#endif /* nspr_cpucfg___ */ diff --git a/nsprpub/pr/include/md/_qnx.h b/nsprpub/pr/include/md/_qnx.h new file mode 100644 index 00000000000..f7593c6a33d --- /dev/null +++ b/nsprpub/pr/include/md/_qnx.h @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_qnx_defs_h___ +#define nspr_qnx_defs_h___ + +/* +** Internal configuration macros +*/ +#define PR_LINKER_ARCH "qnx" +#define _PR_SI_SYSNAME "QNX" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#undef _PR_POLL_AVAILABLE +#undef _PR_USE_POLL +#define _PR_HAVE_SOCKADDR_LEN +#define HAVE_BSD_FLOCK +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME + +#include + +#undef HAVE_STACK_GROWING_UP +#undef HAVE_DLL +#undef USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_NEED_STRCASECMP + +#ifndef HAVE_STRERROR +#define HAVE_STRERROR +#endif + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _PR_NUM_GCREGS _JBLEN +#define _MD_GET_SP(_t) (_t)->md.context[7] + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_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); \ + _LONGJMP(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; +}; + +/* +** 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 +}; + +#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; +}; + +#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_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* +** We wrapped the select() call. _MD_SELECT refers to the built-in, +** unwrapped version. +*/ +#include +#include +#include +#define _MD_SELECT select + +#define SA_RESTART 0 + +#endif /* nspr_qnx_defs_h___ */ diff --git a/nsprpub/pr/include/md/_reliantunix.cfg b/nsprpub/pr/include/md/_reliantunix.cfg new file mode 100644 index 00000000000..f2913d181c2 --- /dev/null +++ b/nsprpub/pr/include/md/_reliantunix.cfg @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef RELIANTUNIX +#define RELIANTUNIX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef 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_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 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_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 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 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 +#define PR_WORDS_PER_DWORD_LOG2 1 + +#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_WORD 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define _PR_POLL_BACKCOMPAT + +#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/nsprpub/pr/include/md/_reliantunix.h b/nsprpub/pr/include/md/_reliantunix.h new file mode 100644 index 00000000000..a924e2f992b --- /dev/null +++ b/nsprpub/pr/include/md/_reliantunix.h @@ -0,0 +1,270 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * reliantunix.h + * 5/18/96 Taken from nec.h -- chrisk@netscape.com + * 3/14/97 Modified for nspr20 -- chrisk@netscape.com + */ +#ifndef nspr_reliantunix_defs_h___ +#define nspr_reliantunix_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "sinix" +#define _PR_SI_SYSNAME "SINIX" +#define _PR_SI_ARCHITECTURE "mips" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE (2*65536L) +#define _MD_MMAP_FLAGS MAP_PRIVATE|MAP_FIXED + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define HAVE_NETCONFIG +#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 +#define _PR_STAT_HAS_ST_ATIM +#define _PR_NO_LARGE_FILES + +/* + * Mike Patnode indicated that it is possibly safe now to use context-switching + * calls that do not change the signal mask, like setjmp vs. sigsetjmp. + * So we'll use our homegrown, getcontext/setcontext-compatible stuff which + * will save us the getcontext/setcontext system calls at each context switch. + * It already works in FastTrack 2.01, so it should do it here :-) + * - chrisk 040497 + */ +#define USE_SETCXT /* temporarily disabled... */ + +#include + +#ifdef USE_SETCXT +/* use non-syscall machine language replacement */ +#define _GETCONTEXT getcxt +#define _SETCONTEXT setcxt +/* defined in os_ReliantUNIX.s */ +extern int getcxt(ucontext_t *); +extern int setcxt(ucontext_t *); +#else +#define _GETCONTEXT getcontext +#define _SETCONTEXT setcontext +#endif + +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gpregs[CXT_SP] +#define _PR_CONTEXT_TYPE ucontext_t +#define _PR_NUM_GCREGS NGREG + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#define _PR_IS_NATIVE_THREAD_SUPPORTED() 0 + +/* +** 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; +}; + +/* + * 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; +}; + +#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() + +/* +** Initialize the thread context preparing it to execute "_main()" +** - get a nice, fresh context +** - set its SP to the stack we allcoated for it +** - set it to start things at "e" +*/ +#define _MD_INIT_CONTEXT(thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + _GETCONTEXT(CONTEXT(thread)); \ + /* this is supposed to point to the stack BASE, not to SP */ \ + CONTEXT(thread)->uc_stack.ss_sp = thread->stack->stackBottom; \ + CONTEXT(thread)->uc_stack.ss_size = thread->stack->stackSize; \ + CONTEXT(thread)->uc_mcontext.gpregs[CXT_SP] = ((unsigned long)_sp - 128) & 0xfffffff8; \ + CONTEXT(thread)->uc_mcontext.gpregs[CXT_T9] = _main; \ + CONTEXT(thread)->uc_mcontext.gpregs[CXT_EPC] = _main; \ + CONTEXT(thread)->uc_mcontext.gpregs[CXT_RA] = 0; \ + thread->no_sched = 0; \ + PR_END_MACRO + +/* +** Save current context as it is scheduled away +*/ +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + if (!_GETCONTEXT(CONTEXT(_thread))) { \ + _MD_SAVE_ERRNO(_thread); \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } \ + PR_END_MACRO + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT or set up +** by _MD_INIT_CONTEXT +** CXT_V0 is the register that holds the return value. +** We must set it to 1 so that we can see if the return from +** getcontext() is the result of calling getcontext() or +** setcontext()... +** setting a context got with getcontext() appears to +** return from getcontext(), too! +** CXT_A3 is the register that holds status when returning +** from a syscall. It is set to 0 to indicate success, +** because we want getcontext() on the other side of the magic +** door to be ok. +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_thread); \ + uc->uc_mcontext.gpregs[CXT_V0] = 1;\ + uc->uc_mcontext.gpregs[CXT_A3] = 0;\ + _MD_RESTORE_ERRNO(_thread); \ + _MD_SET_CURRENT_THREAD(_thread); \ + _SETCONTEXT(uc); \ + PR_END_MACRO + +#define _MD_SAVE_ERRNO(t) (t)->md.errcode = errno; +#define _MD_RESTORE_ERRNO(t) errno = (t)->md.errcode; + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +#define S_ISSOCK(mode) ((mode&0xF000) == 0xC000) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(mode) ((mode&0xA000) == 0xC000) +#endif + +#include +#include +#include +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *execptfds, struct timeval *timeout); +#define _MD_SELECT(nfds,r,w,e,tv) _select(nfds,r,w,e,tv) +#define _MD_POLL _poll + +#endif /* nspr_reliantunix_defs_h___ */ diff --git a/nsprpub/pr/include/md/_riscos.cfg b/nsprpub/pr/include/md/_riscos.cfg new file mode 100644 index 00000000000..53010bda127 --- /dev/null +++ b/nsprpub/pr/include/md/_riscos.cfg @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef RISCOS +#define RISCOS +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#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_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_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 +#define PR_WORDS_PER_DWORD_LOG2 1 + +#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/nsprpub/pr/include/md/_riscos.h b/nsprpub/pr/include/md/_riscos.h new file mode 100644 index 00000000000..5a0309eb3e4 --- /dev/null +++ b/nsprpub/pr/include/md/_riscos.h @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): Peter Naulls + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_riscos_defs_h___ +#define nspr_riscos_defs_h___ + +/* +** Internal configuration macros +*/ +#define PR_LINKER_ARCH "riscos" +#define _PR_SI_SYSNAME "RISCOS" +#define _PR_SI_ARCHITECTURE "arm" +#define PR_DLL_SUFFIX ".a" + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_HAVE_SOCKADDR_LEN +#undef HAVE_BSD_FLOCK +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_HAVE_POSIX_SEMAPHORES + +#include +#include +#include + + +#undef HAVE_STACK_GROWING_UP +#undef HAVE_DLL +#undef USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define PT_NO_SIGTIMEDWAIT + +#ifndef HAVE_STRERROR +#define HAVE_STRERROR +#endif + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _PR_NUM_GCREGS _JBLEN +#define _MD_GET_SP(_t) (_t)->md.context[7] + +#define CONTEXT(_th) ((_th)->md.context) + + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_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); \ + _LONGJMP(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; +}; + +/* +** 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 +}; + +#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; +}; + +#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_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* +** We wrapped the select() call. _MD_SELECT refers to the built-in, +** unwrapped version. +*/ +#include +#include +#include +#define _MD_SELECT select + +#endif /* nspr_riscos_defs_h___ */ diff --git a/nsprpub/pr/include/md/_scoos.cfg b/nsprpub/pr/include/md/_scoos.cfg new file mode 100644 index 00000000000..d7c461fff46 --- /dev/null +++ b/nsprpub/pr/include/md/_scoos.cfg @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef SCO +#define SCO +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef 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 + +#define _PR_POLL_BACKCOMPAT + +#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/nsprpub/pr/include/md/_scoos.h b/nsprpub/pr/include/md/_scoos.h new file mode 100644 index 00000000000..6efaa7ea2bb --- /dev/null +++ b/nsprpub/pr/include/md/_scoos.h @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_scoos5_defs_h___ +#define nspr_scoos5_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "scoos5" +#define PR_DLL_SUFFIX ".so" + +#define _PR_SI_SYSNAME "SCO" +#define _PR_SI_ARCHITECTURE "x86" +#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 + +#if !defined (HAVE_STRERROR) +#define HAVE_STRERROR +#endif + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME + +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_RECV_BROKEN /* recv doesn't work on Unix Domain Sockets */ + +#define USE_SETJMP + +#ifdef _PR_LOCAL_THREADS_ONLY +#include + +#define _MD_GET_SP(_t) (_t)->md.jb[4] +#define PR_NUM_GCREGS _SIGJBLEN +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.jb) + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread),1)) { \ + (*_main)(); \ + } \ + _MD_GET_SP(_thread) = (int) ((_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)->osErrorCode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + siglongjmp(CONTEXT(_thread), 1); \ +} + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +struct _MDThread { + jmp_buf jb; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +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; +}; + +#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_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_SELECT _select +#define _MD_POLL _poll + +#endif /* nspr_scoos5_defs_h___ */ diff --git a/nsprpub/pr/include/md/_solaris.cfg b/nsprpub/pr/include/md/_solaris.cfg new file mode 100644 index 00000000000..81313e553db --- /dev/null +++ b/nsprpub/pr/include/md/_solaris.cfg @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef SOLARIS +#define SOLARIS +#endif + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#if defined(sparc) || defined(__sparc) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#if defined(__sparcv9) +#define IS_64 +#endif +#elif defined(__x86_64) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define IS_64 +#elif defined(i386) || defined(__i386) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_DOUBLE 4 +#else +#error unknown processor +#endif + +#ifdef 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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_POINTER 8 + +#else /* 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 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_FLOAT 4 +#define PR_ALIGN_OF_POINTER 4 + +#endif /* IS_64 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#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 /* ifndef nspr_cpucfg___ */ diff --git a/nsprpub/pr/include/md/_solaris.h b/nsprpub/pr/include/md/_solaris.h new file mode 100644 index 00000000000..aed078fcbfa --- /dev/null +++ b/nsprpub/pr/include/md/_solaris.h @@ -0,0 +1,806 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_solaris_defs_h___ +#define nspr_solaris_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "solaris" +#define _PR_SI_SYSNAME "SOLARIS" +#ifdef sparc +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__x86_64) +#define _PR_SI_ARCHITECTURE "x86-64" +#elif defined(i386) +#define _PR_SI_ARCHITECTURE "x86" +#else +#error unknown processor +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE (2*65536L) +#define _MD_MMAP_FLAGS MAP_SHARED + +#undef HAVE_STACK_GROWING_UP + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK + +/* + * Intel x86 has atomic instructions. + * + * Sparc v8 does not have instructions to efficiently implement + * atomic increment/decrement operations. In the local threads + * only and pthreads versions, we use the default atomic routine + * implementation in pratom.c. The obsolete global threads only + * version uses a global mutex_t to implement the atomic routines + * in solaris.c, which is actually equivalent to the default + * implementation. + * + * 64-bit Solaris requires sparc v9, which has atomic instructions. + */ +#if defined(i386) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(IS_64) +#define _PR_HAVE_ATOMIC_OPS +#endif + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ST_ATIM +#ifdef SOLARIS2_5 +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY +#else +#define _PR_HAVE_POSIX_SEMAPHORES +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#endif +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#define _PR_ACCEPT_INHERIT_NONBLOCK +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#else +#define AF_INET6 26 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#define AI_CANONNAME 0x0010 +#define AI_V4MAPPED 0x0001 +#define AI_ALL 0x0002 +#define AI_ADDRCONFIG 0x0004 +#define _PR_HAVE_MD_SOCKADDR_IN6 +/* isomorphic to struct in6_addr on Solaris 8 */ +struct _md_in6_addr { + union { + PRUint8 _S6_u8[16]; + PRUint32 _S6_u32[4]; + PRUint32 __S6_align; + } _S6_un; +}; +/* isomorphic to struct sockaddr_in6 on Solaris 8 */ +struct _md_sockaddr_in6 { + PRUint16 sin6_family; + PRUint16 sin6_port; + PRUint32 sin6_flowinfo; + struct _md_in6_addr sin6_addr; + PRUint32 sin6_scope_id; + PRUint32 __sin6_src_id; +}; +#endif +#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS) +#define _PR_HAVE_GETHOST_R +#define _PR_HAVE_GETHOST_R_POINTER +#endif + +#include "prinrval.h" +NSPR_API(PRIntervalTime) _MD_Solaris_GetInterval(void); +#define _MD_GET_INTERVAL _MD_Solaris_GetInterval +NSPR_API(PRIntervalTime) _MD_Solaris_TicksPerSecond(void); +#define _MD_INTERVAL_PER_SEC _MD_Solaris_TicksPerSecond + +#if defined(_PR_HAVE_ATOMIC_OPS) +/* +** Atomic Operations +*/ +#define _MD_INIT_ATOMIC() + +NSPR_API(PRInt32) _MD_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _MD_AtomicIncrement + +NSPR_API(PRInt32) _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _MD_AtomicAdd + +NSPR_API(PRInt32) _MD_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _MD_AtomicDecrement + +NSPR_API(PRInt32) _MD_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _MD_AtomicSet +#endif /* _PR_HAVE_ATOMIC_OPS */ + +#if defined(_PR_PTHREADS) + +NSPR_API(void) _MD_EarlyInit(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit + +#elif defined(_PR_GLOBAL_THREADS_ONLY) + +#include "prthread.h" + +#include + +/* +** Iinitialization Related definitions +*/ + +NSPR_API(void) _MD_EarlyInit(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit + +#define _MD_GET_SP(threadp) threadp->md.sp + +/* +** Clean-up the thread machine dependent data structure +*/ +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_INIT_ATTACHED_THREAD _MD_InitializeThread + +NSPR_API(PRStatus) _MD_CreateThread(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +#define _MD_CREATE_THREAD _MD_CreateThread + +#define _PR_CONTEXT_TYPE ucontext_t + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#include +#include +#include + +extern struct PRLock *_pr_schedLock; + +/* +** Thread Local Storage +*/ + +#define THREAD_KEY_T thread_key_t + +extern struct PRThread *_pr_attached_thread_tls(); +extern struct PRThread *_pr_current_thread_tls(); +extern struct _PRCPU *_pr_current_cpu_tls(); +extern struct PRThread *_pr_last_thread_tls(); + +extern THREAD_KEY_T threadid_key; +extern THREAD_KEY_T cpuid_key; +extern THREAD_KEY_T last_thread_key; + +#define _MD_GET_ATTACHED_THREAD() _pr_attached_thread_tls() +#define _MD_CURRENT_THREAD() _pr_current_thread_tls() +#define _MD_CURRENT_CPU() _pr_current_cpu_tls() +#define _MD_LAST_THREAD() _pr_last_thread_tls() + +#define _MD_SET_CURRENT_THREAD(newval) \ + PR_BEGIN_MACRO \ + thr_setspecific(threadid_key, (void *)newval); \ + PR_END_MACRO + +#define _MD_SET_CURRENT_CPU(newval) \ + PR_BEGIN_MACRO \ + thr_setspecific(cpuid_key, (void *)newval); \ + PR_END_MACRO + +#define _MD_SET_LAST_THREAD(newval) \ + PR_BEGIN_MACRO \ + thr_setspecific(last_thread_key, (void *)newval); \ + PR_END_MACRO + +#define _MD_CLEAN_THREAD(_thread) _MD_cleanup_thread(_thread) +extern void _MD_exit_thread(PRThread *thread); +#define _MD_EXIT_THREAD(thread) _MD_exit_thread(thread) + +#define _MD_SUSPEND_THREAD(thread) _MD_Suspend(thread) +#define _MD_RESUME_THREAD(thread) thr_continue((thread)->md.handle) + +/* XXXX Needs to be defined - Prashant */ +#define _MD_SUSPEND_CPU(cpu) +#define _MD_RESUME_CPU(cpu) + +extern void _MD_Begin_SuspendAll(void); +extern void _MD_End_SuspendAll(void); +extern void _MD_End_ResumeAll(void); +#define _MD_BEGIN_SUSPEND_ALL() _MD_Begin_SuspendAll() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() _MD_End_SuspendAll() +#define _MD_END_RESUME_ALL() _MD_End_ResumeAll() + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(md_lockp) (mutex_init(&((md_lockp)->lock),USYNC_THREAD,NULL) ? PR_FAILURE : PR_SUCCESS) +#define _MD_FREE_LOCK(md_lockp) mutex_destroy(&((md_lockp)->lock)) +#define _MD_UNLOCK(md_lockp) mutex_unlock(&((md_lockp)->lock)) +#define _MD_TEST_AND_LOCK(md_lockp) mutex_trylock(&((md_lockp)->lock)) +struct _MDLock; +NSPR_API(void) _MD_lock(struct _MDLock *md_lock); +#undef PROFILE_LOCKS +#ifndef PROFILE_LOCKS +#define _MD_LOCK(md_lockp) _MD_lock(md_lockp) +#else +#define _MD_LOCK(md_lockp) \ + PR_BEGIN_MACRO \ + int rv = _MD_TEST_AND_LOCK(md_lockp); \ + if (rv == 0) { \ + (md_lockp)->hitcount++; \ + } else { \ + (md_lockp)->misscount++; \ + _MD_lock(md_lockp); \ + } \ + PR_END_MACRO +#endif + +#define _PR_LOCK_HEAP() if (_pr_heapLock) _MD_LOCK(&_pr_heapLock->md) +#define _PR_UNLOCK_HEAP() if (_pr_heapLock) _MD_UNLOCK(&_pr_heapLock->md) + +#define _MD_ATTACH_THREAD(threadp) + + +#define THR_KEYCREATE thr_keycreate +#define THR_SELF thr_self +#define _MD_NEW_CV(condp) cond_init(&((condp)->cv), USYNC_THREAD, 0) +#define COND_WAIT(condp, mutexp) cond_wait(condp, mutexp) +#define COND_TIMEDWAIT(condp, mutexp, tspec) \ + cond_timedwait(condp, mutexp, tspec) +#define _MD_NOTIFY_CV(condp, lockp) cond_signal(&((condp)->cv)) +#define _MD_NOTIFYALL_CV(condp,unused) cond_broadcast(&((condp)->cv)) +#define _MD_FREE_CV(condp) cond_destroy(&((condp)->cv)) +#define _MD_YIELD() thr_yield() +#include +/* + * Because clock_gettime() on Solaris/x86 2.4 always generates a + * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(), + * which is implemented using gettimeofday(). + */ +#if defined(i386) && defined(SOLARIS2_4) +extern int _pr_solx86_clock_gettime(clockid_t clock_id, struct timespec *tp); +#define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt)) +#else +#define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt)) +#endif /* i386 && SOLARIS2_4 */ + +#define MUTEX_T mutex_t +#define COND_T cond_t + +#define _MD_NEW_SEM(md_semp,_val) sema_init(&((md_semp)->sem),_val,USYNC_THREAD,NULL) +#define _MD_DESTROY_SEM(md_semp) sema_destroy(&((md_semp)->sem)) +#define _MD_WAIT_SEM(md_semp) sema_wait(&((md_semp)->sem)) +#define _MD_POST_SEM(md_semp) sema_post(&((md_semp)->sem)) + +#define _MD_SAVE_ERRNO(_thread) +#define _MD_RESTORE_ERRNO(_thread) +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) + +extern struct _MDLock _pr_ioq_lock; +#define _MD_IOQ_LOCK() _MD_LOCK(&_pr_ioq_lock) +#define _MD_IOQ_UNLOCK() _MD_UNLOCK(&_pr_ioq_lock) + +extern PRStatus _MD_wait(struct PRThread *, PRIntervalTime timeout); +#define _MD_WAIT _MD_wait + +extern PRStatus _MD_WakeupWaiter(struct PRThread *); +#define _MD_WAKEUP_WAITER _MD_WakeupWaiter + +NSPR_API(void) _MD_InitIO(void); +#define _MD_INIT_IO _MD_InitIO + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + PR_END_MACRO +#define _MD_SWITCH_CONTEXT(_thread) +#define _MD_RESTORE_CONTEXT(_newThread) + +struct _MDLock { + MUTEX_T lock; +#ifdef PROFILE_LOCKS + PRInt32 hitcount; + PRInt32 misscount; +#endif +}; + +struct _MDCVar { + COND_T cv; +}; + +struct _MDSemaphore { + sema_t sem; +}; + +struct _MDThread { + _PR_CONTEXT_TYPE context; + thread_t handle; + lwpid_t lwpid; + uint_t sp; /* stack pointer */ + uint_t threadID; /* ptr to solaris-internal thread id structures */ + struct _MDSemaphore waiter_sem; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +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; +}; + +/* The following defines the unwrapped versions of select() and poll(). */ +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#include +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +PR_BEGIN_EXTERN_C + +/* +** Missing function prototypes +*/ +extern int gethostname (char *name, int namelen); + +PR_END_EXTERN_C + +#else /* _PR_GLOBAL_THREADS_ONLY */ + +/* + * LOCAL_THREADS_ONLY implementation on Solaris + */ + +#include "prthread.h" + +#include +#include +#include +#include + +/* +** Iinitialization Related definitions +*/ + +NSPR_API(void) _MD_EarlyInit(void); +NSPR_API(void) _MD_SolarisInit(); +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _MD_SolarisInit +#define _MD_INIT_THREAD _MD_InitializeThread + +#ifdef USE_SETJMP + +#include + +#define _PR_CONTEXT_TYPE jmp_buf + +#ifdef sparc +#define _MD_GET_SP(_t) (_t)->md.context[2] +#else +#define _MD_GET_SP(_t) (_t)->md.context[4] +#endif + +#define PR_NUM_GCREGS _JBLEN +#define CONTEXT(_thread) (_thread)->md.context + +#else /* ! USE_SETJMP */ + +#ifdef sparc +#define _PR_CONTEXT_TYPE ucontext_t +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[REG_SP] +/* +** Sparc's use register windows. the _MD_GetRegisters for the sparc's +** doesn't actually store anything into the argument buffer; instead the +** register windows are homed to the stack. I assume that the stack +** always has room for the registers to spill to... +*/ +#define PR_NUM_GCREGS 0 +#else +#define _PR_CONTEXT_TYPE unsigned int edi; sigset_t oldMask, blockMask; ucontext_t +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[USP] +#define PR_NUM_GCREGS _JBLEN +#endif + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#endif /* ! USE_SETJMP */ + +#include +/* + * Because clock_gettime() on Solaris/x86 always generates a + * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(), + * which is implemented using gettimeofday(). + */ +#ifdef i386 +#define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt)) +#else +#define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt)) +#endif /* i386 */ + +#define _MD_SAVE_ERRNO(_thread) (_thread)->md.errcode = errno; +#define _MD_RESTORE_ERRNO(_thread) errno = (_thread)->md.errcode; + +#ifdef sparc + +#ifdef USE_SETJMP +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + int *context = (_thread)->md.context; \ + *status = PR_TRUE; \ + (void) setjmp(context); \ + (_thread)->md.context[1] = (int) ((_sp) - 64); \ + (_thread)->md.context[2] = (int) _main; \ + (_thread)->md.context[3] = (int) _main + 4; \ + _thread->no_sched = 0; \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + _MD_SAVE_ERRNO(_thread) \ + _MD_SET_LAST_THREAD(_thread); \ + _MD_SET_CURRENT_THREAD(_thread); \ + _PR_Schedule(); \ + } + +#define _MD_RESTORE_CONTEXT(_newThread) \ +{ \ + _MD_RESTORE_ERRNO(_newThread) \ + _MD_SET_CURRENT_THREAD(_newThread); \ + longjmp(CONTEXT(_newThread), 1); \ +} + +#else +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_thread); \ + *status = PR_TRUE; \ + getcontext(uc); \ + uc->uc_stack.ss_sp = (char *) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8); \ + uc->uc_stack.ss_size = _thread->stack->stackSize; \ + uc->uc_stack.ss_flags = 0; /* ? */ \ + uc->uc_mcontext.gregs[REG_SP] = (unsigned int) uc->uc_stack.ss_sp; \ + uc->uc_mcontext.gregs[REG_PC] = (unsigned int) _main; \ + uc->uc_mcontext.gregs[REG_nPC] = (unsigned int) ((char*)_main)+4; \ + uc->uc_flags = UC_ALL; \ + _thread->no_sched = 0; \ + PR_END_MACRO + +/* +** Switch away from the current thread context by saving its state and +** calling the thread scheduler. Reload cpu when we come back from the +** context switch because it might have changed. +*/ +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + if (!getcontext(CONTEXT(_thread))) { \ + _MD_SAVE_ERRNO(_thread); \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } \ + PR_END_MACRO + +/* +** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or +** initialized by _MD_INIT_CONTEXT. +*/ +#define _MD_RESTORE_CONTEXT(_newThread) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_newThread); \ + uc->uc_mcontext.gregs[11] = 1; \ + _MD_RESTORE_ERRNO(_newThread); \ + _MD_SET_CURRENT_THREAD(_newThread); \ + setcontext(uc); \ + PR_END_MACRO +#endif + +#else /* x86 solaris */ + +#ifdef USE_SETJMP + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) _main(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 64); \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + _MD_SAVE_ERRNO(_thread) \ + _PR_Schedule(); \ + } + +#define _MD_RESTORE_CONTEXT(_newThread) \ +{ \ + _MD_RESTORE_ERRNO(_newThread) \ + _MD_SET_CURRENT_THREAD(_newThread); \ + longjmp(CONTEXT(_newThread), 1); \ +} + +#else /* USE_SETJMP */ + +#define WINDOWSIZE 0 + +int getedi(void); +void setedi(int); + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_thread); \ + *status = PR_TRUE; \ + getcontext(uc); \ + /* Force sp to be double aligned! */ \ + uc->uc_mcontext.gregs[USP] = (int) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8); \ + uc->uc_mcontext.gregs[PC] = (int) _main; \ + (_thread)->no_sched = 0; \ + PR_END_MACRO + +/* getcontext() may return 1, contrary to what the man page says */ +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_thread); \ + PR_ASSERT(_thread->no_sched); \ + sigfillset(&((_thread)->md.blockMask)); \ + sigprocmask(SIG_BLOCK, &((_thread)->md.blockMask), \ + &((_thread)->md.oldMask)); \ + (_thread)->md.edi = getedi(); \ + if (! getcontext(uc)) { \ + sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \ + uc->uc_mcontext.gregs[EDI] = (_thread)->md.edi; \ + _MD_SAVE_ERRNO(_thread) \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } else { \ + sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \ + setedi((_thread)->md.edi); \ + PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \ + _MD_LAST_THREAD()->no_sched = 0; \ + } \ + PR_END_MACRO + +/* +** Restore a thread context, saved by _PR_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_newthread) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_newthread); \ + uc->uc_mcontext.gregs[EAX] = 1; \ + _MD_RESTORE_ERRNO(_newthread) \ + _MD_SET_CURRENT_THREAD(_newthread); \ + (_newthread)->no_sched = 1; \ + setcontext(uc); \ + PR_END_MACRO +#endif /* USE_SETJMP */ + +#endif /* sparc */ + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDThread { + _PR_CONTEXT_TYPE context; + int errcode; + int id; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +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; +}; + +#ifndef _PR_PTHREADS +#define _MD_INIT_LOCKS() +#endif +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +extern PRStatus _MD_WAIT(struct PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(struct PRThread *); +extern void _MD_YIELD(void); +extern PRStatus _MD_InitializeThread(PRThread *thread); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, + PRThreadPriority newPri); +extern PRStatus _MD_CREATE_THREAD(PRThread *thread, void (*start) (void *), + PRThreadPriority priority, PRThreadScope scope, PRThreadState state, + PRUint32 stackSize); + +NSPR_API(PRIntervalTime) _MD_Solaris_GetInterval(void); +#define _MD_GET_INTERVAL _MD_Solaris_GetInterval +NSPR_API(PRIntervalTime) _MD_Solaris_TicksPerSecond(void); +#define _MD_INTERVAL_PER_SEC _MD_Solaris_TicksPerSecond + +/* The following defines the unwrapped versions of select() and poll(). */ +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#include +#include +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +PR_BEGIN_EXTERN_C + +/* +** Missing function prototypes +*/ +extern int gethostname (char *name, int namelen); + +PR_END_EXTERN_C + +#endif /* _PR_GLOBAL_THREADS_ONLY */ + +extern void _MD_solaris_map_sendfile_error(int err); + +#endif /* nspr_solaris_defs_h___ */ + diff --git a/nsprpub/pr/include/md/_sony.cfg b/nsprpub/pr/include/md/_sony.cfg new file mode 100644 index 00000000000..4b8fbff966e --- /dev/null +++ b/nsprpub/pr/include/md/_sony.cfg @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef SONY +#define SONY +#endif + +#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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#undef HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef 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/nsprpub/pr/include/md/_sony.h b/nsprpub/pr/include/md/_sony.h new file mode 100644 index 00000000000..3d17e04dba8 --- /dev/null +++ b/nsprpub/pr/include/md/_sony.h @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_sony_defs_h___ +#define nspr_sony_defs_h___ + +#define PR_LINKER_ARCH "sony" +#define _PR_SI_SYSNAME "SONY" +#define _PR_SI_ARCHITECTURE "mips" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#if defined(_PR_LOCAL_THREADS_ONLY) +#include +#include + +#define PR_NUM_GCREGS NGREG +#define PR_CONTEXT_TYPE ucontext_t + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[CXT_SP] + +/* +** Initialize the thread context preparing it to execute _main() +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + getcontext(CONTEXT(_thread)); \ + CONTEXT(_thread)->uc_stack.ss_sp = (char*) (_thread)->stack->stackBottom; \ + CONTEXT(_thread)->uc_stack.ss_size = (_thread)->stack->stackSize; \ + _MD_GET_SP(_thread) = (greg_t) (_sp) - 64; \ + makecontext(CONTEXT(_thread), _main, 0); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!getcontext(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + ucontext_t *uc = CONTEXT(_thread); \ + uc->uc_mcontext.gregs[CXT_V0] = 1; \ + uc->uc_mcontext.gregs[CXT_A3] = 0; \ + _MD_SET_CURRENT_THREAD(_thread); \ + errno = (_thread)->md.errcode; \ + setcontext(uc); \ +} + +/* 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; +}; + +/* + * 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; +}; + +#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_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* The following defines unwrapped versions of select() and poll(). */ +extern int _select (int, fd_set *, fd_set *, fd_set *, struct timeval *); +#define _MD_SELECT _select + +#include +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); +#define _MD_POLL _poll + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define NEED_TIME_R +#define NEED_STRFTIME_LOCK + +/* +** Missing function prototypes +*/ +extern int gethostname(char *name, int namelen); + +#endif /* nspr_sony_defs_h___ */ diff --git a/nsprpub/pr/include/md/_sunos4.cfg b/nsprpub/pr/include/md/_sunos4.cfg new file mode 100644 index 00000000000..581d4834334 --- /dev/null +++ b/nsprpub/pr/include/md/_sunos4.cfg @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef SUNOS4 +#define SUNOS4 +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef HAVE_LONG_LONG +#define 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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#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 /* ifndef nspr_cpucfg___ */ diff --git a/nsprpub/pr/include/md/_sunos4.h b/nsprpub/pr/include/md/_sunos4.h new file mode 100644 index 00000000000..0d62892e302 --- /dev/null +++ b/nsprpub/pr/include/md/_sunos4.h @@ -0,0 +1,236 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_sunos_defs_h___ +#define nspr_sunos_defs_h___ + +#include "md/sunos4.h" + +/* On SunOS 4, memset is declared in memory.h */ +#include +#include +#include + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "sunos" +#define _PR_SI_SYSNAME "SUNOS" +#define _PR_SI_ARCHITECTURE "sparc" +#define PR_DLL_SUFFIX ".so.1.0" + +/* +** For sunos type machines, don't specify an address because the +** NetBSD/SPARC O.S. does the wrong thing. +*/ +#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 +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#define USE_DLFCN +#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 + +#define USE_SETJMP + +#include + +#define _MD_GET_SP(_t) (_t)->md.context[2] + +#define PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + int *context = (_thread)->md.context; \ + *status = PR_TRUE; \ + asm("ta 3"); \ + (void) setjmp(context); \ + (_thread)->md.context[2] = (int) ((_sp) - 64); \ + (_thread)->md.context[2] &= ~7; \ + (_thread)->md.context[3] = (int) _main; \ + (_thread)->md.context[4] = (int) _main + 4; \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + asm("ta 3"); \ + if (!setjmp(CONTEXT(_thread))) { \ + (_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); \ + longjmp(CONTEXT(_thread), 1); \ +} + +#pragma unknown_control_flow(longjmp) +#pragma unknown_control_flow(setjmp) +#pragma unknown_control_flow(_PR_Schedule) + +/* +** Missing function prototypes +*/ + +extern int socket (int domain, int type, int protocol); +extern int getsockname (int s, struct sockaddr *name, int *namelen); +extern int getpeername (int s, struct sockaddr *name, int *namelen); +extern int getsockopt (int s, int level, int optname, char* optval, int* optlen); +extern int setsockopt (int s, int level, int optname, const char* optval, int optlen); +extern int accept (int s, struct sockaddr *addr, int *addrlen); +extern int listen (int s, int backlog); +extern int brk(void *); +extern void *sbrk(int); + + +/* Machine-dependent (MD) data structures. SunOS 4 has no native threads. */ + +struct _MDThread { + jmp_buf 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; +}; + +/* + * 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; +}; + +#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() + +/* These are copied from _solaris.h */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* + * 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_sparc_defs_h___ */ diff --git a/nsprpub/pr/include/md/_unix_errors.h b/nsprpub/pr/include/md/_unix_errors.h new file mode 100644 index 00000000000..a44cbb31692 --- /dev/null +++ b/nsprpub/pr/include/md/_unix_errors.h @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prunixerrors_h___ +#define prunixerrors_h___ + +#include +#include + +PR_BEGIN_EXTERN_C + +extern void _MD_unix_map_default_error(int err); +#define _PR_MD_MAP_DEFAULT_ERROR _MD_unix_map_default_error + +extern void _MD_unix_map_opendir_error(int err); +#define _PR_MD_MAP_OPENDIR_ERROR _MD_unix_map_opendir_error + +extern void _MD_unix_map_closedir_error(int err); +#define _PR_MD_MAP_CLOSEDIR_ERROR _MD_unix_map_closedir_error + +extern void _MD_unix_readdir_error(int err); +#define _PR_MD_MAP_READDIR_ERROR _MD_unix_readdir_error + +extern void _MD_unix_map_unlink_error(int err); +#define _PR_MD_MAP_UNLINK_ERROR _MD_unix_map_unlink_error + +extern void _MD_unix_map_stat_error(int err); +#define _PR_MD_MAP_STAT_ERROR _MD_unix_map_stat_error + +extern void _MD_unix_map_fstat_error(int err); +#define _PR_MD_MAP_FSTAT_ERROR _MD_unix_map_fstat_error + +extern void _MD_unix_map_rename_error(int err); +#define _PR_MD_MAP_RENAME_ERROR _MD_unix_map_rename_error + +extern void _MD_unix_map_access_error(int err); +#define _PR_MD_MAP_ACCESS_ERROR _MD_unix_map_access_error + +extern void _MD_unix_map_mkdir_error(int err); +#define _PR_MD_MAP_MKDIR_ERROR _MD_unix_map_mkdir_error + +extern void _MD_unix_map_rmdir_error(int err); +#define _PR_MD_MAP_RMDIR_ERROR _MD_unix_map_rmdir_error + +extern void _MD_unix_map_read_error(int err); +#define _PR_MD_MAP_READ_ERROR _MD_unix_map_read_error + +extern void _MD_unix_map_write_error(int err); +#define _PR_MD_MAP_WRITE_ERROR _MD_unix_map_write_error + +extern void _MD_unix_map_lseek_error(int err); +#define _PR_MD_MAP_LSEEK_ERROR _MD_unix_map_lseek_error + +extern void _MD_unix_map_fsync_error(int err); +#define _PR_MD_MAP_FSYNC_ERROR _MD_unix_map_fsync_error + +extern void _MD_unix_map_close_error(int err); +#define _PR_MD_MAP_CLOSE_ERROR _MD_unix_map_close_error + +extern void _MD_unix_map_socket_error(int err); +#define _PR_MD_MAP_SOCKET_ERROR _MD_unix_map_socket_error + +extern void _MD_unix_map_socketavailable_error(int err); +#define _PR_MD_MAP_SOCKETAVAILABLE_ERROR _MD_unix_map_socketavailable_error + +extern void _MD_unix_map_recv_error(int err); +#define _PR_MD_MAP_RECV_ERROR _MD_unix_map_recv_error + +extern void _MD_unix_map_recvfrom_error(int err); +#define _PR_MD_MAP_RECVFROM_ERROR _MD_unix_map_recvfrom_error + +extern void _MD_unix_map_send_error(int err); +#define _PR_MD_MAP_SEND_ERROR _MD_unix_map_send_error + +extern void _MD_unix_map_sendto_error(int err); +#define _PR_MD_MAP_SENDTO_ERROR _MD_unix_map_sendto_error + +extern void _MD_unix_map_writev_error(int err); +#define _PR_MD_MAP_WRITEV_ERROR _MD_unix_map_writev_error + +extern void _MD_unix_map_accept_error(int err); +#define _PR_MD_MAP_ACCEPT_ERROR _MD_unix_map_accept_error + +extern void _MD_unix_map_connect_error(int err); +#define _PR_MD_MAP_CONNECT_ERROR _MD_unix_map_connect_error + +extern void _MD_unix_map_bind_error(int err); +#define _PR_MD_MAP_BIND_ERROR _MD_unix_map_bind_error + +extern void _MD_unix_map_listen_error(int err); +#define _PR_MD_MAP_LISTEN_ERROR _MD_unix_map_listen_error + +extern void _MD_unix_map_shutdown_error(int err); +#define _PR_MD_MAP_SHUTDOWN_ERROR _MD_unix_map_shutdown_error + +extern void _MD_unix_map_socketpair_error(int err); +#define _PR_MD_MAP_SOCKETPAIR_ERROR _MD_unix_map_socketpair_error + +extern void _MD_unix_map_getsockname_error(int err); +#define _PR_MD_MAP_GETSOCKNAME_ERROR _MD_unix_map_getsockname_error + +extern void _MD_unix_map_getpeername_error(int err); +#define _PR_MD_MAP_GETPEERNAME_ERROR _MD_unix_map_getpeername_error + +extern void _MD_unix_map_getsockopt_error(int err); +#define _PR_MD_MAP_GETSOCKOPT_ERROR _MD_unix_map_getsockopt_error + +extern void _MD_unix_map_setsockopt_error(int err); +#define _PR_MD_MAP_SETSOCKOPT_ERROR _MD_unix_map_setsockopt_error + +extern void _MD_unix_map_open_error(int err); +#define _PR_MD_MAP_OPEN_ERROR _MD_unix_map_open_error + +extern void _MD_unix_map_mmap_error(int err); +#define _PR_MD_MAP_MMAP_ERROR _MD_unix_map_mmap_error + +extern void _MD_unix_map_gethostname_error(int err); +#define _PR_MD_MAP_GETHOSTNAME_ERROR _MD_unix_map_gethostname_error + +extern void _MD_unix_map_select_error(int err); +#define _PR_MD_MAP_SELECT_ERROR _MD_unix_map_select_error + +extern void _MD_unix_map_poll_error(int err); +#define _PR_MD_MAP_POLL_ERROR _MD_unix_map_poll_error + +extern void _MD_unix_map_poll_revents_error(int err); +#define _PR_MD_MAP_POLL_REVENTS_ERROR _MD_unix_map_poll_revents_error + +extern void _MD_unix_map_flock_error(int err); +#define _PR_MD_MAP_FLOCK_ERROR _MD_unix_map_flock_error + +extern void _MD_unix_map_lockf_error(int err); +#define _PR_MD_MAP_LOCKF_ERROR _MD_unix_map_lockf_error + +PR_END_EXTERN_C + +#endif /* prunixerrors_h___ */ diff --git a/nsprpub/pr/include/md/_unixos.h b/nsprpub/pr/include/md/_unixos.h new file mode 100644 index 00000000000..642599bd6d5 --- /dev/null +++ b/nsprpub/pr/include/md/_unixos.h @@ -0,0 +1,633 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prunixos_h___ +#define prunixos_h___ + +/* + * If FD_SETSIZE is not defined on the command line, set the default value + * before include select.h + */ +/* + * Linux: FD_SETSIZE is defined in /usr/include/sys/select.h and should + * not be redefined. + */ +#if !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__) \ + && !defined(DARWIN) && !defined(NEXTSTEP) +#ifndef FD_SETSIZE +#define FD_SETSIZE 4096 +#endif +#endif + +#include +#include +#include +#include +#include + +#include "prio.h" +#include "prmem.h" +#include "prclist.h" + +/* + * For select(), fd_set, and struct timeval. + * + * In The Single UNIX(R) Specification, Version 2, + * the header file for select() is . + * + * fd_set is defined in . Usually + * includes , but on some + * older systems does not include + * , so we include it explicitly. + */ +#include +#include +#if defined(AIX) /* Only pre-4.2 AIX needs it, but for simplicity... */ +#include +#endif + +#define _PR_HAVE_O_APPEND + +#define PR_DIRECTORY_SEPARATOR '/' +#define PR_DIRECTORY_SEPARATOR_STR "/" +#define PR_PATH_SEPARATOR ':' +#define PR_PATH_SEPARATOR_STR ":" +#define GCPTR +typedef int (*FARPROC)(); + +/* + * intervals at which GLOBAL threads wakeup to check for pending interrupt + */ +#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; + PRInt16 out_flags; +} _PRUnixPollDesc; + +typedef struct PRPollQueue { + PRCList links; /* for linking PRPollQueue's together */ + _PRUnixPollDesc *pds; /* array of poll descriptors */ + PRUintn npds; /* length of the array */ + PRPackedBool on_ioq; /* is this on the async i/o work q? */ + PRIntervalTime timeout; /* timeout, in ticks */ + struct PRThread *thr; +} PRPollQueue; + +#define _PR_POLLQUEUE_PTR(_qp) \ + ((PRPollQueue*) ((char*) (_qp) - offsetof(PRPollQueue,links))) + + +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) +#define _MD_CHECK_FOR_EXIT() +#endif + +extern fd_set _pr_md_read_set, _pr_md_write_set, _pr_md_exception_set; +extern PRInt16 _pr_md_read_cnt[], _pr_md_write_cnt[], _pr_md_exception_cnt[]; +extern PRInt32 _pr_md_ioq_max_osfd; +extern PRUint32 _pr_md_ioq_timeout; + +struct _MDFileDesc { + int osfd; +#if defined(LINUX) && defined(_PR_PTHREADS) + int tcp_nodelay; /* used by pt_LinuxSendFile */ +#endif +}; + +struct _MDDir { + DIR *d; +}; + +struct _PRCPU; +extern void _MD_unix_init_running_cpu(struct _PRCPU *cpu); + +/* +** 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 +** work - it just means that we don't really have a functional +** redzone. +*/ +#include +#ifndef PROT_NONE +#define PROT_NONE 0x0 +#endif + +#if defined(DEBUG) && !defined(DARWIN) && !defined(NEXTSTEP) +#if !defined(SOLARIS) +#include /* for memset() */ +#define _MD_INIT_STACK(ts,REDZONE) \ + PR_BEGIN_MACRO \ + (void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_NONE); \ + (void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\ + REDZONE, PROT_NONE); \ + /* \ + ** Fill stack memory with something that turns into an illegal \ + ** pointer value. This will sometimes find runtime references to \ + ** uninitialized pointers. We don't do this for solaris because we \ + ** can use purify instead. \ + */ \ + if (_pr_debugStacks) { \ + memset(ts->allocBase + REDZONE, 0xf7, ts->stackSize); \ + } \ + PR_END_MACRO +#else /* !SOLARIS */ +#define _MD_INIT_STACK(ts,REDZONE) \ + PR_BEGIN_MACRO \ + (void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_NONE); \ + (void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\ + REDZONE, PROT_NONE); \ + PR_END_MACRO +#endif /* !SOLARIS */ + +/* + * _MD_CLEAR_STACK + * Allow access to the redzone pages; the access was turned off in + * _MD_INIT_STACK. + */ +#define _MD_CLEAR_STACK(ts) \ + PR_BEGIN_MACRO \ + (void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_READ|PROT_WRITE);\ + (void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\ + REDZONE, PROT_READ|PROT_WRITE); \ + PR_END_MACRO + +#else /* DEBUG */ + +#define _MD_INIT_STACK(ts,REDZONE) +#define _MD_CLEAR_STACK(ts) + +#endif /* DEBUG */ + +#if !defined(SOLARIS) + +#define PR_SET_INTSOFF(newval) + +#endif + +/************************************************************************/ + +extern void _PR_UnixInit(void); + +/************************************************************************/ + +struct _MDProcess { + pid_t pid; +}; + +struct PRProcess; +struct PRProcessAttr; + +/* Create a new process (fork() + exec()) */ +#define _MD_CREATE_PROCESS _MD_CreateUnixProcess +extern struct PRProcess * _MD_CreateUnixProcess( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _MD_DetachUnixProcess +extern PRStatus _MD_DetachUnixProcess(struct PRProcess *process); + +/* Wait for a child process to terminate */ +#define _MD_WAIT_PROCESS _MD_WaitUnixProcess +extern PRStatus _MD_WaitUnixProcess(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _MD_KillUnixProcess +extern PRStatus _MD_KillUnixProcess(struct PRProcess *process); + +/************************************************************************/ + +extern void _MD_EnableClockInterrupts(void); +extern void _MD_DisableClockInterrupts(void); + +#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 + +/************************************************************************/ + +extern void _MD_InitCPUS(void); +#define _MD_INIT_CPUS _MD_InitCPUS + +extern void _MD_Wakeup_CPUs(void); +#define _MD_WAKEUP_CPUS _MD_Wakeup_CPUs + +#define _MD_PAUSE_CPU _MD_PauseCPU + +#if defined(_PR_LOCAL_THREADS_ONLY) || defined(_PR_GLOBAL_THREADS_ONLY) +#define _MD_CLEANUP_BEFORE_EXIT() +#endif + +#ifndef IRIX +#define _MD_EXIT(status) _exit(status) +#endif + +/************************************************************************/ + +#define _MD_GET_ENV getenv +#define _MD_PUT_ENV putenv + +/************************************************************************/ + +#define _MD_INIT_FILEDESC(fd) + +extern void _MD_MakeNonblock(PRFileDesc *fd); +#define _MD_MAKE_NONBLOCK _MD_MakeNonblock + +/************************************************************************/ + +#if !defined(_PR_PTHREADS) + +extern void _MD_InitSegs(void); +extern PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, + void *vaddr); +extern void _MD_FreeSegment(PRSegment *seg); + +#define _MD_INIT_SEGS _MD_InitSegs +#define _MD_ALLOC_SEGMENT _MD_AllocSegment +#define _MD_FREE_SEGMENT _MD_FreeSegment + +#endif /* !defined(_PR_PTHREADS) */ + +/************************************************************************/ + +#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) + +/************************************************************************/ + +#define _MD_ERRNO() (errno) +#define _MD_GET_SOCKET_ERROR() (errno) + +/************************************************************************/ + +extern PRInt32 _MD_AvailableSocket(PRInt32 osfd); + +extern void _MD_StartInterrupts(void); +extern void _MD_StopInterrupts(void); +extern void _MD_DisableClockInterrupts(void); +extern void _MD_BlockClockInterrupts(void); +extern void _MD_UnblockClockInterrupts(void); +extern void _MD_PauseCPU(PRIntervalTime timeout); + +extern PRStatus _MD_open_dir(struct _MDDir *, const char *); +extern PRInt32 _MD_close_dir(struct _MDDir *); +extern char * _MD_read_dir(struct _MDDir *, PRIntn); +extern PRInt32 _MD_open(const char *name, PRIntn osflags, PRIntn mode); +extern PRInt32 _MD_delete(const char *name); +extern PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info); +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, 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, + PRNetAddr **raddr, void *buf, PRInt32 amount); +extern PRInt32 _PR_UnixSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +extern PRStatus _MD_LockFile(PRInt32 osfd); +extern PRStatus _MD_TLockFile(PRInt32 osfd); +extern PRStatus _MD_UnlockFile(PRInt32 osfd); + +#define _MD_OPEN_DIR(dir, name) _MD_open_dir(dir, name) +#define _MD_CLOSE_DIR(dir) _MD_close_dir(dir) +#define _MD_READ_DIR(dir, flags) _MD_read_dir(dir, flags) +#define _MD_OPEN(name, osflags, mode) _MD_open(name, osflags, mode) +#define _MD_OPEN_FILE(name, osflags, mode) _MD_open(name, osflags, mode) +extern PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount); +#define _MD_READ(fd,buf,amount) _MD_read(fd,buf,amount) +extern PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount); +#define _MD_WRITE(fd,buf,amount) _MD_write(fd,buf,amount) +#define _MD_DELETE(name) _MD_delete(name) +#define _MD_GETFILEINFO(fn, info) _MD_getfileinfo(fn, info) +#define _MD_GETFILEINFO64(fn, info) _MD_getfileinfo64(fn, info) +#define _MD_GETOPENFILEINFO(fd, info) _MD_getopenfileinfo(fd, info) +#define _MD_GETOPENFILEINFO64(fd, info) _MD_getopenfileinfo64(fd, info) +#define _MD_RENAME(from, to) _MD_rename(from, to) +#define _MD_ACCESS(name, how) _MD_access(name, how) +#define _MD_MKDIR(name, mode) _MD_mkdir(name, mode) +#define _MD_MAKE_DIR(name, mode) _MD_mkdir(name, mode) +#define _MD_RMDIR(name) _MD_rmdir(name) +#define _MD_ACCEPT_READ(sock, newSock, raddr, buf, amount) _MD_accept_read(sock, newSock, raddr, buf, amount) + +#define _MD_LOCKFILE _MD_LockFile +#define _MD_TLOCKFILE _MD_TLockFile +#define _MD_UNLOCKFILE _MD_UnlockFile + + +extern PRInt32 _MD_socket(int af, int type, int flags); +#define _MD_SOCKET _MD_socket +extern PRInt32 _MD_connect(PRFileDesc *fd, const PRNetAddr *addr, + PRUint32 addrlen, PRIntervalTime timeout); +#define _MD_CONNECT _MD_connect +extern PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout); +#define _MD_ACCEPT _MD_accept +extern PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen); +#define _MD_BIND _MD_bind +extern PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog); +#define _MD_LISTEN _MD_listen +extern PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how); +#define _MD_SHUTDOWN _MD_shutdown + +extern PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +#define _MD_RECV _MD_recv +extern PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +#define _MD_SEND _MD_send +extern PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout); +#define _MD_RECVFROM _MD_recvfrom +extern PRInt32 _MD_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout); +#define _MD_SENDTO _MD_sendto +extern PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, + PRInt32 iov_size, PRIntervalTime timeout); +#define _MD_WRITEV _MD_writev + +extern PRInt32 _MD_socketavailable(PRFileDesc *fd); +#define _MD_SOCKETAVAILABLE _MD_socketavailable +extern PRInt64 _MD_socketavailable64(PRFileDesc *fd); +#define _MD_SOCKETAVAILABLE64 _MD_socketavailable64 + +#define _MD_PIPEAVAILABLE _MD_socketavailable + +extern PRInt32 _MD_pr_poll(PRPollDesc *pds, PRIntn npds, + PRIntervalTime timeout); +#define _MD_PR_POLL _MD_pr_poll + +extern PRInt32 _MD_close(PRInt32 osfd); +#define _MD_CLOSE_FILE _MD_close +extern PRInt32 _MD_lseek(PRFileDesc*, PRInt32, PRSeekWhence); +#define _MD_LSEEK _MD_lseek +extern PRInt64 _MD_lseek64(PRFileDesc*, PRInt64, PRSeekWhence); +#define _MD_LSEEK64 _MD_lseek64 +extern PRInt32 _MD_fsync(PRFileDesc *fd); +#define _MD_FSYNC _MD_fsync + +extern PRInt32 _MD_socketpair(int af, int type, int flags, PRInt32 *osfd); +#define _MD_SOCKETPAIR _MD_socketpair + +#define _MD_CLOSE_SOCKET _MD_close + +#ifndef NO_NSPR_10_SUPPORT +#define _MD_STAT stat +#endif + +extern PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen); +#define _MD_GETPEERNAME _MD_getpeername +extern PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen); +#define _MD_GETSOCKNAME _MD_getsockname + +extern PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, + PRInt32 optname, char* optval, PRInt32* optlen); +#define _MD_GETSOCKOPT _MD_getsockopt +extern PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, + PRInt32 optname, const char* optval, PRInt32 optlen); +#define _MD_SETSOCKOPT _MD_setsockopt + +extern PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable); +#define _MD_SET_FD_INHERITABLE _MD_set_fd_inheritable + +extern void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported); +#define _MD_INIT_FD_INHERITABLE _MD_init_fd_inheritable + +extern void _MD_query_fd_inheritable(PRFileDesc *fd); +#define _MD_QUERY_FD_INHERITABLE _MD_query_fd_inheritable + +extern PRStatus _MD_gethostname(char *name, PRUint32 namelen); +#define _MD_GETHOSTNAME _MD_gethostname + +extern PRStatus _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen); +#define _MD_GETSYSINFO _MD_getsysinfo + +extern int _MD_unix_get_nonblocking_connect_error(int osfd); + +/* Memory-mapped files */ + +struct _MDFileMap { + PRIntn prot; + PRIntn flags; + PRBool isAnonFM; /* when true, PR_CloseFileMap() must close the related fd */ +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +#define _MD_GET_MEM_MAP_ALIGNMENT() PR_GetPageSize() + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +/* + * The standard (XPG4) gettimeofday() (from BSD) takes two arguments. + * On some SVR4 derivatives, gettimeofday() takes only one argument. + * The GETTIMEOFDAY macro is intended to hide this difference. + */ +#ifdef HAVE_SVID_GETTOD +#define GETTIMEOFDAY(tp) gettimeofday(tp) +#else +#define GETTIMEOFDAY(tp) gettimeofday((tp), NULL) +#endif + +#if defined(_PR_PTHREADS) && !defined(_PR_POLL_AVAILABLE) +#define _PR_NEED_FAKE_POLL +#endif + +#if defined(_PR_NEED_FAKE_POLL) + +/* + * Some platforms don't have poll(), but our pthreads code calls poll(). + * As a temporary measure, I implemented a fake poll() using select(). + * Here are the struct and macro definitions copied from sys/poll.h + * on Solaris 2.5. + */ + +struct pollfd { + int fd; + short events; + short revents; +}; + +/* poll events */ + +#define POLLIN 0x0001 /* fd is readable */ +#define POLLPRI 0x0002 /* high priority info at fd */ +#define POLLOUT 0x0004 /* fd is writeable (won't block) */ +#define POLLRDNORM 0x0040 /* normal data is readable */ +#define POLLWRNORM POLLOUT +#define POLLRDBAND 0x0080 /* out-of-band data is readable */ +#define POLLWRBAND 0x0100 /* out-of-band data is writeable */ + +#define POLLNORM POLLRDNORM + +#define POLLERR 0x0008 /* fd has error condition */ +#define POLLHUP 0x0010 /* fd has been hung up on */ +#define POLLNVAL 0x0020 /* invalid pollfd entry */ + +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 PRInt64 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; +typedef off64_t _MDOff64_t; + +#elif defined(_PR_HAVE_OFF64_T) +typedef struct stat64 _MDStat64; +typedef off64_t _MDOff64_t; +#elif defined(_PR_HAVE_LARGE_OFF_T) +typedef struct stat _MDStat64; +typedef off_t _MDOff64_t; +#elif defined(_PR_NO_LARGE_FILES) +typedef struct stat _MDStat64; +typedef PRInt64 _MDOff64_t; +#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, ...); +#if defined(VMS) +typedef PRIntn (*_MD_Stat64)(const char *path, _MDStat64 *buf, ...); +#else +typedef PRIntn (*_MD_Stat64)(const char *path, _MDStat64 *buf); +#endif +typedef _MDOff64_t (*_MD_Lseek64)(PRIntn osfd, _MDOff64_t, PRIntn whence); +typedef void* (*_MD_Mmap64)( + void *addr, PRSize len, PRIntn prot, PRIntn flags, + PRIntn fildes, _MDOff64_t offset); +struct _MD_IOVector +{ + _MD_Open64 _open64; + _MD_Mmap64 _mmap64; + _MD_Stat64 _stat64; + _MD_Fstat64 _fstat64; + _MD_Lseek64 _lseek64; +}; +extern struct _MD_IOVector _md_iovector; + +#endif /* prunixos_h___ */ diff --git a/nsprpub/pr/include/md/_unixware.cfg b/nsprpub/pr/include/md/_unixware.cfg new file mode 100644 index 00000000000..796e748d73a --- /dev/null +++ b/nsprpub/pr/include/md/_unixware.cfg @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef UNIXWARE +#define UNIXWARE +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef 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 + +#define _PR_POLL_BACKCOMPAT + +#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/nsprpub/pr/include/md/_unixware.h b/nsprpub/pr/include/md/_unixware.h new file mode 100644 index 00000000000..bdc084f23df --- /dev/null +++ b/nsprpub/pr/include/md/_unixware.h @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_unixware_defs_h___ +#define nspr_unixware_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "unixware" +#define _PR_SI_SYSNAME "UnixWare" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ST_ATIM_UNION + +#undef HAVE_STACK_GROWING_UP +#define HAVE_NETCONFIG +#define HAVE_DLL +#define USE_DLFCN +#define HAVE_STRERROR +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_NEED_STRCASECMP + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _MD_GET_SP(_t) (_t)->md.context[4] +#define _PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_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); \ + _LONGJMP(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures. + * Don't use SVR4 native threads (yet). + */ + +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; +}; + +/* + * 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; +}; + +#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() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#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) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#include +#include +#include +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *execptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +#endif /* nspr_unixware_defs_h___ */ diff --git a/nsprpub/pr/include/md/_unixware7.cfg b/nsprpub/pr/include/md/_unixware7.cfg new file mode 100644 index 00000000000..6444b00b613 --- /dev/null +++ b/nsprpub/pr/include/md/_unixware7.cfg @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef UNIXWARE +#define UNIXWARE +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_AF_INET6 27 /* same as AF_INET6 */ + +#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 + +#define _PR_POLL_BACKCOMPAT + +#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/nsprpub/pr/include/md/_win16.cfg b/nsprpub/pr/include/md/_win16.cfg new file mode 100644 index 00000000000..330db386e34 --- /dev/null +++ b/nsprpub/pr/include/md/_win16.cfg @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** _win16.cfg -- prcpucfg.h for win16 +** +** +** lth. 14-Apr-1997. New. Made from _win95.cfg +*/ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_PC +#define XP_PC +#endif + +#ifndef WIN16 +#define WIN16 +#undef WIN32 +#endif + +#if defined(_M_IX86) || defined(_X86_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 2 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 16 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 4 +#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_WORD_LOG2 4 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 2 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 2 +#define PR_ALIGN_OF_DWORD 8 +#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 2 + +#else /* defined(_M_IX86) || defined(_X86_) */ + +#error unknown processor architecture + +#endif /* defined(_M_IX86) || defined(_X86_) */ + +#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 */ + +#undef HAVE_LONG_LONG + +/* +** HAVE_WATCOM_BUG_1 +** When HAVE_WATCOM_BUG_1 is defined, special case code is +** used to circumvent the bug. +** Functions declared __cdecl in DLLs returning floating point types +** generate bad return code and will not return the intended result. +*/ +#define HAVE_WATCOM_BUG_1 + +/* +** HAVE_WATCOM_BUG_2 +** When HAVE_WATCOM_BUG_2 is defined, special case code is +** used to circumvent the bug. +** Functions declared __cdecl in DLLs returning a structure by value +** generate bad return values. +** Yes, similar to Watcom Bug 1. +*/ +#define HAVE_WATCOM_BUG_2 + +#endif /* nspr_cpucfg___ */ diff --git a/nsprpub/pr/include/md/_win16.h b/nsprpub/pr/include/md/_win16.h new file mode 100644 index 00000000000..d7e79c2221f --- /dev/null +++ b/nsprpub/pr/include/md/_win16.h @@ -0,0 +1,568 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_win16_defs_h___ +#define nspr_win16_defs_h___ + +#include +#include +#include +#include + +#include "nspr.h" +/* $$ fix this */ +#define Remind(x) + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "win16" +#define _PR_SI_SYSNAME "WIN16" +#define _PR_SI_ARCHITECTURE "x86" /* XXXMB hardcode for now */ + +#define HAVE_DLL +#define _PR_NO_PREEMPT +#define _PR_LOCAL_THREADS_ONLY +#undef _PR_GLOBAL_THREADS_ONLY +#undef HAVE_THREAD_AFFINITY +#define _PR_HAVE_ATOMIC_OPS + +/* --- Common User-Thread/Native-Thread Definitions --------------------- */ + +extern struct PRLock *_pr_schedLock; +extern char * _pr_top_of_task_stack; + + +/* --- Typedefs --- */ + +#define PR_NUM_GCREGS 9 +typedef PRInt32 PR_CONTEXT_TYPE[PR_NUM_GCREGS]; + +#define _MD_MAGIC_THREAD 0x22222222 +#define _MD_MAGIC_THREADSTACK 0x33333333 +#define _MD_MAGIC_SEGMENT 0x44444444 +#define _MD_MAGIC_DIR 0x55555555 +#define _MD_MAGIC_CV 0x66666666 + + +typedef struct _PRWin16PollDesc +{ + PRInt32 osfd; + PRInt16 in_flags; + PRInt16 out_flags; +} _PRWin16PollDesc; + +typedef struct PRPollQueue +{ + PRCList links; /* for linking PRPollQueue's together */ + _PRWin16PollDesc *pds; /* array of poll descriptors */ + PRUintn npds; /* length of the array */ + PRPackedBool on_ioq; /* is this on the async i/o work q? */ + PRIntervalTime timeout; /* timeout, in ticks */ + struct PRThread *thr; +} PRPollQueue; + +#define _PR_POLLQUEUE_PTR(_qp) \ + ((PRPollQueue *) ((char*) (_qp) - offsetof(PRPollQueue,links))) + +NSPR_API(PRInt32) _PR_WaitForFD(PRInt32 osfd, PRUintn how, + PRIntervalTime timeout); +NSPR_API(void) _PR_Unblock_IO_Wait(struct PRThread *thr); + +#define _PR_MD_MAX_OSFD FD_SETSIZE +#define _PR_IOQ(_cpu) ((_cpu)->md.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.ioq_max_osfd) + +struct _MDCPU { + PRCList ioQ; + 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]; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; +}; + +struct _MDThread { + /* The overlapped structure must be first! */ + HANDLE blocked_sema; /* Threads block on this when waiting + * for IO or CondVar. + */ + PRInt32 errcode; /* preserved errno for this thread */ + CATCHBUF context; /* thread context for Throw() */ + void *SP; /* Stack pointer, used only by GarbColl */ + int threadNumber; /* instrumentation: order of creation */ + _PRWin16PollDesc thr_pd; /* poll descriptor for i/o */ + PRPollQueue thr_pq; /* i/o parameters */ + void *exceptionContext; /* mfc exception context */ + char guardBand[24]; /* don't overwrite this */ + PRUint32 magic; /* self identifier, for debug */ +}; + +struct _MDThreadStack { + PRUint32 magic; /* for debugging */ + PRIntn cxByteCount; /* number of stack bytes to move */ + char * stackTop; /* high address on stack */ +}; + +struct _MDSegment { + PRUint32 magic; /* for debugging */ +}; + + +struct _MDLock { + PRUint32 magic; /* for debugging */ + PRUint32 mutex; +}; + +struct _MDDir { + PRUint32 magic; /* for debugging */ + struct dirent *dir; +}; + +struct _MDCVar { + PRUint32 magic; +}; + +struct _MDSemaphore { + PRInt32 unused; +}; + +struct _MDFileDesc { + PRInt32 osfd; +}; + +struct _MDProcess { + HANDLE handle; + DWORD id; +}; + +/* +** Microsoft 'struct _stat' +** ... taken directly from msvc 1.52c's header file sys/stat.h +** see PR_Stat() implemented in w16io.c +** See BugSplat: 98516 +*/ +#pragma pack(push) +#pragma pack(2) + +typedef unsigned short _ino_t; +typedef short _dev_t; +typedef long _off_t; + +typedef struct _MDMSStat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +} _MDMSStat; +#pragma pack(pop) + +/* --- Errors --- */ + /* These are NSPR generated error codes which need to be unique from + * OS error codes. + */ +#define _MD_UNIQUEBASE 50000 +#define _MD_EINTERRUPTED _MD_UNIQUEBASE + 1 +#define _MD_ETIMEDOUT _MD_UNIQUEBASE + 2 +#define _MD_EIO _MD_UNIQUEBASE + 3 + +struct PRProcess; +struct PRProcessAttr; + +/* --- Create a new process --- */ +#define _MD_CREATE_PROCESS _PR_CreateWindowsProcess +extern struct PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _PR_DetachWindowsProcess +extern PRStatus _PR_DetachWindowsProcess(struct PRProcess *process); + +/* --- Wait for a child process to terminate --- */ +#define _MD_WAIT_PROCESS _PR_WaitWindowsProcess +extern PRStatus _PR_WaitWindowsProcess(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _PR_KillWindowsProcess +extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); + + +/* --- Misc stuff --- */ + +#define MD_ASSERTINT( x ) PR_ASSERT( (x) < 65535 ) + +/* --- IO stuff --- */ +#define MAX_PATH 256 +#define _MD_ERRNO() errno +#define GetLastError() errno + +#define _MD_GET_FILE_ERROR() errno +#define _MD_SET_FILE_ERROR(_err) errno = (_err) + +#define _MD_OPEN _PR_MD_OPEN +#define _MD_READ _PR_MD_READ +#define _MD_WRITE _PR_MD_WRITE +#define _MD_WRITEV _PR_MD_WRITEV +#define _MD_LSEEK _PR_MD_LSEEK +#define _MD_LSEEK64 _PR_MD_LSEEK64 +#define _MD_CLOSE_FILE _PR_MD_CLOSE_FILE +#define _MD_GETFILEINFO _PR_MD_GETFILEINFO +#define _MD_GETOPENFILEINFO _PR_MD_GETOPENFILEINFO +#define _MD_STAT _PR_MD_STAT +#define _MD_RENAME _PR_MD_RENAME +#define _MD_ACCESS _PR_MD_ACCESS +#define _MD_DELETE _PR_MD_DELETE +#define _MD_MKDIR _PR_MD_MKDIR +#define _MD_RMDIR _PR_MD_RMDIR +#define _MD_LOCKFILE _PR_MD_LOCKFILE +#define _MD_TLOCKFILE _PR_MD_TLOCKFILE +#define _MD_UNLOCKFILE _PR_MD_UNLOCKFILE + + +/* --- Socket IO stuff --- */ +#define _MD_EACCES WSAEACCES +#define _MD_EADDRINUSE WSAEADDRINUSE +#define _MD_EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define _MD_EAFNOSUPPORT WSAEAFNOSUPPORT +#define _MD_EAGAIN WSAEWOULDBLOCK +#define _MD_EALREADY WSAEALREADY +#define _MD_EBADF WSAEBADF +#define _MD_ECONNREFUSED WSAECONNREFUSED +#define _MD_ECONNRESET WSAECONNRESET +#define _MD_EFAULT WSAEFAULT +#define _MD_EINPROGRESS WSAEINPROGRESS +#define _MD_EINTR WSAEINTR +#define _MD_EINVAL EINVAL +#define _MD_EISCONN WSAEISCONN +#define _MD_ENETUNREACH WSAENETUNREACH +#define _MD_ENOENT ENOENT +#define _MD_ENOTCONN WSAENOTCONN +#define _MD_ENOTSOCK WSAENOTSOCK +#define _MD_EOPNOTSUPP WSAEOPNOTSUPP +#define _MD_EWOULDBLOCK WSAEWOULDBLOCK +#define _MD_GET_SOCKET_ERROR() WSAGetLastError() +#define _MD_SET_SOCKET_ERROR(_err) WSASetLastError(_err) + +#define _MD_INIT_FILEDESC(fd) +#define _MD_MAKE_NONBLOCK _PR_MD_MAKE_NONBLOCK +#define _MD_SHUTDOWN _PR_MD_SHUTDOWN +#define _MD_LISTEN _PR_MD_LISTEN +#define _MD_CLOSE_SOCKET _PR_MD_CLOSE_SOCKET +#define _MD_SENDTO _PR_MD_SENDTO +#define _MD_RECVFROM _PR_MD_RECVFROM +#define _MD_SOCKETPAIR(s, type, proto, sv) -1 +#define _MD_GETSOCKNAME _PR_MD_GETSOCKNAME +#define _MD_GETPEERNAME _PR_MD_GETPEERNAME +#define _MD_GETSOCKOPT _PR_MD_GETSOCKOPT +#define _MD_SETSOCKOPT _PR_MD_SETSOCKOPT +#define _MD_SELECT select +#define _MD_FSYNC _PR_MD_FSYNC +#define _MD_SOCKETAVAILABLE _PR_MD_SOCKETAVAILABLE + +#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) + +#define _MD_INIT_IO _PR_MD_INIT_IO + +/* win95 doesn't have async IO */ +#define _MD_SOCKET _PR_MD_SOCKET +#define _MD_CONNECT _PR_MD_CONNECT +#define _MD_ACCEPT _PR_MD_ACCEPT +#define _MD_BIND _PR_MD_BIND +#define _MD_RECV _PR_MD_RECV +#define _MD_SEND _PR_MD_SEND + +#define _MD_CHECK_FOR_EXIT() + +/* --- Scheduler stuff --- */ +#define _MD_PAUSE_CPU _PR_MD_PAUSE_CPU + +/* --- DIR stuff --- */ +#define PR_DIRECTORY_SEPARATOR '\\' +#define PR_DIRECTORY_SEPARATOR_STR "\\" +#define PR_PATH_SEPARATOR ';' +#define PR_PATH_SEPARATOR_STR ";" +#define _MD_OPEN_DIR _PR_MD_OPEN_DIR +#define _MD_CLOSE_DIR _PR_MD_CLOSE_DIR +#define _MD_READ_DIR _PR_MD_READ_DIR + +/* --- Segment stuff --- */ +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT _MD_AllocSegment +#define _MD_FREE_SEGMENT _MD_FreeSegment + +/* --- Environment Stuff --- */ +#define _MD_GET_ENV _PR_MD_GET_ENV +#define _MD_PUT_ENV _PR_MD_PUT_ENV + +/* --- Threading Stuff --- */ +#define _MD_DEFAULT_STACK_SIZE 32767L +#define _MD_INIT_THREAD _PR_MD_INIT_THREAD +#define _MD_CREATE_THREAD(t,f,p,sc,st,stsiz) (PR_SUCCESS) +#define _MD_YIELD _PR_MD_YIELD +#define _MD_SET_PRIORITY(t,p) +#define _MD_CLEAN_THREAD(t) +#define _MD_SETTHREADAFFINITYMASK _PR_MD_SETTHREADAFFINITYMASK +#define _MD_GETTHREADAFFINITYMASK _PR_MD_GETTHREADAFFINITYMASK +#define _MD_EXIT_THREAD +#define _MD_SUSPEND_THREAD _PR_MD_SUSPEND_THREAD +#define _MD_RESUME_THREAD _PR_MD_RESUME_THREAD +#define _MD_SUSPEND_CPU _PR_MD_SUSPEND_CPU +#define _MD_RESUME_CPU _PR_MD_RESUME_CPU +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_END_RESUME_ALL() + +/* --- Lock stuff --- */ +/* +** Win16 does not need MD locks. +*/ +#define _PR_LOCK _MD_LOCK +#define _PR_UNLOCK _MD_UNLOCK + +#define _MD_NEW_LOCK(l) (PR_SUCCESS) +#define _MD_FREE_LOCK(l) +#define _MD_LOCK(l) +#define _MD_TEST_AND_LOCK(l) (-1) +#define _MD_UNLOCK(l) + +/* --- lock and cv waiting --- */ +#define _MD_WAIT _PR_MD_WAIT +#define _MD_WAKEUP_WAITER(a) +#define _MD_WAKEUP_CPUS _PR_MD_WAKEUP_CPUS + +/* --- CVar ------------------- */ +#define _MD_WAIT_CV _PR_MD_WAIT_CV +#define _MD_NEW_CV _PR_MD_NEW_CV +#define _MD_FREE_CV _PR_MD_FREE_CV +#define _MD_NOTIFY_CV _PR_MD_NOTIFY_CV +#define _MD_NOTIFYALL_CV _PR_MD_NOTIFYALL_CV + + /* XXXMB- the IOQ stuff is certainly not working correctly yet. */ +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + + +/* --- Initialization stuff --- */ +NSPR_API(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 +#define _MD_FINAL_INIT _PR_MD_FINAL_INIT +#define _MD_INIT_CPUS() + +/* --- User Threading stuff --- */ +#define _MD_EXIT + +#define _MD_CLEANUP_BEFORE_EXIT _PR_MD_CLEANUP_BEFORE_EXIT + +/* --- Intervals --- */ +#define _MD_INTERVAL_INIT _PR_MD_INTERVAL_INIT +#define _MD_GET_INTERVAL _PR_MD_GET_INTERVAL +#define _MD_INTERVAL_PER_SEC _PR_MD_INTERVAL_PER_SEC +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/* --- Scheduler stuff --- */ +#define LOCK_SCHEDULER() 0 +#define UNLOCK_SCHEDULER() 0 +#define _PR_LockSched() 0 +#define _PR_UnlockSched() 0 + +/* --- Initialization stuff --- */ +#define _MD_INIT_LOCKS() + +/* --- Stack stuff --- */ +#define _MD_INIT_STACK _PR_MD_INIT_STACK +#define _MD_CLEAR_STACK(stack) + +/* +** Watcom needs to see this to make the linker work. +** +*/ +NSPR_API(void) _PR_NativeDestroyThread(PRThread *thread); +NSPR_API(void) _PR_UserDestroyThread(PRThread *thread); + + +/* +** If thread emulation is used, then setjmp/longjmp stores the register +** state of each thread. +** +** CatchBuf layout: +** context[0] - IP +** context[1] - CS +** context[2] - SP +** context[3] - BP +** context[4] - SI +** context[5] - DI +** context[6] - DS +** context[7] - ?? (maybe flags) +** context[8] - SS +*/ +#define PR_CONTEXT_TYPE CATCHBUF +#define PR_NUM_GCREGS 9 + +#define _MD_GET_SP(thread) ((thread)->md.SP) +#define CONTEXT(_t) ((_t)->md.context) + +/* +** Initialize a thread context to run "e(o,a)" when started +*/ +#define _MD_INIT_CONTEXT(_t, sp, epa, stat ) \ +{ \ + *(stat) = PR_TRUE; \ + Catch((_t)->md.context ); \ + (_t)->md.context[0] = OFFSETOF(epa); \ + (_t)->md.context[1] = SELECTOROF(epa); \ + (_t)->md.context[2] = OFFSETOF(_pr_top_of_task_stack - 64); \ + (_t)->md.context[3] = 0; \ +} + +#define _MD_SWITCH_CONTEXT(_t) \ + if (!Catch((_t)->md.context)) { \ + int garbCollPlaceHolder; \ + (_t)->md.errcode = errno; \ + (_t)->md.SP = &garbCollPlaceHolder; \ + _PR_Schedule(); \ + } + +#define _MD_SAVE_CONTEXT(_t) \ + { \ + int garbCollPlaceHolder; \ + Catch((_t)->md.context); \ + (_t)->md.errcode = errno; \ + (_t)->md.SP = &garbCollPlaceHolder; \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _PR_MD_RESTORE_CONTEXT _MD_RESTORE_CONTEXT + +/* + * Memory-mapped files + */ + +struct _MDFileMap { + PRInt8 unused; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + + +/* --- Error mapping ----------------------------------- */ +extern void _PR_MD_map_error( int err ); + +#define _PR_MD_MAP_OPENDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_CLOSEDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_READDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_DELETE_ERROR _PR_MD_map_error +#define _PR_MD_MAP_STAT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_FSTAT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_RENAME_ERROR _PR_MD_map_error +#define _PR_MD_MAP_ACCESS_ERROR _PR_MD_map_error +#define _PR_MD_MAP_MKDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_RMDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_READ_ERROR _PR_MD_map_error +#define _PR_MD_MAP_TRANSMITFILE_ERROR _PR_MD_map_error +#define _PR_MD_MAP_WRITE_ERROR _PR_MD_map_error +#define _PR_MD_MAP_LSEEK_ERROR _PR_MD_map_error +#define _PR_MD_MAP_FSYNC_ERROR _PR_MD_map_error +#define _PR_MD_MAP_CLOSE_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SOCKET_ERROR _PR_MD_map_error +#define _PR_MD_MAP_RECV_ERROR _PR_MD_map_error +#define _PR_MD_MAP_RECVFROM_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SEND_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SENDTO_ERROR _PR_MD_map_error +#define _PR_MD_MAP_ACCEPT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_ACCEPTEX_ERROR _PR_MD_map_error +#define _PR_MD_MAP_CONNECT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_BIND_ERROR _PR_MD_map_error +#define _PR_MD_MAP_LISTEN_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SHUTDOWN_ERROR _PR_MD_map_error +#define _PR_MD_MAP_GETSOCKNAME_ERROR _PR_MD_map_error +#define _PR_MD_MAP_GETPEERNAME_ERROR _PR_MD_map_error +#define _PR_MD_MAP_GETSOCKOPT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SETSOCKOPT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_OPEN_ERROR _PR_MD_map_error +#define _PR_MD_MAP_GETHOSTNAME_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SELECT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_LOCKF_ERROR _PR_MD_map_error +#define _PR_MD_MAP_WSASTARTUP_ERROR _PR_MD_map_error + +#endif /* nspr_win16_defs_h___ */ diff --git a/nsprpub/pr/include/md/_win32_errors.h b/nsprpub/pr/include/md/_win32_errors.h new file mode 100644 index 00000000000..d5d8b714236 --- /dev/null +++ b/nsprpub/pr/include/md/_win32_errors.h @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_win32_errors_h___ +#define nspr_win32_errors_h___ + +#include +#include +#include + + +extern void _MD_win32_map_default_error(PRInt32 err); +#define _PR_MD_MAP_DEFAULT_ERROR _MD_win32_map_default_error + +extern void _MD_win32_map_opendir_error(PRInt32 err); +#define _PR_MD_MAP_OPENDIR_ERROR _MD_win32_map_opendir_error + +extern void _MD_win32_map_closedir_error(PRInt32 err); +#define _PR_MD_MAP_CLOSEDIR_ERROR _MD_win32_map_closedir_error + +extern void _MD_unix_readdir_error(PRInt32 err); +#define _PR_MD_MAP_READDIR_ERROR _MD_unix_readdir_error + +extern void _MD_win32_map_delete_error(PRInt32 err); +#define _PR_MD_MAP_DELETE_ERROR _MD_win32_map_delete_error + +extern void _MD_win32_map_stat_error(PRInt32 err); +#define _PR_MD_MAP_STAT_ERROR _MD_win32_map_stat_error + +extern void _MD_win32_map_fstat_error(PRInt32 err); +#define _PR_MD_MAP_FSTAT_ERROR _MD_win32_map_fstat_error + +extern void _MD_win32_map_rename_error(PRInt32 err); +#define _PR_MD_MAP_RENAME_ERROR _MD_win32_map_rename_error + +extern void _MD_win32_map_access_error(PRInt32 err); +#define _PR_MD_MAP_ACCESS_ERROR _MD_win32_map_access_error + +extern void _MD_win32_map_mkdir_error(PRInt32 err); +#define _PR_MD_MAP_MKDIR_ERROR _MD_win32_map_mkdir_error + +extern void _MD_win32_map_rmdir_error(PRInt32 err); +#define _PR_MD_MAP_RMDIR_ERROR _MD_win32_map_rmdir_error + +extern void _MD_win32_map_read_error(PRInt32 err); +#define _PR_MD_MAP_READ_ERROR _MD_win32_map_read_error + +extern void _MD_win32_map_transmitfile_error(PRInt32 err); +#define _PR_MD_MAP_TRANSMITFILE_ERROR _MD_win32_map_transmitfile_error + +extern void _MD_win32_map_write_error(PRInt32 err); +#define _PR_MD_MAP_WRITE_ERROR _MD_win32_map_write_error + +extern void _MD_win32_map_lseek_error(PRInt32 err); +#define _PR_MD_MAP_LSEEK_ERROR _MD_win32_map_lseek_error + +extern void _MD_win32_map_fsync_error(PRInt32 err); +#define _PR_MD_MAP_FSYNC_ERROR _MD_win32_map_fsync_error + +extern void _MD_win32_map_close_error(PRInt32 err); +#define _PR_MD_MAP_CLOSE_ERROR _MD_win32_map_close_error + +extern void _MD_win32_map_socket_error(PRInt32 err); +#define _PR_MD_MAP_SOCKET_ERROR _MD_win32_map_socket_error + +extern void _MD_win32_map_recv_error(PRInt32 err); +#define _PR_MD_MAP_RECV_ERROR _MD_win32_map_recv_error + +extern void _MD_win32_map_recvfrom_error(PRInt32 err); +#define _PR_MD_MAP_RECVFROM_ERROR _MD_win32_map_recvfrom_error + +extern void _MD_win32_map_send_error(PRInt32 err); +#define _PR_MD_MAP_SEND_ERROR _MD_win32_map_send_error + +extern void _MD_win32_map_sendto_error(PRInt32 err); +#define _PR_MD_MAP_SENDTO_ERROR _MD_win32_map_sendto_error + +extern void _MD_win32_map_accept_error(PRInt32 err); +#define _PR_MD_MAP_ACCEPT_ERROR _MD_win32_map_accept_error + +extern void _MD_win32_map_acceptex_error(PRInt32 err); +#define _PR_MD_MAP_ACCEPTEX_ERROR _MD_win32_map_acceptex_error + +extern PRInt32 _MD_win32_map_connect_error(PRInt32 err); +#define _PR_MD_MAP_CONNECT_ERROR _MD_win32_map_connect_error + +extern void _MD_win32_map_bind_error(PRInt32 err); +#define _PR_MD_MAP_BIND_ERROR _MD_win32_map_bind_error + +extern void _MD_win32_map_listen_error(PRInt32 err); +#define _PR_MD_MAP_LISTEN_ERROR _MD_win32_map_listen_error + +extern void _MD_win32_map_shutdown_error(PRInt32 err); +#define _PR_MD_MAP_SHUTDOWN_ERROR _MD_win32_map_shutdown_error + +extern void _MD_win32_map_getsockname_error(PRInt32 err); +#define _PR_MD_MAP_GETSOCKNAME_ERROR _MD_win32_map_getsockname_error + +extern void _MD_win32_map_getpeername_error(PRInt32 err); +#define _PR_MD_MAP_GETPEERNAME_ERROR _MD_win32_map_getpeername_error + +extern void _MD_win32_map_getsockopt_error(PRInt32 err); +#define _PR_MD_MAP_GETSOCKOPT_ERROR _MD_win32_map_getsockopt_error + +extern void _MD_win32_map_setsockopt_error(PRInt32 err); +#define _PR_MD_MAP_SETSOCKOPT_ERROR _MD_win32_map_setsockopt_error + +extern void _MD_win32_map_open_error(PRInt32 err); +#define _PR_MD_MAP_OPEN_ERROR _MD_win32_map_open_error + +extern void _MD_win32_map_gethostname_error(PRInt32 err); +#define _PR_MD_MAP_GETHOSTNAME_ERROR _MD_win32_map_gethostname_error + +extern void _MD_win32_map_select_error(PRInt32 err); +#define _PR_MD_MAP_SELECT_ERROR _MD_win32_map_select_error + +extern void _MD_win32_map_lockf_error(int err); +#define _PR_MD_MAP_LOCKF_ERROR _MD_win32_map_lockf_error + +#endif /* nspr_win32_errors_h___ */ diff --git a/nsprpub/pr/include/md/_win95.cfg b/nsprpub/pr/include/md/_win95.cfg new file mode 100644 index 00000000000..026258b8c30 --- /dev/null +++ b/nsprpub/pr/include/md/_win95.cfg @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_PC +#define XP_PC +#endif + +#ifndef WIN32 +#define WIN32 +#endif + +#ifndef WIN95 +#define WIN95 +#endif + +#define PR_AF_INET6 23 /* same as AF_INET6 */ + +#if defined(_M_IX86) || defined(_X86_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#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_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 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_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 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 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#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 2 + +#elif defined(_ALPHA_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#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_BYTES_PER_WORD_LOG2 2 +#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 + +#elif defined(_AMD64_) + +#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 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 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_WORD 64 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 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 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 +#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(_IA64_) + +#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 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 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_WORD 64 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 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 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 +#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 + +#else /* defined(_M_IX86) || defined(_X86_) */ + +#error unknown processor architecture + +#endif /* defined(_M_IX86) || defined(_X86_) */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#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/nsprpub/pr/include/md/_win95.h b/nsprpub/pr/include/md/_win95.h new file mode 100644 index 00000000000..db1e8d47964 --- /dev/null +++ b/nsprpub/pr/include/md/_win95.h @@ -0,0 +1,562 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_win95_defs_h___ +#define nspr_win95_defs_h___ + +#include "prio.h" + +#include +#include +#include + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "win32" +#define _PR_SI_SYSNAME "WIN95" +#if defined(_M_IX86) || defined(_X86_) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(_AMD64_) +#define _PR_SI_ARCHITECTURE "x86-64" +#elif defined(_IA64_) +#define _PR_SI_ARCHITECTURE "ia64" +#else +#error unknown processor architecture +#endif + +#define HAVE_DLL +#undef HAVE_THREAD_AFFINITY +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#ifndef _PR_INET6 +#define AF_INET6 23 +/* newer ws2tcpip.h provides these */ +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x2 +#define AI_NUMERICHOST 0x4 +#define NI_NUMERICHOST 0x02 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#define _PR_HAVE_MD_SOCKADDR_IN6 +/* isomorphic to struct in6_addr on Windows */ +struct _md_in6_addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + } _S6_un; +}; +/* isomorphic to struct sockaddr_in6 on Windows */ +struct _md_sockaddr_in6 { + PRInt16 sin6_family; + PRUint16 sin6_port; + PRUint32 sin6_flowinfo; + struct _md_in6_addr sin6_addr; + PRUint32 sin6_scope_id; +}; +#endif +#define _PR_HAVE_THREADSAFE_GETHOST +#define _PR_HAVE_ATOMIC_OPS +#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY + +/* --- Common User-Thread/Native-Thread Definitions --------------------- */ + +/* --- Globals --- */ +extern struct PRLock *_pr_schedLock; + +/* --- Typedefs --- */ +typedef void (*FiberFunc)(void *); + +#define PR_NUM_GCREGS 8 +typedef PRInt32 PR_CONTEXT_TYPE[PR_NUM_GCREGS]; +#define GC_VMBASE 0x40000000 +#define GC_VMLIMIT 0x00FFFFFF + +#define _MD_MAGIC_THREAD 0x22222222 +#define _MD_MAGIC_THREADSTACK 0x33333333 +#define _MD_MAGIC_SEGMENT 0x44444444 +#define _MD_MAGIC_DIR 0x55555555 +#define _MD_MAGIC_CV 0x66666666 + +struct _MDCPU { + int unused; +}; + +struct _MDThread { + HANDLE blocked_sema; /* Threads block on this when waiting + * for IO or CondVar. + */ + PRBool inCVWaitQueue; /* PR_TRUE if the thread is in the + * wait queue of some cond var. + * PR_FALSE otherwise. */ + HANDLE handle; /* Win32 thread handle */ + PRUint32 id; + void *sp; /* only valid when suspended */ + PRUint32 magic; /* for debugging */ + PR_CONTEXT_TYPE gcContext; /* Thread context for GC */ + struct PRThread *prev, *next; /* used by the cvar wait queue to + * chain the PRThread structures + * together */ + void (*start)(void *); /* used by _PR_MD_CREATE_THREAD to + * pass its 'start' argument to + * pr_root. */ +}; + +struct _MDThreadStack { + PRUint32 magic; /* for debugging */ +}; + +struct _MDSegment { + PRUint32 magic; /* for debugging */ +}; + +#undef PROFILE_LOCKS + +struct _MDDir { + HANDLE d_hdl; + WIN32_FIND_DATA d_entry; + PRBool firstEntry; /* Is this the entry returned + * by FindFirstFile()? */ + PRUint32 magic; /* for debugging */ +}; + +#ifdef MOZ_UNICODE +struct _MDDirUTF16 { + HANDLE d_hdl; + WIN32_FIND_DATAW d_entry; + PRBool firstEntry; /* Is this the entry returned + * by FindFirstFileW()? */ + PRUint32 magic; /* for debugging */ +}; +#endif /* MOZ_UNICODE */ + +struct _MDCVar { + PRUint32 magic; + struct PRThread *waitHead, *waitTail; /* the wait queue: a doubly- + * linked list of threads + * waiting on this condition + * variable */ + PRIntn nwait; /* number of threads in the + * wait queue */ +}; + +#define _MD_CV_NOTIFIED_LENGTH 6 +typedef struct _MDNotified _MDNotified; +struct _MDNotified { + PRIntn length; /* # of used entries in this + * structure */ + struct { + struct _MDCVar *cv; /* the condition variable notified */ + PRIntn times; /* and the number of times notified */ + struct PRThread *notifyHead; /* list of threads to wake up */ + } cv[_MD_CV_NOTIFIED_LENGTH]; + _MDNotified *link; /* link to another of these, or NULL */ +}; + +struct _MDLock { + CRITICAL_SECTION mutex; /* this is recursive on NT */ + + /* + * When notifying cvars, there is no point in actually + * waking up the threads waiting on the cvars until we've + * released the lock. So, we temporarily record the cvars. + * When doing an unlock, we'll then wake up the waiting threads. + */ + struct _MDNotified notified; /* array of conditions notified */ +#ifdef PROFILE_LOCKS + PRInt32 hitcount; + PRInt32 misscount; +#endif +}; + +struct _MDSemaphore { + HANDLE sem; +}; + +struct _MDFileDesc { + PROsfd osfd; /* The osfd can come from one of three spaces: + * - For stdin, stdout, and stderr, we are using + * the libc file handle (0, 1, 2), which is an int. + * - For files and pipes, we are using Win32 HANDLE, + * which is a void*. + * - For sockets, we are using Winsock SOCKET, which + * is a u_int. + */ +}; + +struct _MDProcess { + HANDLE handle; + DWORD id; +}; + +/* --- Misc stuff --- */ +#define _MD_GET_SP(thread) (thread)->md.gcContext[6] + +/* --- NT security stuff --- */ + +extern void _PR_NT_InitSids(void); +extern void _PR_NT_FreeSids(void); +extern PRStatus _PR_NT_MakeSecurityDescriptorACL( + PRIntn mode, + DWORD accessTable[], + PSECURITY_DESCRIPTOR *resultSD, + PACL *resultACL +); +extern void _PR_NT_FreeSecurityDescriptorACL( + PSECURITY_DESCRIPTOR pSD, PACL pACL); + +/* --- IO stuff --- */ + +#define _MD_OPEN _PR_MD_OPEN +#define _MD_OPEN_FILE _PR_MD_OPEN_FILE +#define _MD_READ _PR_MD_READ +#define _MD_WRITE _PR_MD_WRITE +#define _MD_WRITEV _PR_MD_WRITEV +#define _MD_LSEEK _PR_MD_LSEEK +#define _MD_LSEEK64 _PR_MD_LSEEK64 +extern PRInt32 _MD_CloseFile(PROsfd osfd); +#define _MD_CLOSE_FILE _MD_CloseFile +#define _MD_GETFILEINFO _PR_MD_GETFILEINFO +#define _MD_GETFILEINFO64 _PR_MD_GETFILEINFO64 +#define _MD_GETOPENFILEINFO _PR_MD_GETOPENFILEINFO +#define _MD_GETOPENFILEINFO64 _PR_MD_GETOPENFILEINFO64 +#define _MD_STAT _PR_MD_STAT +#define _MD_RENAME _PR_MD_RENAME +#define _MD_ACCESS _PR_MD_ACCESS +#define _MD_DELETE _PR_MD_DELETE +#define _MD_MKDIR _PR_MD_MKDIR +#define _MD_MAKE_DIR _PR_MD_MAKE_DIR +#define _MD_RMDIR _PR_MD_RMDIR +#define _MD_LOCKFILE _PR_MD_LOCKFILE +#define _MD_TLOCKFILE _PR_MD_TLOCKFILE +#define _MD_UNLOCKFILE _PR_MD_UNLOCKFILE + +/* --- UTF16 IO stuff --- */ +extern PRBool _pr_useUnicode; +#ifdef MOZ_UNICODE +#define _MD_OPEN_FILE_UTF16 _PR_MD_OPEN_FILE_UTF16 +#define _MD_OPEN_DIR_UTF16 _PR_MD_OPEN_DIR_UTF16 +#define _MD_READ_DIR_UTF16 _PR_MD_READ_DIR_UTF16 +#define _MD_CLOSE_DIR_UTF16 _PR_MD_CLOSE_DIR_UTF16 +#define _MD_GETFILEINFO64_UTF16 _PR_MD_GETFILEINFO64_UTF16 +#endif /* MOZ_UNICODE */ + +/* --- Socket IO stuff --- */ +extern void _PR_MD_InitSockets(void); +extern void _PR_MD_CleanupSockets(void); +#define _MD_EACCES WSAEACCES +#define _MD_EADDRINUSE WSAEADDRINUSE +#define _MD_EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define _MD_EAFNOSUPPORT WSAEAFNOSUPPORT +#define _MD_EAGAIN WSAEWOULDBLOCK +#define _MD_EALREADY WSAEALREADY +#define _MD_EBADF WSAEBADF +#define _MD_ECONNREFUSED WSAECONNREFUSED +#define _MD_ECONNRESET WSAECONNRESET +#define _MD_EFAULT WSAEFAULT +#define _MD_EINPROGRESS WSAEINPROGRESS +#define _MD_EINTR WSAEINTR +#define _MD_EINVAL EINVAL +#define _MD_EISCONN WSAEISCONN +#define _MD_ENETUNREACH WSAENETUNREACH +#define _MD_ENOENT ENOENT +#define _MD_ENOTCONN WSAENOTCONN +#define _MD_ENOTSOCK WSAENOTSOCK +#define _MD_EOPNOTSUPP WSAEOPNOTSUPP +#define _MD_EWOULDBLOCK WSAEWOULDBLOCK +#define _MD_GET_SOCKET_ERROR() WSAGetLastError() +#define _MD_SET_SOCKET_ERROR(_err) WSASetLastError(_err) + +#define _MD_INIT_FILEDESC(fd) +extern void _MD_MakeNonblock(PRFileDesc *f); +#define _MD_MAKE_NONBLOCK _MD_MakeNonblock +#define _MD_INIT_FD_INHERITABLE _PR_MD_INIT_FD_INHERITABLE +#define _MD_QUERY_FD_INHERITABLE _PR_MD_QUERY_FD_INHERITABLE +#define _MD_SHUTDOWN _PR_MD_SHUTDOWN +#define _MD_LISTEN _PR_MD_LISTEN +extern PRInt32 _MD_CloseSocket(PROsfd osfd); +#define _MD_CLOSE_SOCKET _MD_CloseSocket +#define _MD_SENDTO _PR_MD_SENDTO +#define _MD_RECVFROM _PR_MD_RECVFROM +#define _MD_SOCKETPAIR(s, type, proto, sv) -1 +#define _MD_GETSOCKNAME _PR_MD_GETSOCKNAME +#define _MD_GETPEERNAME _PR_MD_GETPEERNAME +#define _MD_GETSOCKOPT _PR_MD_GETSOCKOPT +#define _MD_SETSOCKOPT _PR_MD_SETSOCKOPT +#define _MD_SET_FD_INHERITABLE _PR_MD_SET_FD_INHERITABLE +#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) + +#define _MD_INIT_IO _PR_MD_INIT_IO + + +/* win95 doesn't have async IO */ +#define _MD_SOCKET _PR_MD_SOCKET +extern PRInt32 _MD_SocketAvailable(PRFileDesc *fd); +#define _MD_SOCKETAVAILABLE _MD_SocketAvailable +#define _MD_PIPEAVAILABLE _PR_MD_PIPEAVAILABLE +#define _MD_CONNECT _PR_MD_CONNECT +extern PROsfd _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, + PRIntervalTime timeout); +#define _MD_ACCEPT _MD_Accept +#define _MD_BIND _PR_MD_BIND +#define _MD_RECV _PR_MD_RECV +#define _MD_SEND _PR_MD_SEND +#define _MD_PR_POLL _PR_MD_PR_POLL + +/* --- Scheduler stuff --- */ +// #define _MD_PAUSE_CPU _PR_MD_PAUSE_CPU +#define _MD_PAUSE_CPU + +/* --- DIR stuff --- */ +#define PR_DIRECTORY_SEPARATOR '\\' +#define PR_DIRECTORY_SEPARATOR_STR "\\" +#define PR_PATH_SEPARATOR ';' +#define PR_PATH_SEPARATOR_STR ";" +#define _MD_ERRNO() GetLastError() +#define _MD_OPEN_DIR _PR_MD_OPEN_DIR +#define _MD_CLOSE_DIR _PR_MD_CLOSE_DIR +#define _MD_READ_DIR _PR_MD_READ_DIR + +/* --- Segment stuff --- */ +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT(seg, size, vaddr) 0 +#define _MD_FREE_SEGMENT(seg) + +/* --- Environment Stuff --- */ +#define _MD_GET_ENV _PR_MD_GET_ENV +#define _MD_PUT_ENV _PR_MD_PUT_ENV + +/* --- Threading Stuff --- */ +#define _MD_DEFAULT_STACK_SIZE 0 +#define _MD_INIT_THREAD _PR_MD_INIT_THREAD +#define _MD_INIT_ATTACHED_THREAD _PR_MD_INIT_THREAD +#define _MD_CREATE_THREAD _PR_MD_CREATE_THREAD +#define _MD_YIELD _PR_MD_YIELD +#define _MD_SET_PRIORITY _PR_MD_SET_PRIORITY +#define _MD_CLEAN_THREAD _PR_MD_CLEAN_THREAD +#define _MD_SETTHREADAFFINITYMASK _PR_MD_SETTHREADAFFINITYMASK +#define _MD_GETTHREADAFFINITYMASK _PR_MD_GETTHREADAFFINITYMASK +#define _MD_EXIT_THREAD _PR_MD_EXIT_THREAD +#define _MD_EXIT _PR_MD_EXIT +#define _MD_SUSPEND_THREAD _PR_MD_SUSPEND_THREAD +#define _MD_RESUME_THREAD _PR_MD_RESUME_THREAD +#define _MD_SUSPEND_CPU _PR_MD_SUSPEND_CPU +#define _MD_RESUME_CPU _PR_MD_RESUME_CPU +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_END_RESUME_ALL() + +/* --- Lock stuff --- */ +#define _PR_LOCK _MD_LOCK +#define _PR_UNLOCK _MD_UNLOCK + +#define _MD_NEW_LOCK(lock) (InitializeCriticalSection(&((lock)->mutex)),(lock)->notified.length=0,(lock)->notified.link=NULL,PR_SUCCESS) +#define _MD_FREE_LOCK(lock) DeleteCriticalSection(&((lock)->mutex)) +#define _MD_LOCK(lock) EnterCriticalSection(&((lock)->mutex)) +#define _MD_TEST_AND_LOCK(lock) (EnterCriticalSection(&((lock)->mutex)),0) +#define _MD_UNLOCK _PR_MD_UNLOCK + +/* --- lock and cv waiting --- */ +#define _MD_WAIT _PR_MD_WAIT +#define _MD_WAKEUP_WAITER _PR_MD_WAKEUP_WAITER + +/* --- CVar ------------------- */ +#define _MD_WAIT_CV _PR_MD_WAIT_CV +#define _MD_NEW_CV _PR_MD_NEW_CV +#define _MD_FREE_CV _PR_MD_FREE_CV +#define _MD_NOTIFY_CV _PR_MD_NOTIFY_CV +#define _MD_NOTIFYALL_CV _PR_MD_NOTIFYALL_CV + + /* XXXMB- the IOQ stuff is certainly not working correctly yet. */ +// extern struct _MDLock _pr_ioq_lock; +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + + +/* --- Initialization stuff --- */ +#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 +#define _MD_FINAL_INIT() +#define _MD_INIT_CPUS() +#define _MD_INIT_RUNNING_CPU(cpu) + +struct PRProcess; +struct PRProcessAttr; + +#define _MD_CREATE_PROCESS _PR_CreateWindowsProcess +extern struct PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _PR_DetachWindowsProcess +extern PRStatus _PR_DetachWindowsProcess(struct PRProcess *process); + +/* --- Wait for a child process to terminate --- */ +#define _MD_WAIT_PROCESS _PR_WaitWindowsProcess +extern PRStatus _PR_WaitWindowsProcess(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _PR_KillWindowsProcess +extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); + +#define _MD_CLEANUP_BEFORE_EXIT _PR_MD_CLEANUP_BEFORE_EXIT +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + PR_END_MACRO +#define _MD_SWITCH_CONTEXT +#define _MD_RESTORE_CONTEXT + +/* --- Intervals --- */ +#define _MD_INTERVAL_INIT _PR_MD_INTERVAL_INIT +#define _MD_GET_INTERVAL _PR_MD_GET_INTERVAL +#define _MD_INTERVAL_PER_SEC _PR_MD_INTERVAL_PER_SEC +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/* --- Time --- */ +extern void _PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm); + +/* --- 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_GET_ATTACHED_THREAD() _pr_currentThread +#define _MD_SET_CURRENT_THREAD(_thread) (_pr_currentThread = (_thread)) + +extern __declspec(thread) struct PRThread *_pr_thread_last_run; +#define _MD_LAST_THREAD() _pr_thread_last_run +#define _MD_SET_LAST_THREAD(_thread) (_pr_thread_last_run = 0) + +extern __declspec(thread) struct _PRCPU *_pr_currentCPU; +#define _MD_CURRENT_CPU() _pr_currentCPU +#define _MD_SET_CURRENT_CPU(_cpu) (_pr_currentCPU = 0) +#else /* _PR_USE_STATIC_TLS */ +extern DWORD _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; +#define _MD_LAST_THREAD() ((PRThread *) TlsGetValue(_pr_lastThreadIndex)) +#define _MD_SET_LAST_THREAD(_thread) TlsSetValue(_pr_lastThreadIndex, 0) + +extern DWORD _pr_currentCPUIndex; +#define _MD_CURRENT_CPU() ((struct _PRCPU *) TlsGetValue(_pr_currentCPUIndex)) +#define _MD_SET_CURRENT_CPU(_cpu) TlsSetValue(_pr_currentCPUIndex, 0) +#endif /* _PR_USE_STATIC_TLS */ + +/* --- Scheduler stuff --- */ +#define LOCK_SCHEDULER() 0 +#define UNLOCK_SCHEDULER() 0 +#define _PR_LockSched() 0 +#define _PR_UnlockSched() 0 + +/* --- Initialization stuff --- */ +#define _MD_INIT_LOCKS() + +/* --- Stack stuff --- */ +#define _MD_INIT_STACK(stack, redzone) +#define _MD_CLEAR_STACK(stack) + +/* --- Memory-mapped files stuff --- */ + +struct _MDFileMap { + HANDLE hFileMap; + DWORD dwAccess; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +/* --- Named semaphores stuff --- */ +#define _PR_HAVE_NAMED_SEMAPHORES +#define _MD_OPEN_SEMAPHORE _PR_MD_OPEN_SEMAPHORE +#define _MD_WAIT_SEMAPHORE _PR_MD_WAIT_SEMAPHORE +#define _MD_POST_SEMAPHORE _PR_MD_POST_SEMAPHORE +#define _MD_CLOSE_SEMAPHORE _PR_MD_CLOSE_SEMAPHORE +#define _MD_DELETE_SEMAPHORE(name) PR_SUCCESS /* no op */ + +#endif /* nspr_win32_defs_h___ */ diff --git a/nsprpub/pr/include/md/_winnt.cfg b/nsprpub/pr/include/md/_winnt.cfg new file mode 100644 index 00000000000..d1d32bb89db --- /dev/null +++ b/nsprpub/pr/include/md/_winnt.cfg @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_PC +#define XP_PC +#endif + +#ifndef WIN32 +#define WIN32 +#endif + +#ifndef WINNT +#define WINNT +#endif + +#define PR_AF_INET6 23 /* same as AF_INET6 */ + +#if defined(_M_IX86) || defined(_X86_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#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_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 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_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 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 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#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 2 + +#elif defined(_ALPHA_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#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_BYTES_PER_WORD_LOG2 2 +#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 + +#elif defined(_AMD64_) + +#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 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 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_WORD 64 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 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 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 +#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(_IA64_) + +#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 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 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_WORD 64 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 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 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_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 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 +#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 + +#else /* defined(_M_IX86) || defined(_X86_) */ + +#error unknown processor architecture + +#endif /* defined(_M_IX86) || defined(_X86_) */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#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/nsprpub/pr/include/md/_winnt.h b/nsprpub/pr/include/md/_winnt.h new file mode 100644 index 00000000000..b5d0143e80f --- /dev/null +++ b/nsprpub/pr/include/md/_winnt.h @@ -0,0 +1,623 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_win32_defs_h___ +#define nspr_win32_defs_h___ + +/* Need to force service-pack 3 extensions to be defined by +** setting _WIN32_WINNT to NT 4.0 for winsock.h, winbase.h, winnt.h. +*/ +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#elif (_WIN32_WINNT < 0x0400) + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#endif /* _WIN32_WINNT */ + +#include +#include +#ifdef __MINGW32__ +#include +#endif +#include + +#include "prio.h" +#include "prclist.h" + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "win32" +#define _PR_SI_SYSNAME "WINNT" +#if defined(_M_IX86) || defined(_X86_) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(_AMD64_) +#define _PR_SI_ARCHITECTURE "x86-64" +#elif defined(_IA64_) +#define _PR_SI_ARCHITECTURE "ia64" +#else +#error unknown processor architecture +#endif + +#define HAVE_DLL +#define HAVE_CUSTOM_USER_THREADS +#define HAVE_THREAD_AFFINITY +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#ifndef _PR_INET6 +#define AF_INET6 23 +/* newer ws2tcpip.h provides these */ +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x2 +#define AI_NUMERICHOST 0x4 +#define NI_NUMERICHOST 0x02 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#define _PR_HAVE_MD_SOCKADDR_IN6 +/* isomorphic to struct in6_addr on Windows */ +struct _md_in6_addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + } _S6_un; +}; +/* isomorphic to struct sockaddr_in6 on Windows */ +struct _md_sockaddr_in6 { + PRInt16 sin6_family; + PRUint16 sin6_port; + PRUint32 sin6_flowinfo; + struct _md_in6_addr sin6_addr; + PRUint32 sin6_scope_id; +}; +#endif +#define _PR_HAVE_THREADSAFE_GETHOST +#define _PR_HAVE_ATOMIC_OPS +#if defined(_M_IX86) || defined(_X86_) +#define _PR_HAVE_ATOMIC_CAS +#endif +#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY +#define _PR_HAVE_PEEK_BUFFER +#define _PR_PEEK_BUFFER_MAX (32 * 1024) +#define _PR_FD_NEED_EMULATE_MSG_PEEK(fd) \ + (!(fd)->secret->nonblocking && (fd)->secret->inheritable != _PR_TRI_TRUE) +#define _PR_NEED_SECRET_AF + +/* --- Common User-Thread/Native-Thread Definitions --------------------- */ + +/* --- Globals --- */ +extern struct PRLock *_pr_schedLock; + +/* --- Typedefs --- */ +typedef void (*FiberFunc)(void *); + +#define PR_NUM_GCREGS 8 +typedef PRInt32 PR_CONTEXT_TYPE[PR_NUM_GCREGS]; +#define GC_VMBASE 0x40000000 +#define GC_VMLIMIT 0x00FFFFFF + +#define _MD_MAGIC_THREAD 0x22222222 +#define _MD_MAGIC_THREADSTACK 0x33333333 +#define _MD_MAGIC_SEGMENT 0x44444444 +#define _MD_MAGIC_DIR 0x55555555 + +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! */ + 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 + * for IO or CondVar. + */ + PRInt32 blocked_io_status; /* Status of the completed IO */ + PRInt32 blocked_io_bytes; /* Bytes transferred for completed IO */ + PRInt32 blocked_io_error; /* Save error if status is FALSE */ + HANDLE handle; + PRUint32 id; + void *sp; /* only valid when suspended */ + PRUint32 magic; /* for debugging */ + PR_CONTEXT_TYPE gcContext; /* Thread context for GC */ + struct _PRCPU *thr_bound_cpu; /* thread bound to cpu */ + PRBool interrupt_disabled;/* thread cannot be interrupted */ + HANDLE thr_event; /* For native-threads-only support, + thread blocks on this event */ + + /* The following are used only if this is a fiber */ + void *fiber_id; /* flag whether or not this is a fiber*/ + FiberFunc fiber_fn; /* main fiber routine */ + void *fiber_arg; /* arg to main fiber routine */ + PRUint32 fiber_stacksize; /* stacksize for fiber */ + PRInt32 fiber_last_error; /* last error for the fiber */ + void (*start)(void *); /* used by _PR_MD_CREATE_THREAD to + * pass its 'start' argument to + * pr_root. */ +}; + +struct _MDThreadStack { + PRUint32 magic; /* for debugging */ +}; + +struct _MDSegment { + PRUint32 magic; /* for debugging */ +}; + +#undef PROFILE_LOCKS + +struct _MDLock { + CRITICAL_SECTION mutex; /* this is recursive on NT */ +#ifdef PROFILE_LOCKS + PRInt32 hitcount; + PRInt32 misscount; +#endif +}; + +struct _MDDir { + HANDLE d_hdl; + WIN32_FIND_DATA d_entry; + PRBool firstEntry; /* Is this the entry returned + * by FindFirstFile()? */ + PRUint32 magic; /* for debugging */ +}; + +struct _MDCVar { + PRUint32 unused; +}; + +struct _MDSemaphore { + HANDLE sem; +}; + +struct _MDFileDesc { + PROsfd osfd; /* The osfd can come from one of three spaces: + * - For stdin, stdout, and stderr, we are using + * the libc file handle (0, 1, 2), which is an int. + * - For files and pipes, we are using Win32 HANDLE, + * which is a void*. + * - For sockets, we are using Winsock SOCKET, which + * is a u_int. + */ + PRBool io_model_committed; /* The io model (blocking or nonblocking) + * for this osfd has been committed and + * cannot be changed. The osfd has been + * either associated with the io + * completion port or made nonblocking. */ + PRBool sync_file_io; /* Use synchronous file I/O on the osfd + * (a file handle) */ + PRBool accepted_socket; /* Is this an accepted socket (on the + * server side)? */ + PRNetAddr peer_addr; /* If this is an accepted socket, cache + * the peer's address returned by + * AcceptEx(). This is to work around + * the bug that getpeername() on an + * socket accepted by AcceptEx() returns + * an all-zero net address. */ +}; + +struct _MDProcess { + HANDLE handle; + DWORD id; +}; + + +/* --- Misc stuff --- */ +#define _MD_GET_SP(thread) (thread)->md.gcContext[6] + +/* --- NT security stuff --- */ + +extern void _PR_NT_InitSids(void); +extern void _PR_NT_FreeSids(void); +extern PRStatus _PR_NT_MakeSecurityDescriptorACL( + PRIntn mode, + DWORD accessTable[], + PSECURITY_DESCRIPTOR *resultSD, + PACL *resultACL +); +extern void _PR_NT_FreeSecurityDescriptorACL( + PSECURITY_DESCRIPTOR pSD, PACL pACL); + +/* --- IO stuff --- */ + +extern PRInt32 _md_Associate(HANDLE); +extern PRInt32 _PR_MD_CLOSE(PROsfd osfd, PRBool socket); + +#define _MD_OPEN _PR_MD_OPEN +#define _MD_OPEN_FILE _PR_MD_OPEN_FILE +#define _MD_READ _PR_MD_READ +#define _MD_WRITE _PR_MD_WRITE +#define _MD_WRITEV _PR_MD_WRITEV +#define _MD_LSEEK _PR_MD_LSEEK +#define _MD_LSEEK64 _PR_MD_LSEEK64 +#define _MD_CLOSE_FILE(f) _PR_MD_CLOSE(f, PR_FALSE) +#define _MD_GETFILEINFO _PR_MD_GETFILEINFO +#define _MD_GETFILEINFO64 _PR_MD_GETFILEINFO64 +#define _MD_GETOPENFILEINFO _PR_MD_GETOPENFILEINFO +#define _MD_GETOPENFILEINFO64 _PR_MD_GETOPENFILEINFO64 +#define _MD_STAT _PR_MD_STAT +#define _MD_RENAME _PR_MD_RENAME +#define _MD_ACCESS _PR_MD_ACCESS +#define _MD_DELETE _PR_MD_DELETE +#define _MD_MKDIR _PR_MD_MKDIR +#define _MD_MAKE_DIR _PR_MD_MAKE_DIR +#define _MD_RMDIR _PR_MD_RMDIR +#define _MD_LOCKFILE _PR_MD_LOCKFILE +#define _MD_TLOCKFILE _PR_MD_TLOCKFILE +#define _MD_UNLOCKFILE _PR_MD_UNLOCKFILE + +/* --- Socket IO stuff --- */ +#define _MD_GET_SOCKET_ERROR() WSAGetLastError() +#define _MD_SET_SOCKET_ERROR(_err) WSASetLastError(_err) + +#define _MD_INIT_FILEDESC(fd) +#define _MD_MAKE_NONBLOCK _PR_MD_MAKE_NONBLOCK +#define _MD_INIT_FD_INHERITABLE _PR_MD_INIT_FD_INHERITABLE +#define _MD_QUERY_FD_INHERITABLE _PR_MD_QUERY_FD_INHERITABLE +#define _MD_SHUTDOWN _PR_MD_SHUTDOWN +#define _MD_LISTEN _PR_MD_LISTEN +#define _MD_CLOSE_SOCKET(s) _PR_MD_CLOSE(s, PR_TRUE) +#define _MD_SENDTO _PR_MD_SENDTO +#define _MD_RECVFROM _PR_MD_RECVFROM +#define _MD_SOCKETPAIR(s, type, proto, sv) -1 +#define _MD_GETSOCKNAME _PR_MD_GETSOCKNAME +#define _MD_GETPEERNAME _PR_MD_GETPEERNAME +#define _MD_GETSOCKOPT _PR_MD_GETSOCKOPT +#define _MD_SETSOCKOPT _PR_MD_SETSOCKOPT +#define _MD_SELECT select +extern int _PR_NTFiberSafeSelect(int, fd_set *, fd_set *, fd_set *, + const struct timeval *); +#define _MD_FSYNC _PR_MD_FSYNC +#define _MD_SOCKETAVAILABLE _PR_MD_SOCKETAVAILABLE +#define _MD_PIPEAVAILABLE _PR_MD_PIPEAVAILABLE +#define _MD_SET_FD_INHERITABLE _PR_MD_SET_FD_INHERITABLE + +#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) + +#define _MD_INIT_IO _PR_MD_INIT_IO +#define _MD_SOCKET _PR_MD_SOCKET +#define _MD_CONNECT _PR_MD_CONNECT + +#define _MD_ACCEPT(s, a, l, to) \ + _MD_FAST_ACCEPT(s, a, l, to, PR_FALSE, NULL, NULL) +#define _MD_FAST_ACCEPT(s, a, l, to, fast, cb, cba) \ + _PR_MD_FAST_ACCEPT(s, a, l, to, fast, cb, cba) +#define _MD_ACCEPT_READ(s, ns, ra, buf, l, t) \ + _MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, PR_FALSE, NULL, NULL) +#define _MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, fast, cb, cba) \ + _PR_MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, fast, cb, cba) +#define _MD_UPDATE_ACCEPT_CONTEXT _PR_MD_UPDATE_ACCEPT_CONTEXT + +#define _MD_BIND _PR_MD_BIND +#define _MD_RECV _PR_MD_RECV +#define _MD_SEND _PR_MD_SEND +#define _MD_SENDFILE _PR_MD_SENDFILE +#define _MD_PR_POLL _PR_MD_PR_POLL + +/* --- Scheduler stuff --- */ +#define _MD_PAUSE_CPU _PR_MD_PAUSE_CPU + +/* --- DIR stuff --- */ +#define PR_DIRECTORY_SEPARATOR '\\' +#define PR_DIRECTORY_SEPARATOR_STR "\\" +#define PR_PATH_SEPARATOR ';' +#define PR_PATH_SEPARATOR_STR ";" +#define _MD_ERRNO() GetLastError() +#define _MD_OPEN_DIR _PR_MD_OPEN_DIR +#define _MD_CLOSE_DIR _PR_MD_CLOSE_DIR +#define _MD_READ_DIR _PR_MD_READ_DIR + +/* --- Segment stuff --- */ +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT(seg, size, vaddr) 0 +#define _MD_FREE_SEGMENT(seg) + +/* --- Environment Stuff --- */ +#define _MD_GET_ENV _PR_MD_GET_ENV +#define _MD_PUT_ENV _PR_MD_PUT_ENV + +/* --- Threading Stuff --- */ +#define _MD_DEFAULT_STACK_SIZE 0 +#define _MD_INIT_THREAD _PR_MD_INIT_THREAD +#define _MD_INIT_ATTACHED_THREAD _PR_MD_INIT_THREAD +#define _MD_CREATE_THREAD _PR_MD_CREATE_THREAD +#define _MD_JOIN_THREAD _PR_MD_JOIN_THREAD +#define _MD_END_THREAD _PR_MD_END_THREAD +#define _MD_YIELD _PR_MD_YIELD +#define _MD_SET_PRIORITY _PR_MD_SET_PRIORITY +#define _MD_CLEAN_THREAD _PR_MD_CLEAN_THREAD +#define _MD_SETTHREADAFFINITYMASK _PR_MD_SETTHREADAFFINITYMASK +#define _MD_GETTHREADAFFINITYMASK _PR_MD_GETTHREADAFFINITYMASK +#define _MD_EXIT_THREAD _PR_MD_EXIT_THREAD +#define _MD_SUSPEND_THREAD _PR_MD_SUSPEND_THREAD +#define _MD_RESUME_THREAD _PR_MD_RESUME_THREAD +#define _MD_SUSPEND_CPU _PR_MD_SUSPEND_CPU +#define _MD_RESUME_CPU _PR_MD_RESUME_CPU +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_END_RESUME_ALL() + +extern void _PR_Unblock_IO_Wait(PRThread *thr); + +/* --- Lock stuff --- */ +#define _MD_NEW_LOCK(lock) (InitializeCriticalSection(&((lock)->mutex)),PR_SUCCESS) +#define _MD_FREE_LOCK(lock) DeleteCriticalSection(&((lock)->mutex)) +#ifndef PROFILE_LOCKS +#define _MD_LOCK(lock) EnterCriticalSection(&((lock)->mutex)) +#define _MD_TEST_AND_LOCK(lock) (TryEnterCriticalSection(&((lock)->mutex))== FALSE) +#define _MD_UNLOCK(lock) LeaveCriticalSection(&((lock)->mutex)) +#else +#define _MD_LOCK(lock) \ + PR_BEGIN_MACRO \ + BOOL rv = TryEnterCriticalSection(&((lock)->mutex)); \ + if (rv == TRUE) { \ + InterlockedIncrement(&((lock)->hitcount)); \ + } else { \ + InterlockedIncrement(&((lock)->misscount)); \ + EnterCriticalSection(&((lock)->mutex)); \ + } \ + PR_END_MACRO +#define _MD_TEST_AND_LOCK(lock) 0 /* XXXMB */ +#define _MD_UNLOCK(lock) LeaveCriticalSection(&((lock)->mutex)) +#endif +#define _PR_LOCK _MD_LOCK +#define _PR_UNLOCK _MD_UNLOCK + +/* --- lock and cv waiting --- */ +#define _MD_WAIT _PR_MD_WAIT +#define _MD_WAKEUP_WAITER _PR_MD_WAKEUP_WAITER + + /* XXXMB- the IOQ stuff is certainly not working correctly yet. */ +extern struct _MDLock _pr_ioq_lock; +#define _MD_IOQ_LOCK() _MD_LOCK(&_pr_ioq_lock) +#define _MD_IOQ_UNLOCK() _MD_UNLOCK(&_pr_ioq_lock) + + +/* --- Initialization stuff --- */ +#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 +#define _MD_FINAL_INIT() +#define _MD_INIT_CPUS() +#define _MD_INIT_RUNNING_CPU(cpu) + +struct PRProcess; +struct PRProcessAttr; + +/* --- Create a new process --- */ +#define _MD_CREATE_PROCESS _PR_CreateWindowsProcess +extern struct PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _PR_DetachWindowsProcess +extern PRStatus _PR_DetachWindowsProcess(struct PRProcess *process); + +/* --- Wait for a child process to terminate --- */ +#define _MD_WAIT_PROCESS _PR_WaitWindowsProcess +extern PRStatus _PR_WaitWindowsProcess(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _PR_KillWindowsProcess +extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); + +/* --- User Threading stuff --- */ +#define HAVE_FIBERS +#define _MD_CREATE_USER_THREAD _PR_MD_CREATE_USER_THREAD +#define _MD_CREATE_PRIMORDIAL_USER_THREAD _PR_MD_CREATE_PRIMORDIAL_USER_THREAD +#define _MD_CLEANUP_BEFORE_EXIT _PR_MD_CLEANUP_BEFORE_EXIT +#define _MD_EXIT _PR_MD_EXIT +#define _MD_INIT_CONTEXT _PR_MD_INIT_CONTEXT +#define _MD_SWITCH_CONTEXT _PR_MD_SWITCH_CONTEXT +#define _MD_RESTORE_CONTEXT _PR_MD_RESTORE_CONTEXT + +/* --- Intervals --- */ +#define _MD_INTERVAL_INIT _PR_MD_INTERVAL_INIT +#define _MD_GET_INTERVAL _PR_MD_GET_INTERVAL +#define _MD_INTERVAL_PER_SEC _PR_MD_INTERVAL_PER_SEC +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/* --- Time --- */ +extern void _PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm); + +/* --- Native-Thread Specific Definitions ------------------------------- */ + +extern BOOL _pr_use_static_tls; + +extern __declspec(thread) struct PRThread *_pr_current_fiber; +extern DWORD _pr_currentFiberIndex; + +#define _MD_GET_ATTACHED_THREAD() \ + (_pr_use_static_tls ? _pr_current_fiber \ + : (PRThread *) TlsGetValue(_pr_currentFiberIndex)) + +extern struct PRThread * _MD_CURRENT_THREAD(void); + +#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 + +extern __declspec(thread) struct PRThread *_pr_fiber_last_run; +extern DWORD _pr_lastFiberIndex; + +#define _MD_LAST_THREAD() \ + (_pr_use_static_tls ? _pr_fiber_last_run \ + : (PRThread *) TlsGetValue(_pr_lastFiberIndex)) + +#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() \ + (_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_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() + +/* --- Stack stuff --- */ +#define _MD_INIT_STACK(stack, redzone) +#define _MD_CLEAR_STACK(stack) + +/* --- Memory-mapped files stuff --- */ + +struct _MDFileMap { + HANDLE hFileMap; + DWORD dwAccess; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +/* --- Named semaphores stuff --- */ +#define _PR_HAVE_NAMED_SEMAPHORES +#define _MD_OPEN_SEMAPHORE _PR_MD_OPEN_SEMAPHORE +#define _MD_WAIT_SEMAPHORE _PR_MD_WAIT_SEMAPHORE +#define _MD_POST_SEMAPHORE _PR_MD_POST_SEMAPHORE +#define _MD_CLOSE_SEMAPHORE _PR_MD_CLOSE_SEMAPHORE +#define _MD_DELETE_SEMAPHORE(name) PR_SUCCESS /* no op */ + +#endif /* nspr_win32_defs_h___ */ diff --git a/nsprpub/pr/include/md/prosdep.h b/nsprpub/pr/include/md/prosdep.h new file mode 100644 index 00000000000..0de89a98f45 --- /dev/null +++ b/nsprpub/pr/include/md/prosdep.h @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prosdep_h___ +#define prosdep_h___ + +/* +** Get OS specific header information +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +#ifdef XP_PC + +#include "md/_pcos.h" +#ifdef WINNT +#include "md/_winnt.h" +#include "md/_win32_errors.h" +#elif defined(WIN95) +#include "md/_win95.h" +#include "md/_win32_errors.h" +#elif defined(WIN16) +#include "md/_win16.h" +#elif defined(OS2) +#include "md/_os2.h" +#include "md/_os2_errors.h" +#else +#error unknown Windows platform +#endif + +#elif defined XP_MAC + +#include "_macos.h" + +#elif defined(XP_UNIX) + +#if defined(AIX) +#include "md/_aix.h" + +#elif defined(FREEBSD) +#include "md/_freebsd.h" + +#elif defined(NETBSD) +#include "md/_netbsd.h" + +#elif defined(OPENBSD) +#include "md/_openbsd.h" + +#elif defined(BSDI) +#include "md/_bsdi.h" + +#elif defined(HPUX) +#include "md/_hpux.h" + +#elif defined(IRIX) +#include "md/_irix.h" + +#elif defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) +#include "md/_linux.h" + +#elif defined(OSF1) +#include "md/_osf1.h" + +#elif defined(DARWIN) +#include "md/_darwin.h" + +#elif defined(NEXTSTEP) +#include "md/_nextstep.h" + +#elif defined(SOLARIS) +#include "md/_solaris.h" + +#elif defined(SUNOS4) +#include "md/_sunos4.h" + +#elif defined(SNI) +#include "md/_reliantunix.h" + +#elif defined(SONY) +#include "md/_sony.h" + +#elif defined(NEC) +#include "md/_nec.h" + +#elif defined(SCO) +#include "md/_scoos.h" + +#elif defined(UNIXWARE) +#include "md/_unixware.h" + +#elif defined(NCR) +#include "md/_ncr.h" + +#elif defined(DGUX) +#include "md/_dgux.h" + +#elif defined(QNX) +#include "md/_qnx.h" + +#elif defined(VMS) +#include "md/_openvms.h" + +#elif defined(NTO) +#include "md/_nto.h" + +#elif defined(RISCOS) +#include "md/_riscos.h" + +#else +#error unknown Unix flavor + +#endif + +#include "md/_unixos.h" +#include "md/_unix_errors.h" + +#elif defined(XP_BEOS) + +#include "md/_beos.h" +#include "md/_unix_errors.h" + +#else + +#error "The platform is not BeOS, Unix, Windows, or Mac" + +#endif + +#ifdef _PR_PTHREADS +#include "md/_pth.h" +#endif + +PR_END_EXTERN_C + +#endif /* prosdep_h___ */ diff --git a/nsprpub/pr/include/md/sunos4.h b/nsprpub/pr/include/md/sunos4.h new file mode 100644 index 00000000000..0a8f36d45c6 --- /dev/null +++ b/nsprpub/pr/include/md/sunos4.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef pr_sunos4_h___ +#define pr_sunos4_h___ + +#ifndef SVR4 + +/* +** Hodge podge of random missing prototypes for the Sunos4 system +*/ +#include +#include +#include +#include +#include + +#define PATH_MAX _POSIX_PATH_MAX + +struct timeval; +struct timezone; +struct itimerval; +struct sockaddr; +struct stat; +struct tm; + +/* ctype.h */ +extern int tolower(int); +extern int toupper(int); + +/* errno.h */ +extern char *sys_errlist[]; +extern int sys_nerr; + +#define strerror(e) sys_errlist[((unsigned)(e) < sys_nerr) ? e : 0] + +extern void perror(const char *); + +/* getopt */ +extern char *optarg; +extern int optind; +extern int getopt(int argc, char **argv, char *spec); + +/* math.h */ +extern int srandom(long val); +extern long random(void); + +/* memory.h */ +#define memmove(to,from,len) bcopy((char*)(from),(char*)(to),len) + +extern void bcopy(const char *, char *, int); + +/* signal.h */ +/* +** SunOS4 sigaction hides interrupts by default, so we can safely define +** SA_RESTART to 0. +*/ +#define SA_RESTART 0 + +/* stdio.h */ +extern int printf(const char *, ...); +extern int fprintf(FILE *, const char *, ...); +extern int vprintf(const char *, va_list); +extern int vfprintf(FILE *, const char *, va_list); +extern char *vsprintf(char *, const char *, va_list); +extern int scanf(const char *, ...); +extern int sscanf(const char *, const char *, ...); +extern int fscanf(FILE *, const char *, ...); +extern int fgetc(FILE *); +extern int fputc(int, FILE *); +extern int fputs(const char *, FILE *); +extern int puts(const char *); +extern int fread(void *, size_t, size_t, FILE *); +extern int fwrite(const char *, int, int, FILE *); +extern int fseek(FILE *, long, int); +extern long ftell(FILE *); +extern int rewind(FILE *); +extern int fflush(FILE *); +extern int _flsbuf(unsigned char, FILE *); +extern int fclose(FILE *); +extern int remove(const char *); +extern int setvbuf(FILE *, char *, int, size_t); +extern int system(const char *); +extern FILE *popen(const char *, const char *); +extern int pclose(FILE *); + +/* stdlib.h */ +#define strtoul strtol + +extern int isatty(int fildes); +extern long strtol(const char *, char **, int); +extern int putenv(const char *); +extern void srand48(long); +extern long lrand48(void); +extern double drand48(void); + +/* string.h */ +extern int strcasecmp(const char *, const char *); +extern int strncasecmp(const char *, const char *, size_t); +extern int strcoll(const char *, const char *); + +/* time.h */ +extern time_t mktime(struct tm *); +extern size_t strftime(char *, size_t, const char *, const struct tm *); +extern int gettimeofday(struct timeval *, struct timezone *); +extern int setitimer(int, struct itimerval *, struct itimerval *); +extern time_t time(time_t *); +extern time_t timegm(struct tm *); +extern struct tm *localtime(const time_t *); +extern struct tm *gmtime(const time_t *); + +/* unistd.h */ +extern int rename(const char *, const char *); +extern int ioctl(int, int, int *arg); +extern int connect(int, struct sockaddr *, int); +extern int readlink(const char *, char *, int); +extern int symlink(const char *, const char *); +extern int ftruncate(int, off_t); +extern int fchmod(int, mode_t); +extern int fchown(int, uid_t, gid_t); +extern int lstat(const char *, struct stat *); +extern int fstat(int, struct stat *); +extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +extern int gethostname(char *, int); +extern char *getwd(char *); +extern int getpagesize(void); + +#endif /* SVR4 */ + +#endif /* pr_sunos4_h___ */ diff --git a/nsprpub/pr/include/nspr.h b/nsprpub/pr/include/nspr.h new file mode 100644 index 00000000000..cf3bfad7a14 --- /dev/null +++ b/nsprpub/pr/include/nspr.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_h___ +#define nspr_h___ + +#include "pratom.h" +#include "prbit.h" +#include "prclist.h" +#include "prcmon.h" +#include "prcvar.h" +#include "prdtoa.h" +#include "prenv.h" +#include "prerror.h" +#include "prinet.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "pripcsem.h" +#include "prlink.h" +#include "prlock.h" +#include "prlog.h" +#include "prlong.h" +#include "prmem.h" +#include "prmon.h" +#include "prmwait.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prproces.h" +#include "prrng.h" +#include "prrwlock.h" +#include "prshm.h" +#include "prshma.h" +#include "prsystem.h" +#include "prthread.h" +#include "prtime.h" +#include "prtpool.h" +#include "prtrace.h" +#include "prtypes.h" + +#endif /* nspr_h___ */ diff --git a/nsprpub/pr/include/obsolete/.cvsignore b/nsprpub/pr/include/obsolete/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/include/obsolete/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/include/obsolete/Makefile.in b/nsprpub/pr/include/obsolete/Makefile.in new file mode 100644 index 00000000000..1add484493a --- /dev/null +++ b/nsprpub/pr/include/obsolete/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +HEADERS = $(wildcard $(srcdir)/*.h) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR)/obsolete + +include_subdir = obsolete + +include $(topsrcdir)/config/rules.mk + +export:: $(RELEASE_HEADERS) + $(INSTALL) -m 444 $(RELEASE_HEADERS) $(dist_includedir)/obsolete diff --git a/nsprpub/pr/include/obsolete/pralarm.h b/nsprpub/pr/include/obsolete/pralarm.h new file mode 100644 index 00000000000..20476e444f2 --- /dev/null +++ b/nsprpub/pr/include/obsolete/pralarm.h @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: pralarm.h +** Description: API to periodic alarms. +** +** +** Alarms are defined to invoke some client specified function at +** a time in the future. The notification may be a one time event +** or repeated at a fixed interval. The interval at which the next +** notification takes place may be modified by the client code only +** during the respective notification. +** +** The notification is delivered on a thread that is part of the +** alarm context (PRAlarm). The thread will inherit the priority +** of the Alarm creator. +** +** Any number of periodic alarms (PRAlarmID) may be created within +** the context of a single alarm (PRAlarm). The notifications will be +** scheduled as close to the desired time as possible. +** +** Repeating periodic notifies are expected to run at a fixed rate. +** That rate is expressed as some number of notifies per period where +** the period is much larger than a PRIntervalTime (see prinrval.h). +*/ + +#if !defined(pralarm_h) +#define pralarm_h + +#include "prtypes.h" +#include "prinrval.h" + + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +typedef struct PRAlarm PRAlarm; +typedef struct PRAlarmID PRAlarmID; + +typedef PRBool (PR_CALLBACK *PRPeriodicAlarmFn)( + PRAlarmID *id, void *clientData, PRUint32 late); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_CreateAlarm +** DESCRIPTION: +** Create an alarm context. +** INPUTS: void +** OUTPUTS: None +** RETURN: PRAlarm* +** +** SIDE EFFECTS: +** This creates an alarm context, which is an object used for subsequent +** notification creations. It also creates a thread that will be used to +** deliver the notifications that are expected to be defined. The client +** is resposible for destroying the context when appropriate. +** RESTRICTIONS: +** None. +** MEMORY: The object (PRAlarm) and a thread to support notifications. +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRAlarm*) PR_CreateAlarm(void); + +/*********************************************************************** +** FUNCTION: PR_DestroyAlarm +** DESCRIPTION: +** Destroys the context created by PR_CreateAlarm(). +** INPUTS: PRAlarm* +** OUTPUTS: None +** RETURN: PRStatus +** +** SIDE EFFECTS: +** This destroys the context that was created by PR_CreateAlarm(). +** If there are any active alarms (PRAlarmID), they will be cancelled. +** Once that is done, the thread that was used to deliver the alarms +** will be joined. +** RESTRICTIONS: +** None. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRStatus) PR_DestroyAlarm(PRAlarm *alarm); + +/*********************************************************************** +** FUNCTION: PR_SetAlarm +** DESCRIPTION: +** Creates a periodic notifier that is to be delivered to a specified +** function at some fixed interval. +** INPUTS: PRAlarm *alarm Parent alarm context +** PRIntervalTime period Interval over which the notifies +** are delivered. +** PRUint32 rate The rate within the interval that +** the notifies will be delivered. +** PRPeriodicAlarmFn function Entry point where the notifies +** will be delivered. +** OUTPUTS: None +** RETURN: PRAlarmID* Handle to the notifier just created +** or NULL if the request failed. +** +** SIDE EFFECTS: +** A periodic notifier is created. The notifications will be delivered +** by the alarm's internal thread at a fixed interval whose rate is the +** number of interrupts per interval specified. The first notification +** will be delivered as soon as possible, and they will continue until +** the notifier routine indicates that they should cease of the alarm +** context is destroyed (PR_DestroyAlarm). +** RESTRICTIONS: +** None. +** MEMORY: Memory for the notifier object. +** ALGORITHM: The rate at which notifications are delivered are stated +** to be "'rate' notifies per 'interval'". The exact time of +** the notification is computed based on a epoch established +** when the notifier was set. Each notification is delivered +** not ealier than the epoch plus the fixed rate times the +** notification sequence number. Such notifications have the +** potential to be late by not more than 'interval'/'rate'. +** The amount of lateness of one notification is taken into +** account on the next in an attempt to avoid long term slew. +***********************************************************************/ +NSPR_API(PRAlarmID*) PR_SetAlarm( + PRAlarm *alarm, PRIntervalTime period, PRUint32 rate, + PRPeriodicAlarmFn function, void *clientData); + +/*********************************************************************** +** FUNCTION: PR_ResetAlarm +** DESCRIPTION: +** Resets an existing alarm. +** INPUTS: PRAlarmID *id Identify of the notifier. +** PRIntervalTime period Interval over which the notifies +** are delivered. +** PRUint32 rate The rate within the interval that +** the notifies will be delivered. +** OUTPUTS: None +** RETURN: PRStatus Indication of completion. +** +** SIDE EFFECTS: +** An existing alarm may have its period and rate redefined. The +** additional side effect is that the notifier's epoch is recomputed. +** The first notification delivered by the newly refreshed alarm is +** defined to be 'interval'/'rate' from the time of the reset. +** RESTRICTIONS: +** This function may only be called in the notifier for that alarm. +** MEMORY: N/A. +** ALGORITHM: See PR_SetAlarm(). +***********************************************************************/ +NSPR_API(PRStatus) PR_ResetAlarm( + PRAlarmID *id, PRIntervalTime period, PRUint32 rate); + +PR_END_EXTERN_C + +#endif /* !defined(pralarm_h) */ + +/* prinrval.h */ diff --git a/nsprpub/pr/include/obsolete/probslet.h b/nsprpub/pr/include/obsolete/probslet.h new file mode 100644 index 00000000000..98bed4d59e2 --- /dev/null +++ b/nsprpub/pr/include/obsolete/probslet.h @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** A collection of things thought to be obsolete +*/ + +#if defined(PROBSLET_H) +#else +#define PROBSLET_H + +#include "prio.h" +#include "private/pprio.h" /* for PROsfd */ + +PR_BEGIN_EXTERN_C + +/* +** Yield the current thread. The proper function to use in place of +** PR_Yield() is PR_Sleep() with an argument of PR_INTERVAL_NO_WAIT. +*/ +NSPR_API(PRStatus) PR_Yield(void); + +/************************************************************************/ +/************* The following definitions are for select *****************/ +/************************************************************************/ + +/* +** The following is obsolete and will be deleted in the next release! +** These are provided for compatibility, but are GUARANTEED to be slow. +** +** Override PR_MAX_SELECT_DESC if you need more space in the select set. +*/ +#ifndef PR_MAX_SELECT_DESC +#define PR_MAX_SELECT_DESC 1024 +#endif +typedef struct PR_fd_set { + PRUint32 hsize; + PRFileDesc *harray[PR_MAX_SELECT_DESC]; + PRUint32 nsize; + PROsfd narray[PR_MAX_SELECT_DESC]; +} PR_fd_set; + +/* +************************************************************************* +** FUNCTION: PR_Select +** DESCRIPTION: +** +** The call returns as soon as I/O is ready on one or more of the underlying +** file/socket descriptors or an exceptional condition is pending. A count of the +** number of ready descriptors is returned unless a timeout occurs in which case +** zero is returned. On return, PR_Select replaces the given descriptor sets with +** subsets consisting of those descriptors that are ready for the requested condition. +** The total number of ready descriptors in all the sets is the return value. +** +** INPUTS: +** PRInt32 num +** This argument is unused but is provided for select(unix) interface +** compatability. All input PR_fd_set arguments are self-describing +** with its own maximum number of elements in the set. +** +** PR_fd_set *readfds +** A set describing the io descriptors for which ready for reading +** condition is of interest. +** +** PR_fd_set *writefds +** A set describing the io descriptors for which ready for writing +** condition is of interest. +** +** PR_fd_set *exceptfds +** A set describing the io descriptors for which exception pending +** condition is of interest. +** +** Any of the above readfds, writefds or exceptfds may be given as NULL +** pointers if no descriptors are of interest for that particular condition. +** +** PRIntervalTime timeout +** Amount of time the call will block waiting for I/O to become ready. +** If this time expires without any I/O becoming ready, the result will +** be zero. +** +** OUTPUTS: +** PR_fd_set *readfds +** A set describing the io descriptors which are ready for reading. +** +** PR_fd_set *writefds +** A set describing the io descriptors which are ready for writing. +** +** PR_fd_set *exceptfds +** A set describing the io descriptors which have pending exception. +** +** RETURN:PRInt32 +** Number of io descriptors with asked for conditions or zero if the function +** timed out or -1 on failure. The reason for the failure is obtained by +** calling PR_GetError(). +** XXX can we implement this on windoze and mac? +************************************************************************** +*/ +NSPR_API(PRInt32) PR_Select( + PRInt32 num, PR_fd_set *readfds, PR_fd_set *writefds, + PR_fd_set *exceptfds, PRIntervalTime timeout); + +/* +** The following are not thread safe for two threads operating on them at the +** same time. +** +** The following routines are provided for manipulating io descriptor sets. +** PR_FD_ZERO(&fdset) initializes a descriptor set fdset to the null set. +** PR_FD_SET(fd, &fdset) includes a particular file descriptor fd in fdset. +** PR_FD_CLR(fd, &fdset) removes a file descriptor fd from fdset. +** PR_FD_ISSET(fd, &fdset) is nonzero if file descriptor fd is a member of +** fdset, zero otherwise. +** +** PR_FD_NSET(osfd, &fdset) includes a particular native file descriptor osfd +** in fdset. +** PR_FD_NCLR(osfd, &fdset) removes a native file descriptor osfd from fdset. +** PR_FD_NISSET(osfd, &fdset) is nonzero if native file descriptor osfd is a member of +** fdset, zero otherwise. +*/ + +NSPR_API(void) PR_FD_ZERO(PR_fd_set *set); +NSPR_API(void) PR_FD_SET(PRFileDesc *fd, PR_fd_set *set); +NSPR_API(void) PR_FD_CLR(PRFileDesc *fd, PR_fd_set *set); +NSPR_API(PRInt32) PR_FD_ISSET(PRFileDesc *fd, PR_fd_set *set); +NSPR_API(void) PR_FD_NSET(PROsfd osfd, PR_fd_set *set); +NSPR_API(void) PR_FD_NCLR(PROsfd osfd, PR_fd_set *set); +NSPR_API(PRInt32) PR_FD_NISSET(PROsfd osfd, PR_fd_set *set); + +/* +** The next two entry points should not be in the API, but they are +** declared here for historical reasons. +*/ + +NSPR_API(PRInt32) PR_GetSysfdTableMax(void); + +NSPR_API(PRInt32) PR_SetSysfdTableSize(PRIntn table_size); + +#ifndef NO_NSPR_10_SUPPORT +#ifdef XP_MAC +#include +#else +#include +#endif + +NSPR_API(PRInt32) PR_Stat(const char *path, struct stat *buf); +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* defined(PROBSLET_H) */ + +/* probslet.h */ diff --git a/nsprpub/pr/include/obsolete/protypes.h b/nsprpub/pr/include/obsolete/protypes.h new file mode 100644 index 00000000000..4405bfce2f0 --- /dev/null +++ b/nsprpub/pr/include/obsolete/protypes.h @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This header typedefs the old 'native' types to the new PRs. + * These definitions are scheduled to be eliminated at the earliest + * possible time. The NSPR API is implemented and documented using + * the new definitions. + */ + +#if !defined(PROTYPES_H) +#define PROTYPES_H + +typedef PRUintn uintn; +#ifndef _XP_Core_ +typedef PRIntn intn; +#endif + +/* + * It is trickier to define uint, int8, uint8, int16, uint16, + * int32, uint32, int64, and uint64 because some of these int + * types are defined by standard header files on some platforms. + * Our strategy here is to include all such standard headers + * first, and then define these int types only if they are not + * defined by those standard headers. + */ + +/* + * BeOS defines all the int types below in its standard header + * file SupportDefs.h. + */ +#ifdef XP_BEOS +#include +#endif + +/* + * OpenVMS defines all the int types below in its standard + * header files ints.h and types.h. + */ +#ifdef VMS +#include +#include +#endif + +/* + * SVR4 typedef of uint is commonly found on UNIX machines. + * + * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h) + * defines the types int8, int16, int32, and int64. + */ +#ifdef XP_UNIX +#include +#endif + +/* model.h on HP-UX defines int8, int16, and int32. */ +#ifdef HPUX +#include +#endif + +/* + * uint + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(XP_UNIX) || defined(NTO) +typedef PRUintn uint; +#endif + +/* + * uint64 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +typedef PRUint64 uint64; +#endif + +/* + * uint32 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO) +typedef PRUint32 uint32; +#else +typedef unsigned long uint32; +#endif +#endif + +/* + * uint16 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +typedef PRUint16 uint16; +#endif + +/* + * uint8 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +typedef PRUint8 uint8; +#endif + +/* + * int64 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) +typedef PRInt64 int64; +#endif + +/* + * int32 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO) +typedef PRInt32 int32; +#else +typedef long int32; +#endif +#endif + +/* + * int16 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +typedef PRInt16 int16; +#endif + +/* + * int8 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +typedef PRInt8 int8; +#endif + +typedef PRFloat64 float64; +typedef PRUptrdiff uptrdiff_t; +typedef PRUword uprword_t; +typedef PRWord prword_t; + + +/* Re: prbit.h */ +#define TEST_BIT PR_TEST_BIT +#define SET_BIT PR_SET_BIT +#define CLEAR_BIT PR_CLEAR_BIT + +/* Re: prarena.h->plarena.h */ +#define PRArena PLArena +#define PRArenaPool PLArenaPool +#define PRArenaStats PLArenaStats +#define PR_ARENA_ALIGN PL_ARENA_ALIGN +#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL +#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE +#define PR_ARENA_GROW PL_ARENA_GROW +#define PR_ARENA_MARK PL_ARENA_MARK +#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED +#define PR_CLEAR_ARENA PL_CLEAR_ARENA +#define PR_ARENA_RELEASE PL_ARENA_RELEASE +#define PR_COUNT_ARENA PL_COUNT_ARENA +#define PR_ARENA_DESTROY PL_ARENA_DESTROY +#define PR_InitArenaPool PL_InitArenaPool +#define PR_FreeArenaPool PL_FreeArenaPool +#define PR_FinishArenaPool PL_FinishArenaPool +#define PR_CompactArenaPool PL_CompactArenaPool +#define PR_ArenaFinish PL_ArenaFinish +#define PR_ArenaAllocate PL_ArenaAllocate +#define PR_ArenaGrow PL_ArenaGrow +#define PR_ArenaRelease PL_ArenaRelease +#define PR_ArenaCountAllocation PL_ArenaCountAllocation +#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth +#define PR_ArenaCountGrowth PL_ArenaCountGrowth +#define PR_ArenaCountRelease PL_ArenaCountRelease +#define PR_ArenaCountRetract PL_ArenaCountRetract + +/* Re: prhash.h->plhash.h */ +#define PRHashEntry PLHashEntry +#define PRHashTable PLHashTable +#define PRHashNumber PLHashNumber +#define PRHashFunction PLHashFunction +#define PRHashComparator PLHashComparator +#define PRHashEnumerator PLHashEnumerator +#define PRHashAllocOps PLHashAllocOps +#define PR_NewHashTable PL_NewHashTable +#define PR_HashTableDestroy PL_HashTableDestroy +#define PR_HashTableRawLookup PL_HashTableRawLookup +#define PR_HashTableRawAdd PL_HashTableRawAdd +#define PR_HashTableRawRemove PL_HashTableRawRemove +#define PR_HashTableAdd PL_HashTableAdd +#define PR_HashTableRemove PL_HashTableRemove +#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries +#define PR_HashTableLookup PL_HashTableLookup +#define PR_HashTableDump PL_HashTableDump +#define PR_HashString PL_HashString +#define PR_CompareStrings PL_CompareStrings +#define PR_CompareValues PL_CompareValues + +#if defined(XP_MAC) +#ifndef TRUE /* Mac standard is lower case true */ + #define TRUE 1 +#endif +#ifndef FALSE /* Mac standard is lower case false */ + #define FALSE 0 +#endif +#endif + +#endif /* !defined(PROTYPES_H) */ diff --git a/nsprpub/pr/include/obsolete/prsem.h b/nsprpub/pr/include/obsolete/prsem.h new file mode 100644 index 00000000000..fd0863aba65 --- /dev/null +++ b/nsprpub/pr/include/obsolete/prsem.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prsem_h___ +#define prsem_h___ + +/* +** API for counting semaphores. Semaphores are counting synchronizing +** variables based on a lock and a condition variable. They are lightweight +** contention control for a given count of resources. +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRSemaphore PRSemaphore; + +/* +** Create a new semaphore object. +*/ +NSPR_API(PRSemaphore*) PR_NewSem(PRUintn value); + +/* +** Destroy the given semaphore object. +** +*/ +NSPR_API(void) PR_DestroySem(PRSemaphore *sem); + +/* +** Wait on a Semaphore. +** +** This routine allows a calling thread to wait or proceed depending upon the +** state of the semahore sem. The thread can proceed only if the counter value +** of the semaphore sem is currently greater than 0. If the value of semaphore +** sem is positive, it is decremented by one and the routine returns immediately +** allowing the calling thread to continue. If the value of semaphore sem is 0, +** the calling thread blocks awaiting the semaphore to be released by another +** thread. +** +** This routine can return PR_PENDING_INTERRUPT if the waiting thread +** has been interrupted. +*/ +NSPR_API(PRStatus) PR_WaitSem(PRSemaphore *sem); + +/* +** This routine increments the counter value of the semaphore. If other threads +** are blocked for the semaphore, then the scheduler will determine which ONE +** thread will be unblocked. +*/ +NSPR_API(void) PR_PostSem(PRSemaphore *sem); + +/* +** Returns the value of the semaphore referenced by sem without affecting +** the state of the semaphore. The value represents the semaphore vaule +F** at the time of the call, but may not be the actual value when the +** caller inspects it. +*/ +NSPR_API(PRUintn) PR_GetValueSem(PRSemaphore *sem); + +PR_END_EXTERN_C + +#endif /* prsem_h___ */ diff --git a/nsprpub/pr/include/pratom.h b/nsprpub/pr/include/pratom.h new file mode 100644 index 00000000000..9389ee38f3f --- /dev/null +++ b/nsprpub/pr/include/pratom.h @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* GLOBAL FUNCTIONS: +** DESCRIPTION: +** PR Atomic operations +*/ + +#ifndef pratom_h___ +#define pratom_h___ + +#include "prtypes.h" +#include "prlock.h" + +PR_BEGIN_EXTERN_C + +/* +** FUNCTION: PR_AtomicIncrement +** DESCRIPTION: +** Atomically increment a 32 bit value. +** INPUTS: +** val: a pointer to the value to increment +** RETURN: +** the returned value is the result of the increment +*/ +NSPR_API(PRInt32) PR_AtomicIncrement(PRInt32 *val); + +/* +** FUNCTION: PR_AtomicDecrement +** DESCRIPTION: +** Atomically decrement a 32 bit value. +** INPUTS: +** val: a pointer to the value to decrement +** RETURN: +** the returned value is the result of the decrement +*/ +NSPR_API(PRInt32) PR_AtomicDecrement(PRInt32 *val); + +/* +** FUNCTION: PR_AtomicSet +** DESCRIPTION: +** Atomically set a 32 bit value. +** INPUTS: +** val: A pointer to a 32 bit value to be set +** newval: The newvalue to assign to val +** RETURN: +** Returns the prior value +*/ +NSPR_API(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 +*/ +NSPR_API(PRInt32) PR_AtomicAdd(PRInt32 *ptr, PRInt32 val); + +/* +** MACRO: PR_ATOMIC_INCREMENT +** MACRO: PR_ATOMIC_DECREMENT +** MACRO: PR_ATOMIC_SET +** MACRO: PR_ATOMIC_ADD +** DESCRIPTION: +** Macro versions of the atomic operations. They may be implemented +** as compiler intrinsics. +** +** IMPORTANT NOTE TO NSPR MAINTAINERS: +** Implement these macros with compiler intrinsics only on platforms +** where the PR_AtomicXXX functions are truly atomic (i.e., where the +** configuration macro _PR_HAVE_ATOMIC_OPS is defined). Otherwise, +** the macros and functions won't be compatible and can't be used +** interchangeably. +*/ +#if defined(_WIN32) && (_MSC_VER >= 1310) + +long __cdecl _InterlockedIncrement(long volatile *Addend); +#pragma intrinsic(_InterlockedIncrement) + +long __cdecl _InterlockedDecrement(long volatile *Addend); +#pragma intrinsic(_InterlockedDecrement) + +long __cdecl _InterlockedExchange(long volatile *Target, long Value); +#pragma intrinsic(_InterlockedExchange) + +long __cdecl _InterlockedExchangeAdd(long volatile *Addend, long Value); +#pragma intrinsic(_InterlockedExchangeAdd) + +#define PR_ATOMIC_INCREMENT(val) _InterlockedIncrement(val) +#define PR_ATOMIC_DECREMENT(val) _InterlockedDecrement(val) +#define PR_ATOMIC_SET(val, newval) _InterlockedExchange(val, newval) +#define PR_ATOMIC_ADD(ptr, val) (_InterlockedExchangeAdd(ptr, val) + (val)) + +#elif ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && \ + ((defined(DARWIN) && \ + (defined(__ppc__) || defined(__i386__))) || \ + (defined(LINUX) && \ + (defined(__i386__) || defined(__ia64__) || defined(__x86_64__) || \ + (defined(__powerpc__) && !defined(__powerpc64__)) || \ + defined(__alpha)))) + +/* + * Because the GCC manual warns that some processors may support + * reduced functionality of __sync_lock_test_and_set, we test for the + * processors that we believe support a full atomic exchange operation. + */ + +#define PR_ATOMIC_INCREMENT(val) __sync_add_and_fetch(val, 1) +#define PR_ATOMIC_DECREMENT(val) __sync_sub_and_fetch(val, 1) +#define PR_ATOMIC_SET(val, newval) __sync_lock_test_and_set(val, newval) +#define PR_ATOMIC_ADD(ptr, val) __sync_add_and_fetch(ptr, val) + +#else + +#define PR_ATOMIC_INCREMENT(val) PR_AtomicIncrement(val) +#define PR_ATOMIC_DECREMENT(val) PR_AtomicDecrement(val) +#define PR_ATOMIC_SET(val, newval) PR_AtomicSet(val, newval) +#define PR_ATOMIC_ADD(ptr, val) PR_AtomicAdd(ptr, val) + +#endif + +/* +** 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; + +/* +** 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. +*/ +NSPR_API(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 +*/ +NSPR_API(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 +*/ +NSPR_API(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 +*/ +NSPR_API(PRStatus) PR_DestroyStack(PRStack *stack); + +PR_END_EXTERN_C + +#endif /* pratom_h___ */ diff --git a/nsprpub/pr/include/prbit.h b/nsprpub/pr/include/prbit.h new file mode 100644 index 00000000000..1f4fc843e40 --- /dev/null +++ b/nsprpub/pr/include/prbit.h @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prbit_h___ +#define prbit_h___ + +#include "prtypes.h" +PR_BEGIN_EXTERN_C + +/* +** A prbitmap_t is a long integer that can be used for bitmaps +*/ +typedef unsigned long prbitmap_t; + +#define PR_TEST_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] & (1L << ((_bit) & (PR_BITS_PER_LONG-1)))) +#define PR_SET_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] |= (1L << ((_bit) & (PR_BITS_PER_LONG-1)))) +#define PR_CLEAR_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] &= ~(1L << ((_bit) & (PR_BITS_PER_LONG-1)))) + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +NSPR_API(PRIntn) PR_CeilingLog2(PRUint32 i); + +/* +** Compute the log of the greatest power of 2 less than or equal to n +*/ +NSPR_API(PRIntn) PR_FloorLog2(PRUint32 i); + +/* +** Macro version of PR_CeilingLog2: Compute the log of the least power of +** 2 greater than or equal to _n. The result is returned in _log2. +*/ +#define PR_CEILING_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 0; \ + if ((j_) & ((j_)-1)) \ + (_log2) += 1; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + PR_END_MACRO + +/* +** Macro version of PR_FloorLog2: Compute the log of the greatest power of +** 2 less than or equal to _n. The result is returned in _log2. +** +** This is equivalent to finding the highest set bit in the word. +*/ +#define PR_FLOOR_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 0; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + PR_END_MACRO + +/* +** Macros for rotate left and right. The argument 'a' must be an unsigned +** 32-bit integer type such as PRUint32. +** +** There is no rotate operation in the C Language, so the construct +** (a << 4) | (a >> 28) is frequently used instead. Most compilers convert +** this to a rotate instruction, but MSVC doesn't without a little help. +** To get MSVC to generate a rotate instruction, we have to use the _rotl +** or _rotr intrinsic and use a pragma to make it inline. +** +** Note: MSVC in VS2005 will do an inline rotate instruction on the above +** construct. +*/ + +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \ + defined(_M_X64)) +#include +#pragma intrinsic(_rotl, _rotr) +#define PR_ROTATE_LEFT32(a, bits) _rotl(a, bits) +#define PR_ROTATE_RIGHT32(a, bits) _rotr(a, bits) +#else +#define PR_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) +#define PR_ROTATE_RIGHT32(a, bits) (((a) >> (bits)) | ((a) << (32 - (bits)))) +#endif + +PR_END_EXTERN_C +#endif /* prbit_h___ */ diff --git a/nsprpub/pr/include/prclist.h b/nsprpub/pr/include/prclist.h new file mode 100644 index 00000000000..1680ac177c9 --- /dev/null +++ b/nsprpub/pr/include/prclist.h @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prclist_h___ +#define prclist_h___ + +#include "prtypes.h" + +typedef struct PRCListStr PRCList; + +/* +** Circular linked list +*/ +struct PRCListStr { + PRCList *next; + PRCList *prev; +}; + +/* +** Insert element "_e" into the list, before "_l". +*/ +#define PR_INSERT_BEFORE(_e,_l) \ + PR_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + PR_END_MACRO + +/* +** Insert element "_e" into the list, after "_l". +*/ +#define PR_INSERT_AFTER(_e,_l) \ + PR_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + PR_END_MACRO + +/* +** Return the element following element "_e" +*/ +#define PR_NEXT_LINK(_e) \ + ((_e)->next) +/* +** Return the element preceding element "_e" +*/ +#define PR_PREV_LINK(_e) \ + ((_e)->prev) + +/* +** Append an element "_e" to the end of the list "_l" +*/ +#define PR_APPEND_LINK(_e,_l) PR_INSERT_BEFORE(_e,_l) + +/* +** Insert an element "_e" at the head of the list "_l" +*/ +#define PR_INSERT_LINK(_e,_l) PR_INSERT_AFTER(_e,_l) + +/* Return the head/tail of the list */ +#define PR_LIST_HEAD(_l) (_l)->next +#define PR_LIST_TAIL(_l) (_l)->prev + +/* +** Remove the element "_e" from it's circular list. +*/ +#define PR_REMOVE_LINK(_e) \ + PR_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + PR_END_MACRO + +/* +** Remove the element "_e" from it's circular list. Also initializes the +** linkage. +*/ +#define PR_REMOVE_AND_INIT_LINK(_e) \ + PR_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + (_e)->next = (_e); \ + (_e)->prev = (_e); \ + PR_END_MACRO + +/* +** Return non-zero if the given circular list "_l" is empty, zero if the +** circular list is not empty +*/ +#define PR_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* +** Initialize a circular list +*/ +#define PR_INIT_CLIST(_l) \ + PR_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + PR_END_MACRO + +#define PR_INIT_STATIC_CLIST(_l) \ + {(_l), (_l)} + +#endif /* prclist_h___ */ diff --git a/nsprpub/pr/include/prcmon.h b/nsprpub/pr/include/prcmon.h new file mode 100644 index 00000000000..f61cf56a0ba --- /dev/null +++ b/nsprpub/pr/include/prcmon.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prcmon_h___ +#define prcmon_h___ + +/* +** Interface to cached monitors. Cached monitors use an address to find a +** given PR monitor. In this way a monitor can be associated with another +** object without preallocating a monitor for all objects. +** +** A hash table is used to quickly map addresses to individual monitors +** and the system automatically grows the hash table as needed. +** +** Cache monitors are about 5 times slower to use than uncached monitors. +*/ +#include "prmon.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +/** +** Like PR_EnterMonitor except use the "address" to find a monitor in the +** monitor cache. If successful, returns the PRMonitor now associated +** with "address". Note that you must PR_CExitMonitor the address to +** release the monitor cache entry (otherwise the monitor cache will fill +** up). This call will return NULL if the monitor cache needs to be +** expanded and the system is out of memory. +*/ +NSPR_API(PRMonitor*) PR_CEnterMonitor(void *address); + +/* +** Like PR_ExitMonitor except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CExitMonitor(void *address); + +/* +** Like PR_Wait except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CWait(void *address, PRIntervalTime timeout); + +/* +** Like PR_Notify except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CNotify(void *address); + +/* +** Like PR_NotifyAll except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CNotifyAll(void *address); + +/* +** Set a callback to be invoked each time a monitor is recycled from the cache +** freelist, with the monitor's cache-key passed in address. +*/ +NSPR_API(void) PR_CSetOnMonitorRecycle(void (PR_CALLBACK *callback)(void *address)); + +PR_END_EXTERN_C + +#endif /* prcmon_h___ */ diff --git a/nsprpub/pr/include/prcountr.h b/nsprpub/pr/include/prcountr.h new file mode 100644 index 00000000000..4b197e974bb --- /dev/null +++ b/nsprpub/pr/include/prcountr.h @@ -0,0 +1,557 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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 + + + +/* ----------------------------------------------------------------------- +** 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. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_INIT_COUNTER_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) +#else +#define PR_INIT_COUNTER_HANDLE(handle,value) +#endif + +/* ----------------------------------------------------------------------- +** 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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_CREATE_COUNTER(handle,qName,rName,description)\ + (handle) = PR_CreateCounter((qName),(rName),(description)) +#else +#define PR_CREATE_COUNTER(handle,qName,rName,description) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_DESTROY_COUNTER(handle) PR_DestroyCounter((handle)) +#else +#define PR_DESTROY_COUNTER(handle) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetCounterHandleFromName((qName),(rName)) +#else +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetCounterNameFromHandle((handle),(qName),(rName),(description)) +#else +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description ) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_INCREMENT_COUNTER(handle) PR_IncrementCounter(handle) +#else +#define PR_INCREMENT_COUNTER(handle) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_DECREMENT_COUNTER(handle) PR_DecrementCounter(handle) +#else +#define PR_DECREMENT_COUNTER(handle) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_ADD_TO_COUNTER(handle,value)\ + PR_AddToCounter((handle),(value)) +#else +#define PR_ADD_TO_COUNTER(handle,value) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_SUBTRACT_FROM_COUNTER(handle,value)\ + PR_SubtractFromCounter((handle),(value)) +#else +#define PR_SUBTRACT_FROM_COUNTER(handle,value) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER(counter,handle)\ + (counter) = PR_GetCounter((handle)) +#else +#define PR_GET_COUNTER(counter,handle) 0 +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_SET_COUNTER(handle,value) PR_SetCounter((handle),(value)) +#else +#define PR_SET_COUNTER(handle,value) +#endif + +NSPR_API(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. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle)\ + (next) = PR_FindNextCounterQname((handle)) +#else +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle) NULL +#endif + +NSPR_API(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. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextCounterRname((rhandle),(qhandle)) +#else +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle) +#endif + +NSPR_API(PRCounterHandle) + PR_FindNextCounterRname( + PRCounterHandle rhandle, + PRCounterHandle qhandle +); + +PR_END_EXTERN_C + +#endif /* prcountr_h___ */ diff --git a/nsprpub/pr/include/prcvar.h b/nsprpub/pr/include/prcvar.h new file mode 100644 index 00000000000..c668493783d --- /dev/null +++ b/nsprpub/pr/include/prcvar.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prcvar_h___ +#define prcvar_h___ + +#include "prlock.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRCondVar PRCondVar; + +/* +** Create a new condition variable. +** +** "lock" is the lock used to protect the condition variable. +** +** Condition variables are synchronization objects that threads can use +** to wait for some condition to occur. +** +** This may fail if memory is tight or if some operating system resource +** is low. In such cases, a NULL will be returned. +*/ +NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock); + +/* +** Destroy a condition variable. There must be no thread +** waiting on the condvar. The caller is responsible for guaranteeing +** that the condvar is no longer in use. +** +*/ +NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar); + +/* +** The thread that waits on a condition is blocked in a "waiting on +** condition" state until another thread notifies the condition or a +** caller specified amount of time expires. The lock associated with +** the condition variable will be released, which must have be held +** prior to the call to wait. +** +** Logically a notified thread is moved from the "waiting on condition" +** state and made "ready." When scheduled, it will attempt to reacquire +** the lock that it held when wait was called. +** +** The timeout has two well known values, PR_INTERVAL_NO_TIMEOUT and +** PR_INTERVAL_NO_WAIT. The former value requires that a condition be +** notified (or the thread interrupted) before it will resume from the +** wait. If the timeout has a value of PR_INTERVAL_NO_WAIT, the effect +** is to release the lock, possibly causing a rescheduling within the +** runtime, then immediately attempting to reacquire the lock and resume. +** +** Any other value for timeout will cause the thread to be rescheduled +** either due to explicit notification or an expired interval. The latter +** must be determined by treating time as one part of the monitored data +** being protected by the lock and tested explicitly for an expired +** interval. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable or the thread was interrupted (PR_Interrupt()). +** The particular reason can be extracted with PR_GetError(). +*/ +NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout); + +/* +** Notify ONE thread that is currently waiting on 'cvar'. Which thread is +** dependent on the implementation of the runtime. Common sense would dictate +** that all threads waiting on a single condition have identical semantics, +** therefore which one gets notified is not significant. +** +** The calling thead must hold the lock that protects the condition, as +** well as the invariants that are tightly bound to the condition, when +** notify is called. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar); + +/* +** Notify all of the threads waiting on the condition variable. The order +** that the threads are notified is indeterminant. The lock that protects +** the condition must be held. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar); + +PR_END_EXTERN_C + +#endif /* prcvar_h___ */ diff --git a/nsprpub/pr/include/prdtoa.h b/nsprpub/pr/include/prdtoa.h new file mode 100644 index 00000000000..54e8c34f4c3 --- /dev/null +++ b/nsprpub/pr/include/prdtoa.h @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prdtoa_h___ +#define prdtoa_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_strtod() returns as a double-precision floating-point number +** the value represented by the character string pointed to by +** s00. The string is scanned up to the first unrecognized +** character. +**a +** If the value of se is not (char **)NULL, a pointer to +** the character terminating the scan is returned in the location pointed +** to by se. If no number can be formed, se is set to s00, and +** zero is returned. +*/ +#if defined(HAVE_WATCOM_BUG_1) +/* this is a hack to circumvent a bug in the Watcom C/C++ 11.0 compiler +** When Watcom fixes the bug, remove the special case for Win16 +*/ +PRFloat64 __pascal __loadds __export +#else +NSPR_API(PRFloat64) +#endif +PR_strtod(const char *s00, char **se); + +/* +** PR_cnvtf() +** conversion routines for floating point +** prcsn - number of digits of precision to generate floating +** point value. +*/ +NSPR_API(void) PR_cnvtf(char *buf, PRIntn bufsz, PRIntn prcsn, PRFloat64 fval); + +/* +** PR_dtoa() converts double to a string. +** +** ARGUMENTS: +** If rve is not null, *rve is set to point to the end of the return value. +** If d is +-Infinity or NaN, then *decpt is set to 9999. +** +** mode: +** 0 ==> shortest string that yields d when read in +** and rounded to nearest. +*/ +NSPR_API(PRStatus) PR_dtoa(PRFloat64 d, PRIntn mode, PRIntn ndigits, + PRIntn *decpt, PRIntn *sign, char **rve, char *buf, PRSize bufsize); + +PR_END_EXTERN_C + +#endif /* prdtoa_h___ */ diff --git a/nsprpub/pr/include/prenv.h b/nsprpub/pr/include/prenv.h new file mode 100644 index 00000000000..2cae7d79eea --- /dev/null +++ b/nsprpub/pr/include/prenv.h @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prenv_h___ +#define prenv_h___ + +#include "prtypes.h" + +/*******************************************************************************/ +/*******************************************************************************/ +/****************** THESE FUNCTIONS MAY NOT BE THREAD SAFE *********************/ +/*******************************************************************************/ +/*******************************************************************************/ + +PR_BEGIN_EXTERN_C + +/* +** PR_GetEnv() -- Retrieve value of environment variable +** +** Description: +** PR_GetEnv() is modeled on Unix getenv(). +** +** +** Inputs: +** var -- The name of the environment variable +** +** Returns: +** The value of the environment variable 'var' or NULL if +** the variable is undefined. +** +** Restrictions: +** You'd think that a POSIX getenv(), putenv() would be +** consistently implemented everywhere. Surprise! It is not. On +** some platforms, a putenv() where the argument is of +** the form "name" causes the named environment variable to +** be un-set; that is: a subsequent getenv() returns NULL. On +** other platforms, the putenv() fails, on others, it is a +** no-op. Similarly, a putenv() where the argument is of the +** form "name=" causes the named environment variable to be +** un-set; a subsequent call to getenv() returns NULL. On +** other platforms, a subsequent call to getenv() returns a +** pointer to a null-string (a byte of zero). +** +** PR_GetEnv(), PR_SetEnv() provide a consistent behavior +** across all supported platforms. There are, however, some +** restrictions and some practices you must use to achieve +** consistent results everywhere. +** +** When manipulating the environment there is no way to un-set +** an environment variable across all platforms. We suggest +** you interpret the return of a pointer to null-string to +** mean the same as a return of NULL from PR_GetEnv(). +** +** A call to PR_SetEnv() where the parameter is of the form +** "name" will return PR_FAILURE; the environment remains +** unchanged. A call to PR_SetEnv() where the parameter is +** of the form "name=" may un-set the envrionment variable on +** some platforms; on others it may set the value of the +** environment variable to the null-string. +** +** For example, to test for NULL return or return of the +** null-string from PR_GetEnv(), use the following code +** fragment: +** +** char *val = PR_GetEnv("foo"); +** if ((NULL == val) || ('\0' == *val)) { +** ... interpret this as un-set ... +** } +** +** The caller must ensure that the string passed +** to PR_SetEnv() is persistent. That is: The string should +** not be on the stack, where it can be overwritten +** on return from the function calling PR_SetEnv(). +** Similarly, the string passed to PR_SetEnv() must not be +** overwritten by other actions of the process. ... Some +** platforms use the string by reference rather than copying +** it into the environment space. ... You have been warned! +** +** Use of platform-native functions that manipulate the +** environment (getenv(), putenv(), +** SetEnvironmentVariable(), etc.) must not be used with +** NSPR's similar functions. The platform-native functions +** may not be thread safe and/or may operate on different +** conceptual environment space than that operated upon by +** NSPR's functions or other environment manipulating +** functions on the same platform. (!) +** +*/ +NSPR_API(char*) PR_GetEnv(const char *var); + +/* +** PR_SetEnv() -- set, unset or change an environment variable +** +** Description: +** PR_SetEnv() is modeled on the Unix putenv() function. +** +** Inputs: +** string -- pointer to a caller supplied +** constant, persistent string of the form name=value. Where +** name is the name of the environment variable to be set or +** changed; value is the value assigned to the variable. +** +** Returns: +** PRStatus. +** +** Restrictions: +** See the Restrictions documented in the description of +** PR_GetEnv() in this header file. +** +** +*/ +NSPR_API(PRStatus) PR_SetEnv(const char *string); + +/* +** DEPRECATED. Use PR_SetEnv() instead. +*/ +#ifdef XP_MAC +NSPR_API(PRIntn) PR_PutEnv(const char *string); +#endif + +PR_END_EXTERN_C + +#endif /* prenv_h___ */ diff --git a/nsprpub/pr/include/prerr.h b/nsprpub/pr/include/prerr.h new file mode 100644 index 00000000000..eba68f1f4f6 --- /dev/null +++ b/nsprpub/pr/include/prerr.h @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prerr_h___ +#define prerr_h___ + +/* + * + * prerr.h + * This file is automatically generated; please do not edit it. + */ + +/* Memory allocation attempt failed */ +#define PR_OUT_OF_MEMORY_ERROR (-6000L) + +/* Invalid file descriptor */ +#define PR_BAD_DESCRIPTOR_ERROR (-5999L) + +/* The operation would have blocked */ +#define PR_WOULD_BLOCK_ERROR (-5998L) + +/* Invalid memory address argument */ +#define PR_ACCESS_FAULT_ERROR (-5997L) + +/* Invalid function for file type */ +#define PR_INVALID_METHOD_ERROR (-5996L) + +/* Invalid memory address argument */ +#define PR_ILLEGAL_ACCESS_ERROR (-5995L) + +/* Some unknown error has occurred */ +#define PR_UNKNOWN_ERROR (-5994L) + +/* Operation interrupted by another thread */ +#define PR_PENDING_INTERRUPT_ERROR (-5993L) + +/* function not implemented */ +#define PR_NOT_IMPLEMENTED_ERROR (-5992L) + +/* I/O function error */ +#define PR_IO_ERROR (-5991L) + +/* I/O operation timed out */ +#define PR_IO_TIMEOUT_ERROR (-5990L) + +/* I/O operation on busy file descriptor */ +#define PR_IO_PENDING_ERROR (-5989L) + +/* The directory could not be opened */ +#define PR_DIRECTORY_OPEN_ERROR (-5988L) + +/* Invalid function argument */ +#define PR_INVALID_ARGUMENT_ERROR (-5987L) + +/* Network address not available (in use?) */ +#define PR_ADDRESS_NOT_AVAILABLE_ERROR (-5986L) + +/* Network address type not supported */ +#define PR_ADDRESS_NOT_SUPPORTED_ERROR (-5985L) + +/* Already connected */ +#define PR_IS_CONNECTED_ERROR (-5984L) + +/* Network address is invalid */ +#define PR_BAD_ADDRESS_ERROR (-5983L) + +/* Local Network address is in use */ +#define PR_ADDRESS_IN_USE_ERROR (-5982L) + +/* Connection refused by peer */ +#define PR_CONNECT_REFUSED_ERROR (-5981L) + +/* Network address is presently unreachable */ +#define PR_NETWORK_UNREACHABLE_ERROR (-5980L) + +/* Connection attempt timed out */ +#define PR_CONNECT_TIMEOUT_ERROR (-5979L) + +/* Network file descriptor is not connected */ +#define PR_NOT_CONNECTED_ERROR (-5978L) + +/* Failure to load dynamic library */ +#define PR_LOAD_LIBRARY_ERROR (-5977L) + +/* Failure to unload dynamic library */ +#define PR_UNLOAD_LIBRARY_ERROR (-5976L) + +/* Symbol not found in any of the loaded dynamic libraries */ +#define PR_FIND_SYMBOL_ERROR (-5975L) + +/* Insufficient system resources */ +#define PR_INSUFFICIENT_RESOURCES_ERROR (-5974L) + +/* A directory lookup on a network address has failed */ +#define PR_DIRECTORY_LOOKUP_ERROR (-5973L) + +/* Attempt to access a TPD key that is out of range */ +#define PR_TPD_RANGE_ERROR (-5972L) + +/* Process open FD table is full */ +#define PR_PROC_DESC_TABLE_FULL_ERROR (-5971L) + +/* System open FD table is full */ +#define PR_SYS_DESC_TABLE_FULL_ERROR (-5970L) + +/* Network operation attempted on non-network file descriptor */ +#define PR_NOT_SOCKET_ERROR (-5969L) + +/* TCP-specific function attempted on a non-TCP file descriptor */ +#define PR_NOT_TCP_SOCKET_ERROR (-5968L) + +/* TCP file descriptor is already bound */ +#define PR_SOCKET_ADDRESS_IS_BOUND_ERROR (-5967L) + +/* Access Denied */ +#define PR_NO_ACCESS_RIGHTS_ERROR (-5966L) + +/* The requested operation is not supported by the platform */ +#define PR_OPERATION_NOT_SUPPORTED_ERROR (-5965L) + +/* The host operating system does not support the protocol requested */ +#define PR_PROTOCOL_NOT_SUPPORTED_ERROR (-5964L) + +/* Access to the remote file has been severed */ +#define PR_REMOTE_FILE_ERROR (-5963L) + +/* The value requested is too large to be stored in the data buffer provided */ +#define PR_BUFFER_OVERFLOW_ERROR (-5962L) + +/* TCP connection reset by peer */ +#define PR_CONNECT_RESET_ERROR (-5961L) + +/* Unused */ +#define PR_RANGE_ERROR (-5960L) + +/* The operation would have deadlocked */ +#define PR_DEADLOCK_ERROR (-5959L) + +/* The file is already locked */ +#define PR_FILE_IS_LOCKED_ERROR (-5958L) + +/* Write would result in file larger than the system allows */ +#define PR_FILE_TOO_BIG_ERROR (-5957L) + +/* The device for storing the file is full */ +#define PR_NO_DEVICE_SPACE_ERROR (-5956L) + +/* Unused */ +#define PR_PIPE_ERROR (-5955L) + +/* Unused */ +#define PR_NO_SEEK_DEVICE_ERROR (-5954L) + +/* Cannot perform a normal file operation on a directory */ +#define PR_IS_DIRECTORY_ERROR (-5953L) + +/* Symbolic link loop */ +#define PR_LOOP_ERROR (-5952L) + +/* File name is too long */ +#define PR_NAME_TOO_LONG_ERROR (-5951L) + +/* File not found */ +#define PR_FILE_NOT_FOUND_ERROR (-5950L) + +/* Cannot perform directory operation on a normal file */ +#define PR_NOT_DIRECTORY_ERROR (-5949L) + +/* Cannot write to a read-only file system */ +#define PR_READ_ONLY_FILESYSTEM_ERROR (-5948L) + +/* Cannot delete a directory that is not empty */ +#define PR_DIRECTORY_NOT_EMPTY_ERROR (-5947L) + +/* Cannot delete or rename a file object while the file system is busy */ +#define PR_FILESYSTEM_MOUNTED_ERROR (-5946L) + +/* Cannot rename a file to a file system on another device */ +#define PR_NOT_SAME_DEVICE_ERROR (-5945L) + +/* The directory object in the file system is corrupted */ +#define PR_DIRECTORY_CORRUPTED_ERROR (-5944L) + +/* Cannot create or rename a filename that already exists */ +#define PR_FILE_EXISTS_ERROR (-5943L) + +/* Directory is full. No additional filenames may be added */ +#define PR_MAX_DIRECTORY_ENTRIES_ERROR (-5942L) + +/* The required device was in an invalid state */ +#define PR_INVALID_DEVICE_STATE_ERROR (-5941L) + +/* The device is locked */ +#define PR_DEVICE_IS_LOCKED_ERROR (-5940L) + +/* No more entries in the directory */ +#define PR_NO_MORE_FILES_ERROR (-5939L) + +/* Encountered end of file */ +#define PR_END_OF_FILE_ERROR (-5938L) + +/* Seek error */ +#define PR_FILE_SEEK_ERROR (-5937L) + +/* The file is busy */ +#define PR_FILE_IS_BUSY_ERROR (-5936L) + +/* The I/O operation was aborted */ +#define PR_OPERATION_ABORTED_ERROR (-5935L) + +/* Operation is still in progress (probably a non-blocking connect) */ +#define PR_IN_PROGRESS_ERROR (-5934L) + +/* Operation has already been initiated (probably a non-blocking connect) */ +#define PR_ALREADY_INITIATED_ERROR (-5933L) + +/* The wait group is empty */ +#define PR_GROUP_EMPTY_ERROR (-5932L) + +/* Object state improper for request */ +#define PR_INVALID_STATE_ERROR (-5931L) + +/* Network is down */ +#define PR_NETWORK_DOWN_ERROR (-5930L) + +/* Socket shutdown */ +#define PR_SOCKET_SHUTDOWN_ERROR (-5929L) + +/* Connection aborted */ +#define PR_CONNECT_ABORTED_ERROR (-5928L) + +/* Host is unreachable */ +#define PR_HOST_UNREACHABLE_ERROR (-5927L) + +/* The library is not loaded */ +#define PR_LIBRARY_NOT_LOADED_ERROR (-5926L) + +/* The one-time function was previously called and failed. Its error code is no longer available */ +#define PR_CALL_ONCE_ERROR (-5925L) + +/* Placeholder for the end of the list */ +#define PR_MAX_ERROR (-5924L) + +extern void nspr_InitializePRErrorTable(void); +#define ERROR_TABLE_BASE_nspr (-6000L) + +#endif /* prerr_h___ */ diff --git a/nsprpub/pr/include/prerror.h b/nsprpub/pr/include/prerror.h new file mode 100644 index 00000000000..cf94872e306 --- /dev/null +++ b/nsprpub/pr/include/prerror.h @@ -0,0 +1,326 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prerror_h___ +#define prerror_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef PRInt32 PRErrorCode; + +#define PR_NSPR_ERROR_BASE -6000 + +#include "prerr.h" + +/* +** Set error will preserve an error condition within a thread context. +** The values stored are the NSPR (platform independent) translation of +** the error. Also, if available, the platform specific oserror is stored. +** If there is no appropriate OS error number, a zero my be supplied. +*/ +NSPR_API(void) PR_SetError(PRErrorCode errorCode, PRInt32 oserr); + +/* +** The text value specified may be NULL. If it is not NULL and the text length +** is zero, the string is assumed to be a null terminated C string. Otherwise +** the text is assumed to be the length specified and possibly include NULL +** characters (e.g., a multi-national string). +** +** The text will be copied into to thread structure and remain there +** until the next call to PR_SetError. +*/ +NSPR_API(void) PR_SetErrorText( + PRIntn textLength, const char *text); + +/* +** Return the current threads last set error code. +*/ +NSPR_API(PRErrorCode) PR_GetError(void); + +/* +** Return the current threads last set os error code. This is used for +** machine specific code that desires the underlying os error. +*/ +NSPR_API(PRInt32) PR_GetOSError(void); + +/* +** Get the length of the error text. If a zero is returned, then there +** is no text. Otherwise, the value returned is sufficient to contain +** the error text currently available. +*/ +NSPR_API(PRInt32) PR_GetErrorTextLength(void); + +/* +** Copy the current threads current error text. Then actual number of bytes +** copied is returned as the result. If the result is zero, the 'text' area +** is unaffected. +*/ +NSPR_API(PRInt32) PR_GetErrorText(char *text); + + +/* +Copyright (C) 1987, 1988 Student Information Processing Board of the +Massachusetts Institute of Technology. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B. +make no representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied warranty. +*/ + + +/* + * NOTE: + * The interfaces for error-code-translation described in the rest of + * this file are preliminary in the 3.1 release of nspr and are subject + * to change in future releases. + */ + +/* +** Description: Localizable error code to string function. +** +** +** NSPR provides a mechanism for converting an error code to a +** descriptive string, in a caller-specified language. +** +** Error codes themselves are 32 bit (signed) integers. Typically, +** the high order 24 bits are an identifier of which error table the +** error code is from, and the low order 8 bits are a sequential error +** number within the table. NSPR supports error tables whose first +** error code is not a multiple of 256, such error code assignments +** should be avoided when possible. +** +** Error table 0 is defined to match the UNIX system call error table +** (sys_errlist); this allows errno values to be used directly in the +** library. Other error table numbers are typically formed by +** compacting together the first four characters of the error table +** name. The mapping between characters in the name and numeric +** values in the error code are defined in a system-independent +** fashion, so that two systems that can pass integral values between +** them can reliably pass error codes without loss of meaning; this +** should work even if the character sets used are not the +** same. (However, if this is to be done, error table 0 should be +** avoided, since the local system call error tables may differ.) +** +** Libraries defining error codes need only provide a table mapping +** error code numbers to names and default English descriptions, +** calling a routine to install the table, making it ``known'' to NSPR +** library. Once installed, a table may not be removed. Any error +** code the library generates can be converted to the corresponding +** error message. There is also a default format for error codes +** accidentally returned before making the table known, which is of +** the form "unknown code foo 32", where "foo" would be the name of +** the table. +** +** Normally, the error code conversion routine only supports the +** languages "i-default" and "en", returning the error-table-provided +** English description for both languages. The application may +** provide a localization plugin, allowing support for additional +** languages. +** +**/ + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +/* + * PRLanguageCode -- + * + * NSPR represents a language code as a non-negative integer. + * Languages 0 is always "i-default" the language you get without + * explicit negotiation. Language 1 is always "en", English + * which has been explicitly negotiated. Additional language + * codes are defined by an application-provided localization plugin. + */ +typedef PRUint32 PRLanguageCode; +#define PR_LANGUAGE_I_DEFAULT 0 /* i-default, the default language */ +#define PR_LANGUAGE_EN 1 /* English, explicitly negotiated */ + +/* + * struct PRErrorMessage -- + * + * An error message in an error table. + */ +struct PRErrorMessage { + const char * name; /* Macro name for error */ + const char * en_text; /* Default English text */ +}; + +/* + * struct PRErrorTable -- + * + * An error table, provided by a library. + */ +struct PRErrorTable { + const struct PRErrorMessage * msgs; /* Array of error information */ + const char *name; /* Name of error table source */ + PRErrorCode base; /* Error code for first error in table */ + int n_msgs; /* Number of codes in table */ +}; + +/* + * struct PRErrorCallbackPrivate -- + * + * A private structure for the localization plugin + */ +struct PRErrorCallbackPrivate; + +/* + * struct PRErrorCallbackTablePrivate -- + * + * A data structure under which the localization plugin may store information, + * associated with an error table, that is private to itself. + */ +struct PRErrorCallbackTablePrivate; + +/* + * PRErrorCallbackLookupFn -- + * + * A function of PRErrorCallbackLookupFn type is a localization + * plugin callback which converts an error code into a description + * in the requested language. The callback is provided the + * appropriate error table, private data for the plugin and the table. + * The callback returns the appropriate UTF-8 encoded description, or NULL + * if no description can be found. + */ +typedef const char * +PRErrorCallbackLookupFn(PRErrorCode code, PRLanguageCode language, + const struct PRErrorTable *table, + struct PRErrorCallbackPrivate *cb_private, + struct PRErrorCallbackTablePrivate *table_private); + +/* + * PRErrorCallbackNewTableFn -- + * + * A function PRErrorCallbackNewTableFn type is a localization plugin + * callback which is called once with each error table registered + * with NSPR. The callback is provided with the error table and + * the plugin's private structure. The callback returns any table private + * data it wishes to associate with the error table. Does not need to be thread + * safe. + */ +typedef struct PRErrorCallbackTablePrivate * +PRErrorCallbackNewTableFn(const struct PRErrorTable *table, + struct PRErrorCallbackPrivate *cb_private); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_ErrorToString +** DESCRIPTION: +** Returns the UTF-8 message for an error code in +** the requested language. May return the message +** in the default language if a translation in the requested +** language is not available. The returned string is +** valid for the duration of the process. Never returns NULL. +** +***********************************************************************/ +NSPR_API(const char *) PR_ErrorToString(PRErrorCode code, + PRLanguageCode language); + + +/*********************************************************************** +** FUNCTION: PR_ErrorToName +** DESCRIPTION: +** Returns the macro name for an error code, or NULL +** if the error code is not known. The returned string is +** valid for the duration of the process. +** +** Does not work for error table 0, the system error codes. +** +***********************************************************************/ +NSPR_API(const char *) PR_ErrorToName(PRErrorCode code); + + +/*********************************************************************** +** FUNCTION: PR_ErrorLanguages +** DESCRIPTION: +** Returns the RFC 1766 language tags for the language +** codes PR_ErrorToString() supports. The returned array is valid +** for the duration of the process. Never returns NULL. The first +** item in the returned array is the language tag for PRLanguageCode 0, +** the second is for PRLanguageCode 1, and so on. The array is terminated +** with a null pointer. +** +***********************************************************************/ +NSPR_API(const char * const *) PR_ErrorLanguages(void); + + +/*********************************************************************** +** FUNCTION: PR_ErrorInstallTable +** DESCRIPTION: +** Registers an error table with NSPR. Must be done exactly once per +** table. Memory pointed to by `table' must remain valid for the life +** of the process. +** +** NOT THREAD SAFE! +** +***********************************************************************/ +NSPR_API(PRErrorCode) PR_ErrorInstallTable(const struct PRErrorTable *table); + + +/*********************************************************************** +** FUNCTION: PR_ErrorInstallCallback +** DESCRIPTION: +** Registers an error localization plugin with NSPR. May be called +** at most one time. `languages' contains the language codes supported +** by this plugin. Languages 0 and 1 must be "i-default" and "en" +** respectively. `lookup' and `newtable' contain pointers to +** the plugin callback functions. `cb_private' contains any information +** private to the plugin functions. +** +** NOT THREAD SAFE! +** +***********************************************************************/ +NSPR_API(void) PR_ErrorInstallCallback(const char * const * languages, + PRErrorCallbackLookupFn *lookup, + PRErrorCallbackNewTableFn *newtable, + struct PRErrorCallbackPrivate *cb_private); + +PR_END_EXTERN_C + +#endif /* prerror_h___ */ diff --git a/nsprpub/pr/include/prinet.h b/nsprpub/pr/include/prinet.h new file mode 100644 index 00000000000..02dfef6fce3 --- /dev/null +++ b/nsprpub/pr/include/prinet.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: prinet.h + * Description: + * Header file used to find the system header files for socket support. + * This file serves the following purposes: + * - A cross-platform, "get-everything" socket header file. On + * Unix, socket support is scattered in several header files, + * while Windows and Mac have a "get-everything" socket header + * file. + * - NSPR needs the following macro definitions and function + * prototype declarations from these header files: + * AF_INET + * INADDR_ANY, INADDR_LOOPBACK, INADDR_BROADCAST + * ntohl(), ntohs(), htonl(), ntons(). + * NSPR does not define its own versions of these macros and + * functions. It simply uses the native versions, which have + * the same names on all supported platforms. + * This file is intended to be included by nspr20 public header + * files, such as prio.h. One should not include this file directly. + */ + +#ifndef prinet_h__ +#define prinet_h__ + +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) +#include +#include /* AF_INET */ +#include /* INADDR_ANY, ..., ntohl(), ... */ +#ifdef XP_OS2 +#include +#endif +#ifdef XP_UNIX +#ifdef AIX +/* + * On AIX 4.3, the header refers to struct + * ether_addr and struct sockaddr_dl that are not declared. + * The following struct declarations eliminate the compiler + * warnings. + */ +struct ether_addr; +struct sockaddr_dl; +#endif /* AIX */ +#include +#endif /* XP_UNIX */ +#include + +#if defined(FREEBSD) || defined(BSDI) || defined(QNX) +#include /* the only place that defines INADDR_LOOPBACK */ +#endif + +/* + * OS/2 hack. For some reason INADDR_LOOPBACK is not defined in the + * socket headers. + */ +#if defined(OS2) && !defined(INADDR_LOOPBACK) +#define INADDR_LOOPBACK 0x7f000001 +#endif + +/* + * Prototypes of ntohl() etc. are declared in + * on these platforms. + */ +#if defined(BSDI) || defined(OSF1) +#include +#endif + +#elif defined(WIN32) + +/* Do not include any system header files. */ + +#elif defined(WIN16) + +#include + +#elif defined(XP_MAC) + +#include "macsocket.h" + +#else + +#error Unknown platform + +#endif + +#endif /* prinet_h__ */ diff --git a/nsprpub/pr/include/prinit.h b/nsprpub/pr/include/prinit.h new file mode 100644 index 00000000000..5239e4fa5a9 --- /dev/null +++ b/nsprpub/pr/include/prinit.h @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prinit_h___ +#define prinit_h___ + +#include "prthread.h" +#include "prtypes.h" +#include "prwin16.h" +#include + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ + +/* +** NSPR's name, this should persist until at least the turn of the +** century. +*/ +#define PR_NAME "NSPR" + +/* +** NSPR's version is used to determine the likelihood that the version you +** used to build your component is anywhere close to being compatible with +** what is in the underlying library. +** +** The format of the version string is +** ".[.] []" +*/ +#define PR_VERSION "4.7.1" +#define PR_VMAJOR 4 +#define PR_VMINOR 7 +#define PR_VPATCH 1 +#define PR_BETA PR_FALSE + +/* +** PRVersionCheck +** +** The basic signature of the function that is called to provide version +** checking. The result will be a boolean that indicates the likelihood +** that the underling library will perform as the caller expects. +** +** The only argument is a string, which should be the verson identifier +** of the library in question. That string will be compared against an +** equivalent string that represents the actual build version of the +** exporting library. +** +** The result will be the logical union of the directly called library +** and all dependent libraries. +*/ + +typedef PRBool (*PRVersionCheck)(const char*); + +/* +** PR_VersionCheck +** +** NSPR's existance proof of the version check function. +** +** Note that NSPR has no cooperating dependencies. +*/ + +NSPR_API(PRBool) PR_VersionCheck(const char *importedVersion); + + +/************************************************************************/ +/*******************************INITIALIZATION***************************/ +/************************************************************************/ + +/* +** Initialize the runtime. Attach a thread object to the currently +** executing native thread of type "type". +** +** The specificaiton of 'maxPTDs' is ignored. +*/ +NSPR_API(void) PR_Init( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs); + +/* +** And alternate form of initialization, one that may become the default if +** not the only mechanism, provides a method to get the NSPR runtime init- +** ialized and place NSPR between the caller and the runtime library. This +** allows main() to be treated as any other thread root function, signalling +** its compeletion by returning and allowing the runtime to coordinate the +** completion of the other threads of the runtime. +** +** The priority of the main (or primordial) thread will be PR_PRIORITY_NORMAL. +** The thread may adjust its own priority by using PR_SetPriority(), though +** at this time the support for priorities is somewhat weak. +** +** The specificaiton of 'maxPTDs' is ignored. +** +** The value returned by PR_Initialize is the value returned from the root +** function, 'prmain'. +*/ + +typedef PRIntn (PR_CALLBACK *PRPrimordialFn)(PRIntn argc, char **argv); + +NSPR_API(PRIntn) PR_Initialize( + PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs); + +/* +** Return PR_TRUE if PR_Init has already been called. +*/ +NSPR_API(PRBool) PR_Initialized(void); + +/* + * Perform a graceful shutdown of NSPR. PR_Cleanup() may be called by + * the primordial thread near the end of the main() function. + * + * PR_Cleanup() attempts to synchronize the natural termination of + * process. It does that by blocking the caller, if and only if it is + * the primordial thread, until the number of user threads has dropped + * to zero. When the primordial thread returns from main(), the process + * will immediately and silently exit. That is, it will (if necessary) + * forcibly terminate any existing threads and exit without significant + * blocking and there will be no error messages or core files. + * + * PR_Cleanup() returns PR_SUCCESS if NSPR is successfully shutdown, + * or PR_FAILURE if the calling thread of this function is not the + * primordial thread. + */ +NSPR_API(PRStatus) PR_Cleanup(void); + +/* +** Disable Interrupts +** Disables timer signals used for pre-emptive scheduling. +*/ +NSPR_API(void) PR_DisableClockInterrupts(void); + +/* +** Enables Interrupts +** Enables timer signals used for pre-emptive scheduling. +*/ +NSPR_API(void) PR_EnableClockInterrupts(void); + +/* +** Block Interrupts +** Blocks the timer signal used for pre-emptive scheduling +*/ +NSPR_API(void) PR_BlockClockInterrupts(void); + +/* +** Unblock Interrupts +** Unblocks the timer signal used for pre-emptive scheduling +*/ +NSPR_API(void) PR_UnblockClockInterrupts(void); + +/* +** Create extra virtual processor threads. Generally used with MP systems. +*/ +NSPR_API(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). +*/ +NSPR_API(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. + */ +NSPR_API(void) PR_ProcessExit(PRIntn status); + +/* +** Abort the process in a non-graceful manner. This will cause a core file, +** call to the debugger or other moral equivalent as well as causing the +** entire process to stop. +*/ +NSPR_API(void) PR_Abort(void); + +/* + **************************************************************** + * + * Module initialization: + * + **************************************************************** + */ + +typedef struct PRCallOnceType { + PRIntn initialized; + PRInt32 inProgress; + PRStatus status; +} PRCallOnceType; + +typedef PRStatus (PR_CALLBACK *PRCallOnceFN)(void); + +typedef PRStatus (PR_CALLBACK *PRCallOnceWithArgFN)(void *arg); + +NSPR_API(PRStatus) PR_CallOnce( + PRCallOnceType *once, + PRCallOnceFN func +); + +NSPR_API(PRStatus) PR_CallOnceWithArg( + PRCallOnceType *once, + PRCallOnceWithArgFN func, + void *arg +); + + +PR_END_EXTERN_C + +#endif /* prinit_h___ */ diff --git a/nsprpub/pr/include/prinrval.h b/nsprpub/pr/include/prinrval.h new file mode 100644 index 00000000000..9d9d0189b38 --- /dev/null +++ b/nsprpub/pr/include/prinrval.h @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prinrval.h +** Description: API to interval timing functions of NSPR. +** +** +** NSPR provides interval times that are independent of network time +** of day values. Interval times are (in theory) accurate regardless +** of host processing requirements and also very cheap to acquire. It +** is expected that getting an interval time while in a synchronized +** function (holding one's lock). +**/ + +#if !defined(prinrval_h) +#define prinrval_h + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +typedef PRUint32 PRIntervalTime; + +/*********************************************************************** +** DEFINES: PR_INTERVAL_MIN +** PR_INTERVAL_MAX +** DESCRIPTION: +** These two constants define the range (in ticks / second) of the +** platform dependent type, PRIntervalTime. These constants bound both +** the period and the resolution of a PRIntervalTime. +***********************************************************************/ +#define PR_INTERVAL_MIN 1000UL +#define PR_INTERVAL_MAX 100000UL + +/*********************************************************************** +** DEFINES: PR_INTERVAL_NO_WAIT +** PR_INTERVAL_NO_TIMEOUT +** DESCRIPTION: +** Two reserved constants are defined in the PRIntervalTime namespace. +** They are used to indicate that the process should wait no time (return +** immediately) or wait forever (never time out), respectively. +***********************************************************************/ +#define PR_INTERVAL_NO_WAIT 0UL +#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_IntervalNow +** DESCRIPTION: +** Return the value of NSPR's free running interval timer. That timer +** can be used to establish epochs and determine intervals (be computing +** the difference between two times). +** INPUTS: void +** OUTPUTS: void +** RETURN: PRIntervalTime +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** The units of PRIntervalTime are platform dependent. They are chosen +** such that they are appropriate for the host OS, yet provide sufficient +** resolution and period to be useful to clients. +** MEMORY: N/A +** ALGORITHM: Platform dependent +***********************************************************************/ +NSPR_API(PRIntervalTime) PR_IntervalNow(void); + +/*********************************************************************** +** FUNCTION: PR_TicksPerSecond +** DESCRIPTION: +** Return the number of ticks per second for PR_IntervalNow's clock. +** The value will be in the range [PR_INTERVAL_MIN..PR_INTERVAL_MAX]. +** INPUTS: void +** OUTPUTS: void +** RETURN: PRUint32 +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** None +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRUint32) PR_TicksPerSecond(void); + +/*********************************************************************** +** FUNCTION: PR_SecondsToInterval +** PR_MillisecondsToInterval +** PR_MicrosecondsToInterval +** DESCRIPTION: +** Convert standard clock units to platform dependent intervals. +** INPUTS: PRUint32 +** OUTPUTS: void +** RETURN: PRIntervalTime +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** Conversion may cause overflow, which is not reported. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds); +NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli); +NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro); + +/*********************************************************************** +** FUNCTION: PR_IntervalToSeconds +** PR_IntervalToMilliseconds +** PR_IntervalToMicroseconds +** DESCRIPTION: +** Convert platform dependent intervals to standard clock units. +** INPUTS: PRIntervalTime +** OUTPUTS: void +** RETURN: PRUint32 +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** Conversion may cause overflow, which is not reported. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks); + +PR_END_EXTERN_C + + +#endif /* !defined(prinrval_h) */ + +/* prinrval.h */ diff --git a/nsprpub/pr/include/prio.h b/nsprpub/pr/include/prio.h new file mode 100644 index 00000000000..626d860dc44 --- /dev/null +++ b/nsprpub/pr/include/prio.h @@ -0,0 +1,2030 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: prio.h + * + * Description: PR i/o related stuff, such as file system access, file + * i/o, socket i/o, etc. + */ + +#ifndef prio_h___ +#define prio_h___ + +#include "prlong.h" +#include "prtime.h" +#include "prinrval.h" +#include "prinet.h" + +PR_BEGIN_EXTERN_C + +/* Typedefs */ +typedef struct PRDir PRDir; +typedef struct PRDirEntry PRDirEntry; +#ifdef MOZ_UNICODE +typedef struct PRDirUTF16 PRDirUTF16; +typedef struct PRDirEntryUTF16 PRDirEntryUTF16; +#endif /* MOZ_UNICODE */ +typedef struct PRFileDesc PRFileDesc; +typedef struct PRFileInfo PRFileInfo; +typedef struct PRFileInfo64 PRFileInfo64; +typedef union PRNetAddr PRNetAddr; +typedef struct PRIOMethods PRIOMethods; +typedef struct PRPollDesc PRPollDesc; +typedef struct PRFilePrivate PRFilePrivate; +typedef struct PRSendFileData PRSendFileData; + +/* +*************************************************************************** +** The file descriptor. +** This is the primary structure to represent any active open socket, +** whether it be a normal file or a network connection. Such objects +** are stackable (or layerable). Each layer may have its own set of +** method pointers and context private to that layer. All each layer +** knows about its neighbors is how to get to their method table. +*************************************************************************** +*/ + +typedef PRIntn PRDescIdentity; /* see: Layering file descriptors */ + +struct PRFileDesc { + const PRIOMethods *methods; /* the I/O methods table */ + PRFilePrivate *secret; /* layer dependent data */ + PRFileDesc *lower, *higher; /* pointers to adjacent layers */ + void (PR_CALLBACK *dtor)(PRFileDesc *fd); + /* A destructor function for layer */ + PRDescIdentity identity; /* Identity of this particular layer */ +}; + +/* +*************************************************************************** +** PRTransmitFileFlags +** +** Flags for PR_TransmitFile. Pass PR_TRANSMITFILE_CLOSE_SOCKET to +** PR_TransmitFile if the connection should be closed after the file +** is transmitted. +*************************************************************************** +*/ +typedef enum PRTransmitFileFlags { + PR_TRANSMITFILE_KEEP_OPEN = 0, /* socket is left open after file + * is transmitted. */ + PR_TRANSMITFILE_CLOSE_SOCKET = 1 /* socket is closed after file + * is transmitted. */ +} PRTransmitFileFlags; + +/* +************************************************************************** +** Macros for PRNetAddr +** +** Address families: PR_AF_INET, PR_AF_INET6, PR_AF_LOCAL +** IP addresses: PR_INADDR_ANY, PR_INADDR_LOOPBACK, PR_INADDR_BROADCAST +************************************************************************** +*/ + +#ifdef WIN32 + +#define PR_AF_INET 2 +#define PR_AF_LOCAL 1 +#define PR_INADDR_ANY (unsigned long)0x00000000 +#define PR_INADDR_LOOPBACK 0x7f000001 +#define PR_INADDR_BROADCAST (unsigned long)0xffffffff + +#else /* WIN32 */ + +#define PR_AF_INET AF_INET +#define PR_AF_LOCAL AF_UNIX +#define PR_INADDR_ANY INADDR_ANY +#define PR_INADDR_LOOPBACK INADDR_LOOPBACK +#define PR_INADDR_BROADCAST INADDR_BROADCAST + +#endif /* WIN32 */ + +/* +** Define PR_AF_INET6 in prcpucfg.h with the same +** value as AF_INET6 on platforms with IPv6 support. +** Otherwise define it here. +*/ +#ifndef PR_AF_INET6 +#define PR_AF_INET6 100 +#endif + +#ifndef PR_AF_UNSPEC +#define PR_AF_UNSPEC 0 +#endif + +/* +************************************************************************** +** A network address +** +** Only Internet Protocol (IPv4 and IPv6) addresses are supported. +** The address family must always represent IPv4 (AF_INET, probably == 2) +** or IPv6 (AF_INET6). +************************************************************************** +*************************************************************************/ + +struct PRIPv6Addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + PRUint32 _S6_u32[4]; + PRUint64 _S6_u64[2]; + } _S6_un; +}; +#define pr_s6_addr _S6_un._S6_u8 +#define pr_s6_addr16 _S6_un._S6_u16 +#define pr_s6_addr32 _S6_un._S6_u32 +#define pr_s6_addr64 _S6_un._S6_u64 + +typedef struct PRIPv6Addr PRIPv6Addr; + +union PRNetAddr { + struct { + PRUint16 family; /* address family (0x00ff maskable) */ +#ifdef XP_BEOS + char data[10]; /* Be has a smaller structure */ +#else + char data[14]; /* raw address data */ +#endif + } raw; + struct { + PRUint16 family; /* address family (AF_INET) */ + PRUint16 port; /* port number */ + PRUint32 ip; /* The actual 32 bits of address */ +#ifdef XP_BEOS + char pad[4]; /* Be has a smaller structure */ +#else + char pad[8]; +#endif + } inet; + struct { + PRUint16 family; /* address family (AF_INET6) */ + PRUint16 port; /* port number */ + PRUint32 flowinfo; /* routing information */ + PRIPv6Addr ip; /* the actual 128 bits of address */ + PRUint32 scope_id; /* set of interfaces for a scope */ + } ipv6; +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + struct { /* Unix domain socket address */ + PRUint16 family; /* address family (AF_UNIX) */ +#ifdef XP_OS2 + char path[108]; /* null-terminated pathname */ + /* bind fails if size is not 108. */ +#else + char path[104]; /* null-terminated pathname */ +#endif + } local; +#endif +}; + +/* +*************************************************************************** +** PRSockOption +** +** The file descriptors can have predefined options set after they file +** descriptor is created to change their behavior. Only the options in +** the following enumeration are supported. +*************************************************************************** +*/ +typedef enum PRSockOption +{ + PR_SockOpt_Nonblocking, /* nonblocking io */ + PR_SockOpt_Linger, /* linger on close if data present */ + PR_SockOpt_Reuseaddr, /* allow local address reuse */ + PR_SockOpt_Keepalive, /* keep connections alive */ + PR_SockOpt_RecvBufferSize, /* send buffer size */ + PR_SockOpt_SendBufferSize, /* receive buffer size */ + + PR_SockOpt_IpTimeToLive, /* time to live */ + PR_SockOpt_IpTypeOfService, /* type of service and precedence */ + + PR_SockOpt_AddMember, /* add an IP group membership */ + PR_SockOpt_DropMember, /* drop an IP group membership */ + PR_SockOpt_McastInterface, /* multicast interface address */ + PR_SockOpt_McastTimeToLive, /* multicast timetolive */ + PR_SockOpt_McastLoopback, /* multicast loopback */ + + PR_SockOpt_NoDelay, /* don't delay send to coalesce packets */ + PR_SockOpt_MaxSegment, /* maximum segment size */ + PR_SockOpt_Broadcast, /* enable broadcast */ + PR_SockOpt_Last +} PRSockOption; + +typedef struct PRLinger { + PRBool polarity; /* Polarity of the option's setting */ + PRIntervalTime linger; /* Time to linger before closing */ +} PRLinger; + +typedef struct PRMcastRequest { + PRNetAddr mcaddr; /* IP multicast address of group */ + PRNetAddr ifaddr; /* local IP address of interface */ +} PRMcastRequest; + +typedef struct PRSocketOptionData +{ + PRSockOption option; + union + { + PRUintn ip_ttl; /* IP time to live */ + PRUintn mcast_ttl; /* IP multicast time to live */ + PRUintn tos; /* IP type of service and precedence */ + PRBool non_blocking; /* Non-blocking (network) I/O */ + PRBool reuse_addr; /* Allow local address reuse */ + PRBool keep_alive; /* Keep connections alive */ + PRBool mcast_loopback; /* IP multicast loopback */ + PRBool no_delay; /* Don't delay send to coalesce packets */ + PRBool broadcast; /* Enable broadcast */ + PRSize max_segment; /* Maximum segment size */ + PRSize recv_buffer_size; /* Receive buffer size */ + PRSize send_buffer_size; /* Send buffer size */ + PRLinger linger; /* Time to linger on close if data present */ + PRMcastRequest add_member; /* add an IP group membership */ + PRMcastRequest drop_member; /* Drop an IP group membership */ + PRNetAddr mcast_if; /* multicast interface address */ + } value; +} PRSocketOptionData; + +/* +*************************************************************************** +** PRIOVec +** +** The I/O vector is used by the write vector method to describe the areas +** that are affected by the ouput operation. +*************************************************************************** +*/ +typedef struct PRIOVec { + char *iov_base; + int iov_len; +} PRIOVec; + +/* +*************************************************************************** +** Discover what type of socket is being described by the file descriptor. +*************************************************************************** +*/ +typedef enum PRDescType +{ + PR_DESC_FILE = 1, + PR_DESC_SOCKET_TCP = 2, + PR_DESC_SOCKET_UDP = 3, + PR_DESC_LAYERED = 4, + PR_DESC_PIPE = 5 +} PRDescType; + +typedef enum PRSeekWhence { + PR_SEEK_SET = 0, + PR_SEEK_CUR = 1, + PR_SEEK_END = 2 +} PRSeekWhence; + +NSPR_API(PRDescType) PR_GetDescType(PRFileDesc *file); + +/* +*************************************************************************** +** PRIOMethods +** +** The I/O methods table provides procedural access to the functions of +** the file descriptor. It is the responsibility of a layer implementor +** to provide suitable functions at every entry point. If a layer provides +** no functionality, it should call the next lower(higher) function of the +** same name (e.g., return fd->lower->method->close(fd->lower)); +** +** Not all functions are implemented for all types of files. In cases where +** that is true, the function will return a error indication with an error +** code of PR_INVALID_METHOD_ERROR. +*************************************************************************** +*/ + +typedef PRStatus (PR_CALLBACK *PRCloseFN)(PRFileDesc *fd); +typedef PRInt32 (PR_CALLBACK *PRReadFN)(PRFileDesc *fd, void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRWriteFN)(PRFileDesc *fd, const void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRAvailableFN)(PRFileDesc *fd); +typedef PRInt64 (PR_CALLBACK *PRAvailable64FN)(PRFileDesc *fd); +typedef PRStatus (PR_CALLBACK *PRFsyncFN)(PRFileDesc *fd); +typedef PROffset32 (PR_CALLBACK *PRSeekFN)(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how); +typedef PROffset64 (PR_CALLBACK *PRSeek64FN)(PRFileDesc *fd, PROffset64 offset, PRSeekWhence how); +typedef PRStatus (PR_CALLBACK *PRFileInfoFN)(PRFileDesc *fd, PRFileInfo *info); +typedef PRStatus (PR_CALLBACK *PRFileInfo64FN)(PRFileDesc *fd, PRFileInfo64 *info); +typedef PRInt32 (PR_CALLBACK *PRWritevFN)( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRConnectFN)( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout); +typedef PRFileDesc* (PR_CALLBACK *PRAcceptFN) ( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRBindFN)(PRFileDesc *fd, const PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRListenFN)(PRFileDesc *fd, PRIntn backlog); +typedef PRStatus (PR_CALLBACK *PRShutdownFN)(PRFileDesc *fd, PRIntn how); +typedef PRInt32 (PR_CALLBACK *PRRecvFN)( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRSendFN) ( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRRecvfromFN)( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRSendtoFN)( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout); +typedef PRInt16 (PR_CALLBACK *PRPollFN)( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); +typedef PRInt32 (PR_CALLBACK *PRAcceptreadFN)( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime t); +typedef PRInt32 (PR_CALLBACK *PRTransmitfileFN)( + PRFileDesc *sd, PRFileDesc *fd, const void *headers, + PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime t); +typedef PRStatus (PR_CALLBACK *PRGetsocknameFN)(PRFileDesc *fd, PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRGetpeernameFN)(PRFileDesc *fd, PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRGetsocketoptionFN)( + PRFileDesc *fd, PRSocketOptionData *data); +typedef PRStatus (PR_CALLBACK *PRSetsocketoptionFN)( + PRFileDesc *fd, const PRSocketOptionData *data); +typedef PRInt32 (PR_CALLBACK *PRSendfileFN)( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRConnectcontinueFN)( + PRFileDesc *fd, PRInt16 out_flags); +typedef PRIntn (PR_CALLBACK *PRReservedFN)(PRFileDesc *fd); + +struct PRIOMethods { + PRDescType file_type; /* Type of file represented (tos) */ + PRCloseFN close; /* close file and destroy descriptor */ + PRReadFN read; /* read up to specified bytes into buffer */ + PRWriteFN write; /* write specified bytes from buffer */ + PRAvailableFN available; /* determine number of bytes available */ + PRAvailable64FN available64; /* ditto, 64 bit */ + PRFsyncFN fsync; /* flush all buffers to permanent store */ + PRSeekFN seek; /* position the file to the desired place */ + PRSeek64FN seek64; /* ditto, 64 bit */ + PRFileInfoFN fileInfo; /* Get information about an open file */ + PRFileInfo64FN fileInfo64; /* ditto, 64 bit */ + PRWritevFN writev; /* Write segments as described by iovector */ + PRConnectFN connect; /* Connect to the specified (net) address */ + PRAcceptFN accept; /* Accept a connection for a (net) peer */ + PRBindFN bind; /* Associate a (net) address with the fd */ + PRListenFN listen; /* Prepare to listen for (net) connections */ + PRShutdownFN shutdown; /* Shutdown a (net) connection */ + PRRecvFN recv; /* Solicit up the the specified bytes */ + PRSendFN send; /* Send all the bytes specified */ + PRRecvfromFN recvfrom; /* Solicit (net) bytes and report source */ + PRSendtoFN sendto; /* Send bytes to (net) address specified */ + PRPollFN poll; /* Test the fd to see if it is ready */ + PRAcceptreadFN acceptread; /* Accept and read on a new (net) fd */ + PRTransmitfileFN transmitfile; /* Transmit at entire file */ + PRGetsocknameFN getsockname; /* Get (net) address associated with fd */ + PRGetpeernameFN getpeername; /* Get peer's (net) address */ + PRReservedFN reserved_fn_6; /* reserved for future use */ + PRReservedFN reserved_fn_5; /* reserved for future use */ + PRGetsocketoptionFN getsocketoption; + /* Get current setting of specified option */ + PRSetsocketoptionFN setsocketoption; + /* Set value of specified option */ + PRSendfileFN sendfile; /* Send a (partial) file with header/trailer*/ + PRConnectcontinueFN connectcontinue; + /* Continue a nonblocking connect */ + PRReservedFN reserved_fn_3; /* reserved for future use */ + PRReservedFN reserved_fn_2; /* reserved for future use */ + PRReservedFN reserved_fn_1; /* reserved for future use */ + PRReservedFN reserved_fn_0; /* reserved for future use */ +}; + +/* + ************************************************************************** + * FUNCTION: PR_GetSpecialFD + * DESCRIPTION: Get the file descriptor that represents the standard input, + * output, or error stream. + * INPUTS: + * PRSpecialFD id + * A value indicating the type of stream desired: + * PR_StandardInput: standard input + * PR_StandardOuput: standard output + * PR_StandardError: standard error + * OUTPUTS: none + * RETURNS: PRFileDesc * + * If the argument is valid, PR_GetSpecialFD returns a file descriptor + * that represents the corresponding standard I/O stream. Otherwise, + * PR_GetSpecialFD returns NULL and sets error PR_INVALID_ARGUMENT_ERROR. + ************************************************************************** + */ + +typedef enum PRSpecialFD +{ + PR_StandardInput, /* standard input */ + PR_StandardOutput, /* standard output */ + PR_StandardError /* standard error */ +} PRSpecialFD; + +NSPR_API(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD id); + +#define PR_STDIN PR_GetSpecialFD(PR_StandardInput) +#define PR_STDOUT PR_GetSpecialFD(PR_StandardOutput) +#define PR_STDERR PR_GetSpecialFD(PR_StandardError) + +/* + ************************************************************************** + * Layering file descriptors + * + * File descriptors may be layered. Each layer has it's own identity. + * Identities are allocated by the runtime and are to be associated + * (by the layer implementor) with all layers that are of that type. + * It is then possible to scan the chain of layers and find a layer + * that one recongizes and therefore predict that it will implement + * a desired protocol. + * + * There are three well-known identities: + * PR_INVALID_IO_LAYER => an invalid layer identity, for error return + * PR_TOP_IO_LAYER => the identity of the top of the stack + * PR_NSPR_IO_LAYER => the identity used by NSPR proper + * PR_TOP_IO_LAYER may be used as a shorthand for identifying the topmost + * layer of an existing stack. Ie., the following two constructs are + * equivalent. + * + * rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, my_layer); + * rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), my_layer) + * + * A string may be associated with the creation of the identity. It + * will be copied by the runtime. If queried the runtime will return + * a reference to that copied string (not yet another copy). There + * is no facility for deleting an identity. + ************************************************************************** + */ + +#define PR_IO_LAYER_HEAD (PRDescIdentity)-3 +#define PR_INVALID_IO_LAYER (PRDescIdentity)-1 +#define PR_TOP_IO_LAYER (PRDescIdentity)-2 +#define PR_NSPR_IO_LAYER (PRDescIdentity)0 + +NSPR_API(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name); +NSPR_API(const char*) PR_GetNameForIdentity(PRDescIdentity ident); +NSPR_API(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd); +NSPR_API(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd_stack, PRDescIdentity id); + +/* + ************************************************************************** + * PR_GetDefaultIOMethods: Accessing the default methods table. + * You may get a pointer to the default methods table by calling this function. + * You may then select any elements from that table with which to build your + * layer's methods table. You may NOT modify the table directly. + ************************************************************************** + */ +NSPR_API(const PRIOMethods *) PR_GetDefaultIOMethods(void); + +/* + ************************************************************************** + * Creating a layer + * + * A new layer may be allocated by calling PR_CreateIOLayerStub(). The + * file descriptor returned will contain the pointer to the methods table + * provided. The runtime will not modify the table nor test its correctness. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_CreateIOLayerStub( + PRDescIdentity ident, const PRIOMethods *methods); + +/* + ************************************************************************** + * Creating a layer + * + * A new stack may be created by calling PR_CreateIOLayer(). The + * file descriptor returned will point to the top of the stack, which has + * the layer 'fd' as the topmost layer. + * + * NOTE: This function creates a new style stack, which has a fixed, dummy + * header. The old style stack, created by a call to PR_PushIOLayer, + * results in modifying contents of the top layer of the stack, when + * pushing and popping layers of the stack. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_CreateIOLayer(PRFileDesc* fd); + +/* + ************************************************************************** + * Pushing a layer + * + * A file descriptor (perhaps allocated using PR_CreateIOLayerStub()) may + * be pushed into an existing stack of file descriptors at any point the + * caller deems appropriate. The new layer will be inserted into the stack + * just above the layer with the indicated identity. + * + * Note: Even if the identity parameter indicates the top-most layer of + * the stack, the value of the file descriptor describing the original + * stack will not change. + ************************************************************************** + */ +NSPR_API(PRStatus) PR_PushIOLayer( + PRFileDesc *fd_stack, PRDescIdentity id, PRFileDesc *layer); + +/* + ************************************************************************** + * Popping a layer + * + * A layer may be popped from a stack by indicating the identity of the + * layer to be removed. If found, a pointer to the removed object will + * be returned to the caller. The object then becomes the responsibility + * of the caller. + * + * Note: Even if the identity indicates the top layer of the stack, the + * reference returned will not be the file descriptor for the stack and + * that file descriptor will remain valid. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_PopIOLayer(PRFileDesc *fd_stack, PRDescIdentity id); + +/* + ************************************************************************** + * FUNCTION: PR_Open + * DESCRIPTION: Open a file for reading, writing, or both. + * INPUTS: + * const char *name + * The path name of the file to be opened + * PRIntn flags + * The file status flags. + * It is a bitwise OR of the following bit flags (only one of + * the first three flags below may be used): + * PR_RDONLY Open for reading only. + * PR_WRONLY Open for writing only. + * PR_RDWR Open for reading and writing. + * PR_CREATE_FILE If the file does not exist, the file is created + * If the file exists, this flag has no effect. + * PR_SYNC If set, each write will wait for both the file data + * and file status to be physically updated. + * PR_APPEND The file pointer is set to the end of + * the file prior to each write. + * PR_TRUNCATE If the file exists, its length is truncated to 0. + * PR_EXCL With PR_CREATE_FILE, if the file does not exist, + * the file is created. If the file already + * exists, no action and NULL is returned + * + * PRIntn mode + * The access permission bits of the file mode, if the file is + * created when PR_CREATE_FILE is on. + * OUTPUTS: None + * RETURNS: PRFileDesc * + * If the file is successfully opened, + * returns a pointer to the PRFileDesc + * created for the newly opened file. + * Returns a NULL pointer if the open + * failed. + * SIDE EFFECTS: + * RESTRICTIONS: + * MEMORY: + * The return value, if not NULL, points to a dynamically allocated + * PRFileDesc object. + * ALGORITHM: + ************************************************************************** + */ + +/* Open flags */ +#define PR_RDONLY 0x01 +#define PR_WRONLY 0x02 +#define PR_RDWR 0x04 +#define PR_CREATE_FILE 0x08 +#define PR_APPEND 0x10 +#define PR_TRUNCATE 0x20 +#define PR_SYNC 0x40 +#define PR_EXCL 0x80 + +/* +** File modes .... +** +** CAVEAT: 'mode' is currently only applicable on UNIX platforms. +** The 'mode' argument may be ignored by PR_Open on other platforms. +** +** 00400 Read by owner. +** 00200 Write by owner. +** 00100 Execute (search if a directory) by owner. +** 00040 Read by group. +** 00020 Write by group. +** 00010 Execute by group. +** 00004 Read by others. +** 00002 Write by others +** 00001 Execute by others. +** +*/ + +NSPR_API(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode); + +/* + ************************************************************************** + * FUNCTION: PR_OpenFile + * DESCRIPTION: + * Open a file for reading, writing, or both. + * PR_OpenFile has the same prototype as PR_Open but implements + * the specified file mode where possible. + ************************************************************************** + */ + +/* File mode bits */ +#define PR_IRWXU 00700 /* read, write, execute/search by owner */ +#define PR_IRUSR 00400 /* read permission, owner */ +#define PR_IWUSR 00200 /* write permission, owner */ +#define PR_IXUSR 00100 /* execute/search permission, owner */ +#define PR_IRWXG 00070 /* read, write, execute/search by group */ +#define PR_IRGRP 00040 /* read permission, group */ +#define PR_IWGRP 00020 /* write permission, group */ +#define PR_IXGRP 00010 /* execute/search permission, group */ +#define PR_IRWXO 00007 /* read, write, execute/search by others */ +#define PR_IROTH 00004 /* read permission, others */ +#define PR_IWOTH 00002 /* write permission, others */ +#define PR_IXOTH 00001 /* execute/search permission, others */ + +NSPR_API(PRFileDesc*) PR_OpenFile( + const char *name, PRIntn flags, PRIntn mode); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRFileDesc*) PR_OpenFileUTF16( + const PRUnichar *name, PRIntn flags, PRIntn mode); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************** + * FUNCTION: PR_Close + * DESCRIPTION: + * Close a file or socket. + * INPUTS: + * PRFileDesc *fd + * a pointer to a PRFileDesc. + * OUTPUTS: + * None. + * RETURN: + * PRStatus + * SIDE EFFECTS: + * RESTRICTIONS: + * None. + * MEMORY: + * The dynamic memory pointed to by the argument fd is freed. + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Close(PRFileDesc *fd); + +/* + ************************************************************************** + * FUNCTION: PR_Read + * DESCRIPTION: + * Read bytes from a file or socket. + * The operation will block until either an end of stream indication is + * encountered, some positive number of bytes are transferred, or there + * is an error. No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * pointer to the PRFileDesc object for the file or socket + * void *buf + * pointer to a buffer to hold the data read in. + * PRInt32 amount + * the size of 'buf' (in bytes) + * OUTPUTS: + * RETURN: + * PRInt32 + * a positive number indicates the number of bytes actually read in. + * 0 means end of file is reached or the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + * SIDE EFFECTS: + * data is written into the buffer pointed to by 'buf'. + * RESTRICTIONS: + * None. + * MEMORY: + * N/A + * ALGORITHM: + * N/A + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount); + +/* + *************************************************************************** + * FUNCTION: PR_Write + * DESCRIPTION: + * Write a specified number of bytes to a file or socket. The thread + * invoking this function blocks until all the data is written. + * INPUTS: + * PRFileDesc *fd + * pointer to a PRFileDesc object that refers to a file or socket + * const void *buf + * pointer to the buffer holding the data + * PRInt32 amount + * amount of data in bytes to be written from the buffer + * OUTPUTS: + * None. + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully written. + * A -1 is an indication that the operation failed. The reason + * for the failure is obtained by calling PR_GetError(). + *************************************************************************** + */ + +NSPR_API(PRInt32) PR_Write(PRFileDesc *fd,const void *buf,PRInt32 amount); + +/* + *************************************************************************** + * FUNCTION: PR_Writev + * DESCRIPTION: + * Write data to a socket. The data is organized in a PRIOVec array. The + * operation will block until all the data is written or the operation + * fails. + * INPUTS: + * PRFileDesc *fd + * Pointer that points to a PRFileDesc object for a socket. + * const PRIOVec *iov + * An array of PRIOVec. PRIOVec is a struct with the following + * two fields: + * char *iov_base; + * int iov_len; + * PRInt32 iov_size + * Number of elements in the iov array. The value of this + * argument must not be greater than PR_MAX_IOVECTOR_SIZE. + * If it is, the method will fail (PR_BUFFER_OVERFLOW_ERROR). + * PRIntervalTime timeout + * Time limit for completion of the entire write operation. + * OUTPUTS: + * None + * RETURN: + * A positive number indicates the number of bytes successfully written. + * A -1 is an indication that the operation failed. The reason + * for the failure is obtained by calling PR_GetError(). + *************************************************************************** + */ + +#define PR_MAX_IOVECTOR_SIZE 16 /* 'iov_size' must be <= */ + +NSPR_API(PRInt32) PR_Writev( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout); + +/* + *************************************************************************** + * FUNCTION: PR_Delete + * DESCRIPTION: + * Delete a file from the filesystem. The operation may fail if the + * file is open. + * INPUTS: + * const char *name + * Path name of the file to be deleted. + * OUTPUTS: + * None. + * RETURN: PRStatus + * The function returns PR_SUCCESS if the file is successfully + * deleted, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_Delete(const char *name); + +/**************************************************************************/ + +typedef enum PRFileType +{ + PR_FILE_FILE = 1, + PR_FILE_DIRECTORY = 2, + PR_FILE_OTHER = 3 +} PRFileType; + +struct PRFileInfo { + PRFileType type; /* Type of file */ + PROffset32 size; /* Size, in bytes, of file's contents */ + PRTime creationTime; /* Creation time per definition of PRTime */ + PRTime modifyTime; /* Last modification time per definition of PRTime */ +}; + +struct PRFileInfo64 { + PRFileType type; /* Type of file */ + PROffset64 size; /* Size, in bytes, of file's contents */ + PRTime creationTime; /* Creation time per definition of PRTime */ + PRTime modifyTime; /* Last modification time per definition of PRTime */ +}; + +/**************************************************************************** + * FUNCTION: PR_GetFileInfo, PR_GetFileInfo64 + * DESCRIPTION: + * Get the information about the file with the given path name. This is + * applicable only to NSFileDesc describing 'file' types (see + * INPUTS: + * const char *fn + * path name of the file + * OUTPUTS: + * PRFileInfo *info + * Information about the given file is written into the file + * information object pointer to by 'info'. + * RETURN: PRStatus + * PR_GetFileInfo returns PR_SUCCESS if file information is successfully + * obtained, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info); +NSPR_API(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************** + * FUNCTION: PR_GetOpenFileInfo, PR_GetOpenFileInfo64 + * DESCRIPTION: + * Get information about an open file referred to by the + * given PRFileDesc object. + * INPUTS: + * const PRFileDesc *fd + * A reference to a valid, open file. + * OUTPUTS: + * Same as PR_GetFileInfo, PR_GetFileInfo64 + * RETURN: PRStatus + * PR_GetFileInfo returns PR_SUCCESS if file information is successfully + * obtained, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info); +NSPR_API(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info); + +/* + ************************************************************************** + * FUNCTION: PR_Rename + * DESCRIPTION: + * Rename a file from the old name 'from' to the new name 'to'. + * INPUTS: + * const char *from + * The old name of the file to be renamed. + * const char *to + * The new name of the file. + * OUTPUTS: + * None. + * RETURN: PRStatus + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Rename(const char *from, const char *to); + +/* + ************************************************************************* + * FUNCTION: PR_Access + * DESCRIPTION: + * Determine accessibility of a file. + * INPUTS: + * const char *name + * path name of the file + * PRAccessHow how + * specifies which access permission to check for. + * It can be one of the following values: + * PR_ACCESS_READ_OK Test for read permission + * PR_ACCESS_WRITE_OK Test for write permission + * PR_ACCESS_EXISTS Check existence of file + * OUTPUTS: + * None. + * RETURN: PRStatus + * PR_SUCCESS is returned if the requested access is permitted. + * Otherwise, PR_FAILURE is returned. Additional information + * regarding the reason for the failure may be retrieved from + * PR_GetError(). + ************************************************************************* + */ + +typedef enum PRAccessHow { + PR_ACCESS_EXISTS = 1, + PR_ACCESS_WRITE_OK = 2, + PR_ACCESS_READ_OK = 3 +} PRAccessHow; + +NSPR_API(PRStatus) PR_Access(const char *name, PRAccessHow how); + +/* + ************************************************************************* + * FUNCTION: PR_Seek, PR_Seek64 + * DESCRIPTION: + * Moves read-write file offset + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object. + * PROffset32, PROffset64 offset + * Specifies a value, in bytes, that is used in conjunction + * with the 'whence' parameter to set the file pointer. A + * negative value causes seeking in the reverse direction. + * PRSeekWhence whence + * Specifies how to interpret the 'offset' parameter in setting + * the file pointer associated with the 'fd' parameter. + * Values for the 'whence' parameter are: + * PR_SEEK_SET Sets the file pointer to the value of the + * 'offset' parameter + * PR_SEEK_CUR Sets the file pointer to its current location + * plus the value of the offset parameter. + * PR_SEEK_END Sets the file pointer to the size of the + * file plus the value of the offset parameter. + * OUTPUTS: + * None. + * RETURN: PROffset32, PROffset64 + * Upon successful completion, the resulting pointer location, + * measured in bytes from the beginning of the file, is returned. + * If the PR_Seek() function fails, the file offset remains + * unchanged, and the returned value is -1. The error code can + * then be retrieved via PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PROffset32) PR_Seek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence); +NSPR_API(PROffset64) PR_Seek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence); + +/* + ************************************************************************ + * FUNCTION: PR_Available + * DESCRIPTION: + * Determine the amount of data in bytes available for reading + * in the given file or socket. + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object that refers to a file or + * socket. + * OUTPUTS: + * None + * RETURN: PRInt32, PRInt64 + * Upon successful completion, PR_Available returns the number of + * bytes beyond the current read pointer that is available for + * reading. Otherwise, it returns a -1 and the reason for the + * failure can be retrieved via PR_GetError(). + ************************************************************************ + */ + +NSPR_API(PRInt32) PR_Available(PRFileDesc *fd); +NSPR_API(PRInt64) PR_Available64(PRFileDesc *fd); + +/* + ************************************************************************ + * FUNCTION: PR_Sync + * DESCRIPTION: + * Sync any buffered data for a fd to its backing device (disk). + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object that refers to a file or + * socket + * OUTPUTS: + * None + * RETURN: PRStatus + * PR_SUCCESS is returned if the requested access is permitted. + * Otherwise, PR_FAILURE is returned. + ************************************************************************ + */ + +NSPR_API(PRStatus) PR_Sync(PRFileDesc *fd); + +/************************************************************************/ + +struct PRDirEntry { + const char *name; /* name of entry, relative to directory name */ +}; + +#ifdef MOZ_UNICODE +struct PRDirEntryUTF16 { + const PRUnichar *name; /* name of entry in UTF16, relative to + * directory name */ +}; +#endif /* MOZ_UNICODE */ + +#if !defined(NO_NSPR_10_SUPPORT) +#define PR_DirName(dirEntry) (dirEntry->name) +#endif + +/* + ************************************************************************* + * FUNCTION: PR_OpenDir + * DESCRIPTION: + * Open the directory by the given name + * INPUTS: + * const char *name + * path name of the directory to be opened + * OUTPUTS: + * None + * RETURN: PRDir * + * If the directory is sucessfully opened, a PRDir object is + * dynamically allocated and a pointer to it is returned. + * If the directory cannot be opened, a NULL pointer is returned. + * MEMORY: + * Upon successful completion, the return value points to + * dynamically allocated memory. + ************************************************************************* + */ + +NSPR_API(PRDir*) PR_OpenDir(const char *name); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_ReadDir + * DESCRIPTION: + * INPUTS: + * PRDir *dir + * pointer to a PRDir object that designates an open directory + * PRDirFlags flags + * PR_SKIP_NONE Do not skip any files + * PR_SKIP_DOT Skip the directory entry "." that + * represents the current directory + * PR_SKIP_DOT_DOT Skip the directory entry ".." that + * represents the parent directory. + * PR_SKIP_BOTH Skip both '.' and '..' + * PR_SKIP_HIDDEN Skip hidden files + * OUTPUTS: + * RETURN: PRDirEntry* + * Returns a pointer to the next entry in the directory. Returns + * a NULL pointer upon reaching the end of the directory or when an + * error occurs. The actual reason can be retrieved via PR_GetError(). + ************************************************************************* + */ + +typedef enum PRDirFlags { + PR_SKIP_NONE = 0x0, + PR_SKIP_DOT = 0x1, + PR_SKIP_DOT_DOT = 0x2, + PR_SKIP_BOTH = 0x3, + PR_SKIP_HIDDEN = 0x4 +} PRDirFlags; + +NSPR_API(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_CloseDir + * DESCRIPTION: + * Close the specified directory. + * INPUTS: + * PRDir *dir + * The directory to be closed. + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_CloseDir(PRDir *dir); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_MkDir + * DESCRIPTION: + * Create a new directory with the given name and access mode. + * INPUTS: + * const char *name + * The name of the directory to be created. All the path components + * up to but not including the leaf component must already exist. + * PRIntn mode + * See 'mode' definiton in PR_Open(). + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_MkDir(const char *name, PRIntn mode); + +/* + ************************************************************************* + * FUNCTION: PR_MakeDir + * DESCRIPTION: + * Create a new directory with the given name and access mode. + * PR_MakeDir has the same prototype as PR_MkDir but implements + * the specified access mode where possible. + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_MakeDir(const char *name, PRIntn mode); + +/* + ************************************************************************* + * FUNCTION: PR_RmDir + * DESCRIPTION: + * Remove a directory by the given name. + * INPUTS: + * const char *name + * The name of the directory to be removed. All the path components + * must already exist. Only the leaf component will be removed. + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_RmDir(const char *name); + +/* + ************************************************************************* + * FUNCTION: PR_NewUDPSocket + * DESCRIPTION: + * Create a new UDP socket. + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewUDPSocket returns a pointer + * to the PRFileDesc created for the newly opened UDP socket. + * Returns a NULL pointer if the creation of a new UDP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_NewUDPSocket(void); + +/* + ************************************************************************* + * FUNCTION: PR_NewTCPSocket + * DESCRIPTION: + * Create a new TCP socket. + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewTCPSocket returns a pointer + * to the PRFileDesc created for the newly opened TCP socket. + * Returns a NULL pointer if the creation of a new TCP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_NewTCPSocket(void); + +/* + ************************************************************************* + * FUNCTION: PR_OpenUDPSocket + * DESCRIPTION: + * Create a new UDP socket of the specified address family. + * INPUTS: + * PRIntn af + * Address family + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_OpenUDPSocket returns a pointer + * to the PRFileDesc created for the newly opened UDP socket. + * Returns a NULL pointer if the creation of a new UDP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_OpenUDPSocket(PRIntn af); + +/* + ************************************************************************* + * FUNCTION: PR_OpenTCPSocket + * DESCRIPTION: + * Create a new TCP socket of the specified address family. + * INPUTS: + * PRIntn af + * Address family + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewTCPSocket returns a pointer + * to the PRFileDesc created for the newly opened TCP socket. + * Returns a NULL pointer if the creation of a new TCP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_OpenTCPSocket(PRIntn af); + +/* + ************************************************************************* + * FUNCTION: PR_Connect + * DESCRIPTION: + * Initiate a connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket + * PRNetAddr *addr + * Specifies the address of the socket in its own communication + * space. + * PRIntervalTime timeout + * Time limit for completion of the connect operation. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of connection initiation, PR_Connect + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Connect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_ConnectContinue + * DESCRIPTION: + * Continue a nonblocking connect. After a nonblocking connect + * is initiated with PR_Connect() (which fails with + * PR_IN_PROGRESS_ERROR), one should call PR_Poll() on the socket, + * with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT. When + * PR_Poll() returns, one calls PR_ConnectContinue() on the + * socket to determine whether the nonblocking connect has + * completed or is still in progress. Repeat the PR_Poll(), + * PR_ConnectContinue() sequence until the nonblocking connect + * has completed. + * INPUTS: + * PRFileDesc *fd + * the file descriptor representing a socket + * PRInt16 out_flags + * the out_flags field of the poll descriptor returned by + * PR_Poll() + * RETURN: PRStatus + * If the nonblocking connect has successfully completed, + * PR_ConnectContinue returns PR_SUCCESS. If PR_ConnectContinue() + * returns PR_FAILURE, call PR_GetError(): + * - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in + * progress and has not completed yet. The caller should poll + * on the file descriptor for the in_flags + * PR_POLL_WRITE|PR_POLL_EXCEPT and retry PR_ConnectContinue + * later when PR_Poll() returns. + * - Other errors: the nonblocking connect has failed with this + * error code. + */ + +NSPR_API(PRStatus) PR_ConnectContinue(PRFileDesc *fd, PRInt16 out_flags); + +/* + ************************************************************************* + * THIS FUNCTION IS DEPRECATED. USE PR_ConnectContinue INSTEAD. + * + * FUNCTION: PR_GetConnectStatus + * DESCRIPTION: + * Get the completion status of a nonblocking connect. After + * a nonblocking connect is initiated with PR_Connect() (which + * fails with PR_IN_PROGRESS_ERROR), one should call PR_Poll() + * on the socket, with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT. + * When PR_Poll() returns, one calls PR_GetConnectStatus on the + * PRPollDesc structure to determine whether the nonblocking + * connect has succeeded or failed. + * INPUTS: + * const PRPollDesc *pd + * Pointer to a PRPollDesc whose fd member is the socket, + * and in_flags must contain PR_POLL_WRITE and PR_POLL_EXCEPT. + * PR_Poll() should have been called and set the out_flags. + * RETURN: PRStatus + * If the nonblocking connect has successfully completed, + * PR_GetConnectStatus returns PR_SUCCESS. If PR_GetConnectStatus() + * returns PR_FAILURE, call PR_GetError(): + * - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in + * progress and has not completed yet. + * - Other errors: the nonblocking connect has failed with this + * error code. + */ + +NSPR_API(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd); + +/* + ************************************************************************* + * FUNCTION: PR_Accept + * DESCRIPTION: + * Accept a connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing the rendezvous socket + * on which the caller is willing to accept new connections. + * PRIntervalTime timeout + * Time limit for completion of the accept operation. + * OUTPUTS: + * PRNetAddr *addr + * Returns the address of the connecting entity in its own + * communication space. It may be NULL. + * RETURN: PRFileDesc* + * Upon successful acceptance of a connection, PR_Accept + * returns a valid file descriptor. Otherwise, it returns NULL. + * Further failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_Accept( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_Bind + * DESCRIPTION: + * Bind an address to a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket. + * PRNetAddr *addr + * Specifies the address to which the socket will be bound. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful binding of an address to a socket, PR_Bind + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr); + +/* + ************************************************************************* + * FUNCTION: PR_Listen + * DESCRIPTION: + * Listen for connections on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket that will be + * used to listen for new connections. + * PRIntn backlog + * Specifies the maximum length of the queue of pending connections. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of listen request, PR_Listen + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog); + +/* + ************************************************************************* + * FUNCTION: PR_Shutdown + * DESCRIPTION: + * Shut down part of a full-duplex connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a connected socket. + * PRIntn how + * Specifies the kind of disallowed operations on the socket. + * PR_SHUTDOWN_RCV - Further receives will be disallowed + * PR_SHUTDOWN_SEND - Further sends will be disallowed + * PR_SHUTDOWN_BOTH - Further sends and receives will be disallowed + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of shutdown request, PR_Shutdown + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +typedef enum PRShutdownHow +{ + PR_SHUTDOWN_RCV = 0, /* disallow further receives */ + PR_SHUTDOWN_SEND = 1, /* disallow further sends */ + PR_SHUTDOWN_BOTH = 2 /* disallow further receives and sends */ +} PRShutdownHow; + +NSPR_API(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how); + +/* + ************************************************************************* + * FUNCTION: PR_Recv + * DESCRIPTION: + * Receive a specified number of bytes from a connected socket. + * The operation will block until some positive number of bytes are + * transferred, a time out has occurred, or there is an error. + * No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer to hold the data received. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * must be zero or PR_MSG_PEEK. + * PRIntervalTime timeout + * Time limit for completion of the receive operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * a positive number indicates the number of bytes actually received. + * 0 means the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +#define PR_MSG_PEEK 0x2 + +NSPR_API(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_Send + * DESCRIPTION: + * Send a specified number of bytes from a connected socket. + * The operation will block until all bytes are + * processed, a time out has occurred, or there is an error. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer from where the data is sent. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRIntervalTime timeout + * Time limit for completion of the send operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully processed. + * This number must always equal 'amount'. A -1 is an indication that the + * operation failed. The reason for the failure is obtained by calling + * PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_RecvFrom + * DESCRIPTION: + * Receive up to a specified number of bytes from socket which may + * or may not be connected. + * The operation will block until one or more bytes are + * transferred, a time out has occurred, or there is an error. + * No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer to hold the data received. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRNetAddr *addr + * Specifies the address of the sending peer. It may be NULL. + * PRIntervalTime timeout + * Time limit for completion of the receive operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * a positive number indicates the number of bytes actually received. + * 0 means the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_RecvFrom( + PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_SendTo + * DESCRIPTION: + * Send a specified number of bytes from an unconnected socket. + * The operation will block until all bytes are + * sent, a time out has occurred, or there is an error. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing an unconnected socket. + * void *buf + * pointer to a buffer from where the data is sent. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRNetAddr *addr + * Specifies the address of the peer. +.* PRIntervalTime timeout + * Time limit for completion of the send operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully sent. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_SendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_TransmitFile +** DESCRIPTION: +** Transmitfile sends a complete file (sourceFile) across a socket +** (networkSocket). If headers is non-NULL, the headers will be sent across +** the socket prior to sending the file. +** +** Optionally, the PR_TRANSMITFILE_CLOSE_SOCKET flag may be passed to +** transmitfile. This flag specifies that transmitfile should close the +** socket after sending the data. +** +** INPUTS: +** PRFileDesc *networkSocket +** The socket to send data over +** PRFileDesc *sourceFile +** The file to send +** const void *headers +** A pointer to headers to be sent before sending data +** PRInt32 hlen +** length of header buffers in bytes. +** PRTransmitFileFlags flags +** If the flags indicate that the connection should be closed, +** it will be done immediately after transferring the file, unless +** the operation is unsuccessful. +.* PRIntervalTime timeout + * Time limit for completion of the transmit operation. +** +** RETURNS: +** Returns the number of bytes written or -1 if the operation failed. +** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_ +** SOCKET flag is ignored. The reason for the failure is obtained +** by calling PR_GetError(). +************************************************************************** +*/ + +NSPR_API(PRInt32) PR_TransmitFile( + PRFileDesc *networkSocket, PRFileDesc *sourceFile, + const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, + PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_SendFile +** DESCRIPTION: +** PR_SendFile sends data from a file (sendData->fd) across a socket +** (networkSocket). If specified, a header and/or trailer buffer are sent +** before and after the file, respectively. The file offset, number of bytes +** of file data to send, the header and trailer buffers are specified in the +** sendData argument. +** +** Optionally, if the PR_TRANSMITFILE_CLOSE_SOCKET flag is passed, the +** socket is closed after successfully sending the data. +** +** INPUTS: +** PRFileDesc *networkSocket +** The socket to send data over +** PRSendFileData *sendData +** Contains the FD, file offset and length, header and trailer +** buffer specifications. +** PRTransmitFileFlags flags +** If the flags indicate that the connection should be closed, +** it will be done immediately after transferring the file, unless +** the operation is unsuccessful. +.* PRIntervalTime timeout + * Time limit for completion of the send operation. +** +** RETURNS: +** Returns the number of bytes written or -1 if the operation failed. +** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_ +** SOCKET flag is ignored. The reason for the failure is obtained +** by calling PR_GetError(). +************************************************************************** +*/ + +struct PRSendFileData { + PRFileDesc *fd; /* file to send */ + PRUint32 file_offset; /* file offset */ + PRSize file_nbytes; /* number of bytes of file data to send */ + /* if 0, send data from file_offset to */ + /* end-of-file. */ + const void *header; /* header buffer */ + PRInt32 hlen; /* header len */ + const void *trailer; /* trailer buffer */ + PRInt32 tlen; /* trailer len */ +}; + + +NSPR_API(PRInt32) PR_SendFile( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_AcceptRead +** DESCRIPTION: +** AcceptRead accepts a new connection, returns the newly created +** socket's descriptor and also returns the connecting peer's address. +** AcceptRead, as its name suggests, also receives the first block of data +** sent by the peer. +** +** INPUTS: +** PRFileDesc *listenSock +** A socket descriptor that has been called with the PR_Listen() +** function, also known as the rendezvous socket. +** void *buf +** A pointer to a buffer to receive data sent by the client. This +** buffer must be large enough to receive bytes of data +** and two PRNetAddr structures, plus an extra 32 bytes. See: +** PR_ACCEPT_READ_BUF_OVERHEAD. +** 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 +** from the client. +** PRIntervalTime timeout +** The timeout interval only applies to the read portion of the +** operation. PR_AcceptRead will block indefinitely until the +** connection is accepted; the read will timeout after the timeout +** interval elapses. +** OUTPUTS: +** PRFileDesc **acceptedSock +** The file descriptor for the newly connected socket. This parameter +** 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. 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 +** for the failure is obtained by calling PR_GetError(). +************************************************************************** +**/ +/* define buffer overhead constant. Add this value to the user's +** data length when allocating a buffer to accept data. +** Example: +** #define USER_DATA_SIZE 10 +** char buf[USER_DATA_SIZE + PR_ACCEPT_READ_BUF_OVERHEAD]; +** bytesRead = PR_AcceptRead( s, fd, &a, &p, USER_DATA_SIZE, ...); +*/ +#define PR_ACCEPT_READ_BUF_OVERHEAD (32+(2*sizeof(PRNetAddr))) + +NSPR_API(PRInt32) PR_AcceptRead( + PRFileDesc *listenSock, PRFileDesc **acceptedSock, + PRNetAddr **peerAddr, void *buf, PRInt32 amount, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_NewTCPSocketPair +** DESCRIPTION: +** Create a new TCP socket pair. The returned descriptors can be used +** interchangeably; they are interconnected full-duplex descriptors: data +** written to one can be read from the other and vice-versa. +** +** INPUTS: +** None +** OUTPUTS: +** PRFileDesc *fds[2] +** The file descriptor pair for the newly created TCP sockets. +** RETURN: PRStatus +** Upon successful completion of TCP socket pair, PR_NewTCPSocketPair +** returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further +** failure information can be obtained by calling PR_GetError(). +** XXX can we implement this on windoze and mac? +************************************************************************** +**/ +NSPR_API(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2]); + +/* +************************************************************************* +** FUNCTION: PR_GetSockName +** DESCRIPTION: +** Get socket name. Return the network address for this socket. +** +** INPUTS: +** PRFileDesc *fd +** Points to a PRFileDesc object representing the socket. +** OUTPUTS: +** PRNetAddr *addr +** Returns the address of the socket in its own communication space. +** RETURN: PRStatus +** Upon successful completion, PR_GetSockName returns PR_SUCCESS. +** Otherwise, it returns PR_FAILURE. Further failure information can +** be obtained by calling PR_GetError(). +************************************************************************** +**/ +NSPR_API(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr); + +/* +************************************************************************* +** FUNCTION: PR_GetPeerName +** DESCRIPTION: +** Get name of the connected peer. Return the network address for the +** connected peer socket. +** +** INPUTS: +** PRFileDesc *fd +** Points to a PRFileDesc object representing the connected peer. +** OUTPUTS: +** PRNetAddr *addr +** Returns the address of the connected peer in its own communication +** space. +** RETURN: PRStatus +** Upon successful completion, PR_GetPeerName returns PR_SUCCESS. +** Otherwise, it returns PR_FAILURE. Further failure information can +** be obtained by calling PR_GetError(). +************************************************************************** +**/ +NSPR_API(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr); + +NSPR_API(PRStatus) PR_GetSocketOption( + PRFileDesc *fd, PRSocketOptionData *data); + +NSPR_API(PRStatus) PR_SetSocketOption( + PRFileDesc *fd, const PRSocketOptionData *data); + +/* + ********************************************************************* + * + * File descriptor inheritance + * + ********************************************************************* + */ + +/* + ************************************************************************ + * FUNCTION: PR_SetFDInheritable + * DESCRIPTION: + * Set the inheritance attribute of a file descriptor. + * + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object. + * PRBool inheritable + * If PR_TRUE, the file descriptor fd is set to be inheritable + * by a child process. If PR_FALSE, the file descriptor is set + * to be not inheritable by a child process. + * RETURN: PRStatus + * Upon successful completion, PR_SetFDInheritable returns PR_SUCCESS. + * Otherwise, it returns PR_FAILURE. Further failure information can + * be obtained by calling PR_GetError(). + ************************************************************************* + */ +NSPR_API(PRStatus) PR_SetFDInheritable( + PRFileDesc *fd, + PRBool inheritable); + +/* + ************************************************************************ + * FUNCTION: PR_GetInheritedFD + * DESCRIPTION: + * Get an inherited file descriptor with the specified name. + * + * INPUTS: + * const char *name + * The name of the inherited file descriptor. + * RETURN: PRFileDesc * + * Upon successful completion, PR_GetInheritedFD returns the + * inherited file descriptor with the specified name. Otherwise, + * it returns NULL. Further failure information can be obtained + * by calling PR_GetError(). + ************************************************************************* + */ +NSPR_API(PRFileDesc *) PR_GetInheritedFD(const char *name); + +/* + ********************************************************************* + * + * Memory-mapped files + * + ********************************************************************* + */ + +typedef struct PRFileMap PRFileMap; + +/* + * protection options for read and write accesses of a file mapping + */ +typedef enum PRFileMapProtect { + PR_PROT_READONLY, /* read only */ + PR_PROT_READWRITE, /* readable, and write is shared */ + PR_PROT_WRITECOPY /* readable, and write is private (copy-on-write) */ +} PRFileMapProtect; + +NSPR_API(PRFileMap *) PR_CreateFileMap( + PRFileDesc *fd, + PRInt64 size, + PRFileMapProtect prot); + +/* + * return the alignment (in bytes) of the offset argument to PR_MemMap + */ +NSPR_API(PRInt32) PR_GetMemMapAlignment(void); + +NSPR_API(void *) PR_MemMap( + PRFileMap *fmap, + PROffset64 offset, /* must be aligned and sized according to the + * return value of PR_GetMemMapAlignment() */ + PRUint32 len); + +NSPR_API(PRStatus) PR_MemUnmap(void *addr, PRUint32 len); + +NSPR_API(PRStatus) PR_CloseFileMap(PRFileMap *fmap); + +/* + ****************************************************************** + * + * Interprocess communication + * + ****************************************************************** + */ + +/* + * Creates an anonymous pipe and returns file descriptors for the + * read and write ends of the pipe. + */ + +NSPR_API(PRStatus) PR_CreatePipe( + PRFileDesc **readPipe, + PRFileDesc **writePipe +); + +/************************************************************************/ +/************** The following definitions are for poll ******************/ +/************************************************************************/ + +struct PRPollDesc { + PRFileDesc* fd; + PRInt16 in_flags; + PRInt16 out_flags; +}; + +/* +** Bit values for PRPollDesc.in_flags or PRPollDesc.out_flags. Binary-or +** these together to produce the desired poll request. +*/ + +#if defined(_PR_POLL_BACKCOMPAT) + +#include +#define PR_POLL_READ POLLIN +#define PR_POLL_WRITE POLLOUT +#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 /* _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 /* _PR_POLL_BACKCOMPAT */ + +/* +************************************************************************* +** FUNCTION: PR_Poll +** DESCRIPTION: +** +** The call returns as soon as I/O is ready on one or more of the underlying +** socket objects. A count of the number of ready descriptors is +** returned unless a timeout occurs in which case zero is returned. +** +** PRPollDesc.fd should be set to a pointer to a PRFileDesc object +** representing a socket. This field can be set to NULL to indicate to +** PR_Poll that this PRFileDesc object should be ignored. +** PRPollDesc.in_flags should be set to the desired request +** (read/write/except or some combination). Upon successful return from +** this call PRPollDesc.out_flags will be set to indicate what kind of +** i/o can be performed on the respective descriptor. PR_Poll() uses the +** out_flags fields as scratch variables during the call. If PR_Poll() +** returns 0 or -1, the out_flags fields do not contain meaningful values +** and must not be used. +** +** INPUTS: +** PRPollDesc *pds A pointer to an array of PRPollDesc +** +** PRIntn npds The number of elements in the array +** If this argument is zero PR_Poll is +** equivalent to a PR_Sleep(timeout). +** +** PRIntervalTime timeout Amount of time the call will block waiting +** for I/O to become ready. If this time expires +** w/o any I/O becoming ready, the result will +** be zero. +** +** OUTPUTS: None +** RETURN: +** PRInt32 Number of PRPollDesc's with events or zero +** if the function timed out or -1 on failure. +** The reason for the failure is obtained by +** calling PR_GetError(). +************************************************************************** +*/ +NSPR_API(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). +** +************************************************************************** +*/ + +NSPR_API(PRFileDesc *) PR_NewPollableEvent(void); + +NSPR_API(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event); + +NSPR_API(PRStatus) PR_SetPollableEvent(PRFileDesc *event); + +NSPR_API(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event); + +PR_END_EXTERN_C + +#endif /* prio_h___ */ diff --git a/nsprpub/pr/include/pripcsem.h b/nsprpub/pr/include/pripcsem.h new file mode 100644 index 00000000000..5a96be5813a --- /dev/null +++ b/nsprpub/pr/include/pripcsem.h @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: pripcsem.h + * + * Description: named semaphores for interprocess + * synchronization + * + * Unrelated processes obtain access to a shared semaphore + * by specifying its name. + * + * Our goal is to support named semaphores on at least + * Unix and Win32 platforms. The implementation will use + * one of the three native semaphore APIs: POSIX, System V, + * and Win32. + * + * Because POSIX named semaphores have kernel persistence, + * we are forced to have a delete function in this API. + */ + +#ifndef pripcsem_h___ +#define pripcsem_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/* + * PRSem is an opaque structure that represents a named + * semaphore. + */ +typedef struct PRSem PRSem; + +/* + * PR_OpenSemaphore -- + * + * Create or open a named semaphore with the specified name. + * A handle to the semaphore is returned. + * + * If the named semaphore doesn't exist and the PR_SEM_CREATE + * flag is specified, the named semaphore is created. The + * created semaphore needs to be removed from the system with + * a PR_DeleteSemaphore call. + * + * If PR_SEM_CREATE is specified, the third argument is the + * access permission bits of the new semaphore (same + * interpretation as the mode argument to PR_Open) and the + * fourth argument is the initial value of the new semaphore. + * If PR_SEM_CREATE is not specified, the third and fourth + * arguments are ignored. + */ + +#define PR_SEM_CREATE 0x1 /* create if not exist */ +#define PR_SEM_EXCL 0x2 /* fail if already exists */ + +NSPR_API(PRSem *) PR_OpenSemaphore( + const char *name, PRIntn flags, PRIntn mode, PRUintn value); + +/* + * PR_WaitSemaphore -- + * + * If the value of the semaphore is > 0, decrement the value and return. + * If the value is 0, sleep until the value becomes > 0, then decrement + * the value and return. + * + * The "test and decrement" operation is performed atomically. + */ + +NSPR_API(PRStatus) PR_WaitSemaphore(PRSem *sem); + +/* + * PR_PostSemaphore -- + * + * Increment the value of the named semaphore by 1. + */ + +NSPR_API(PRStatus) PR_PostSemaphore(PRSem *sem); + +/* + * PR_CloseSemaphore -- + * + * Close a named semaphore handle. + */ + +NSPR_API(PRStatus) PR_CloseSemaphore(PRSem *sem); + +/* + * PR_DeleteSemaphore -- + * + * Remove a named semaphore from the system. + */ + +NSPR_API(PRStatus) PR_DeleteSemaphore(const char *name); + +PR_END_EXTERN_C + +#endif /* pripcsem_h___ */ diff --git a/nsprpub/pr/include/private/.cvsignore b/nsprpub/pr/include/private/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/include/private/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/include/private/Makefile.in b/nsprpub/pr/include/private/Makefile.in new file mode 100644 index 00000000000..180393b1e04 --- /dev/null +++ b/nsprpub/pr/include/private/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +RELEASE_HEADERS = pprio.h pprthred.h prpriv.h +RELEASE_HEADERS := $(addprefix $(srcdir)/, $(RELEASE_HEADERS)) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR)/private + +HEADERS = $(RELEASE_HEADERS) $(srcdir)/pprmwait.h $(srcdir)/primpl.h + +include_subdir = private + +include $(topsrcdir)/config/rules.mk + +export:: $(RELEASE_HEADERS) + $(INSTALL) -m 444 $(RELEASE_HEADERS) $(dist_includedir)/private diff --git a/nsprpub/pr/include/private/pprio.h b/nsprpub/pr/include/private/pprio.h new file mode 100644 index 00000000000..63e063cf2c5 --- /dev/null +++ b/nsprpub/pr/include/private/pprio.h @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: pprio.h +** +** Description: Private definitions for I/O related structures +*/ + +#ifndef pprio_h___ +#define pprio_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/************************************************************************/ + +#ifdef _WIN64 +typedef __int64 PROsfd; +#else +typedef PRInt32 PROsfd; +#endif + +/* Return the method tables for files, tcp sockets and udp sockets */ +NSPR_API(const PRIOMethods*) PR_GetFileMethods(void); +NSPR_API(const PRIOMethods*) PR_GetTCPMethods(void); +NSPR_API(const PRIOMethods*) PR_GetUDPMethods(void); +NSPR_API(const PRIOMethods*) PR_GetPipeMethods(void); + +/* +** Convert a NSPR Socket Handle to a Native Socket handle. +** This function will be obsoleted with the next release; avoid using it. +*/ +NSPR_API(PROsfd) PR_FileDesc2NativeHandle(PRFileDesc *); +NSPR_API(void) PR_ChangeFileDescNativeHandle(PRFileDesc *, PROsfd); +NSPR_API(PRFileDesc*) PR_AllocFileDesc(PROsfd osfd, + const PRIOMethods *methods); +NSPR_API(void) PR_FreeFileDesc(PRFileDesc *fd); +/* +** Import an existing OS file to NSPR. +*/ +NSPR_API(PRFileDesc*) PR_ImportFile(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportPipe(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportTCPSocket(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportUDPSocket(PROsfd osfd); + + +/* + ************************************************************************* + * FUNCTION: PR_CreateSocketPollFd + * DESCRIPTION: + * Create a PRFileDesc wrapper for a native socket handle, for use with + * PR_Poll only + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_CreateSocketPollFd returns a pointer + * to the PRFileDesc created for the native socket handle + * Returns a NULL pointer if the create of a new PRFileDesc failed + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd); + +/* + ************************************************************************* + * FUNCTION: PR_DestroySocketPollFd + * DESCRIPTION: + * Destroy the PRFileDesc wrapper created by PR_CreateSocketPollFd + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_DestroySocketPollFd returns + * PR_SUCCESS, else PR_FAILURE + * + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd); + + +/* +** Macros for PR_Socket +** +** Socket types: PR_SOCK_STREAM, PR_SOCK_DGRAM +*/ + +#ifdef WIN32 + +#define PR_SOCK_STREAM 1 +#define PR_SOCK_DGRAM 2 + +#else /* WIN32 */ + +#define PR_SOCK_STREAM SOCK_STREAM +#define PR_SOCK_DGRAM SOCK_DGRAM + +#endif /* WIN32 */ + +/* +** Create a new Socket; this function is obsolete. +*/ +NSPR_API(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto); + +/* FUNCTION: PR_LockFile +** DESCRIPTION: +** Lock a file for exclusive access. +** RETURNS: +** PR_SUCCESS when the lock is held +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_LockFile(PRFileDesc *fd); + +/* FUNCTION: PR_TLockFile +** DESCRIPTION: +** Test and Lock a file for exclusive access. Do not block if the +** file cannot be locked immediately. +** RETURNS: +** PR_SUCCESS when the lock is held +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_TLockFile(PRFileDesc *fd); + +/* FUNCTION: PR_UnlockFile +** DESCRIPTION: +** Unlock a file which has been previously locked successfully by this +** process. +** RETURNS: +** PR_SUCCESS when the lock is released +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_UnlockFile(PRFileDesc *fd); + +/* +** Emulate acceptread by accept and recv. +*/ +NSPR_API(PRInt32) PR_EmulateAcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout); + +/* +** Emulate sendfile by reading from the file and writing to the socket. +** The file is memory-mapped if memory-mapped files are supported. +*/ +NSPR_API(PRInt32) PR_EmulateSendFile( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +#ifdef WIN32 +/* FUNCTION: PR_NTFast_AcceptRead +** DESCRIPTION: +** NT has the notion of an "accept context", which is only needed in +** order to make certain calls. By default, a socket connected via +** AcceptEx can only do a limited number of things without updating +** the acceptcontext. The generic version of PR_AcceptRead always +** updates the accept context. This version does not. +**/ +NSPR_API(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime t); + +typedef void (*_PR_AcceptTimeoutCallback)(void *); + +/* FUNCTION: PR_NTFast_AcceptRead_WithTimeoutCallback +** DESCRIPTION: +** The AcceptEx call combines the accept with the read function. However, +** our daemon threads need to be able to wakeup and reliably flush their +** log buffers if the Accept times out. However, with the current blocking +** interface to AcceptRead, there is no way for us to timeout the Accept; +** this is because when we timeout the Read, we can close the newly +** socket and continue; but when we timeout the accept itself, there is no +** new socket to timeout. So instead, this version of the function is +** provided. After the initial timeout period elapses on the accept() +** portion of the function, it will call the callback routine and then +** continue the accept. If the timeout occurs on the read, it will +** close the connection and return error. +*/ +NSPR_API(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback( + PRFileDesc *sd, + PRFileDesc **nd, + PRNetAddr **raddr, + void *buf, + PRInt32 amount, + PRIntervalTime t, + _PR_AcceptTimeoutCallback callback, + void *callback_arg); + +/* FUNCTION: PR_NTFast_Accept +** DESCRIPTION: +** NT has the notion of an "accept context", which is only needed in +** order to make certain calls. By default, a socket connected via +** AcceptEx can only do a limited number of things without updating +** the acceptcontext. The generic version of PR_Accept always +** updates the accept context. This version does not. +**/ +NSPR_API(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr, + PRIntervalTime timeout); + +/* FUNCTION: PR_NTFast_Update +** DESCRIPTION: +** For sockets accepted with PR_NTFast_Accept or PR_NTFastAcceptRead, +** this function will update the accept context for those sockets, +** so that the socket can make general purpose socket calls. +** Without calling this, the only operations supported on the socket +** Are PR_Read, PR_Write, PR_Transmitfile, and PR_Close. +*/ +NSPR_API(void) PR_NTFast_UpdateAcceptContext(PRFileDesc *acceptSock, + PRFileDesc *listenSock); + + +/* FUNCTION: PR_NT_CancelIo +** DESCRIPTION: +** Cancel IO operations on fd. +*/ +NSPR_API(PRStatus) PR_NT_CancelIo(PRFileDesc *fd); + + +#endif /* WIN32 */ + +/* +** Need external access to this on Mac so we can first set up our faux +** environment vars +*/ +#ifdef XP_MAC +NSPR_API(void) PR_Init_Log(void); +#endif + + +PR_END_EXTERN_C + +#endif /* pprio_h___ */ diff --git a/nsprpub/pr/include/private/pprmwait.h b/nsprpub/pr/include/private/pprmwait.h new file mode 100644 index 00000000000..d116a8b312e --- /dev/null +++ b/nsprpub/pr/include/private/pprmwait.h @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if defined(_PPRMWAIT_H) +#else +#define _PPRMWAIT_H + +#include "prlock.h" +#include "prcvar.h" +#include "prclist.h" +#include "prthread.h" + +#define MAX_POLLING_INTERVAL 100 +#define _PR_POLL_COUNT_FUDGE 64 +#define _PR_DEFAULT_HASH_LENGTH 59 + +/* + * Our hash table resolves collisions by open addressing with + * double hashing. See Cormen, Leiserson, and Rivest, + * Introduction to Algorithms, p. 232, The MIT Press, 1990. + */ + +#define _MW_HASH(a, m) ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m)) +#define _MW_HASH2(a, m) (1 + ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m - 2))) +#define _MW_ABORTED(_rv) \ + ((PR_FAILURE == (_rv)) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) + +typedef enum {_prmw_success, _prmw_rehash, _prmw_error} _PR_HashStory; + +typedef struct _PRWaiterHash +{ + PRUint16 count; /* current number in hash table */ + PRUint16 length; /* current size of the hash table */ + PRRecvWait *recv_wait; /* hash table of receive wait objects */ +} _PRWaiterHash; + +typedef enum {_prmw_running, _prmw_stopping, _prmw_stopped} PRMWGroupState; + +struct PRWaitGroup +{ + PRCList group_link; /* all groups are linked to each other */ + PRCList io_ready; /* list of I/O requests that are ready */ + PRMWGroupState state; /* state of this group (so we can shut down) */ + + PRLock *ml; /* lock for synchronizing this wait group */ + PRCondVar *io_taken; /* calling threads notify when they take I/O */ + PRCondVar *io_complete; /* calling threads wait here for completions */ + PRCondVar *new_business; /* polling thread waits here more work */ + PRCondVar *mw_manage; /* used to manage group lists */ + 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/nsprpub/pr/include/private/pprthred.h b/nsprpub/pr/include/private/pprthred.h new file mode 100644 index 00000000000..c94133965b4 --- /dev/null +++ b/nsprpub/pr/include/private/pprthred.h @@ -0,0 +1,373 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef pprthred_h___ +#define pprthred_h___ + +/* +** API for PR private functions. These calls are to be used by internal +** developers only. +*/ +#include "nspr.h" + +#if defined(XP_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#include +#endif + +PR_BEGIN_EXTERN_C + +/*--------------------------------------------------------------------------- +** THREAD PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** 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 +** +** This can return NULL if some kind of error occurs, or if memory is +** tight. This call invokes "start(obj,arg)" and returns when the +** function returns. The thread object is automatically destroyed. +** +** This call is not normally needed unless you create your own native +** thread. PR_Init does this automatically for the primordial thread. +*/ +NSPR_API(PRThread*) PR_AttachThread(PRThreadType type, + PRThreadPriority priority, + PRThreadStack *stack); + +/* +** 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. +*/ +NSPR_API(void) PR_DetachThread(void); + +/* +** Get the id of the named thread. Each thread is assigned a unique id +** when it is created or attached. +*/ +NSPR_API(PRUint32) PR_GetThreadID(PRThread *thread); + +/* +** Set the procedure that is called when a thread is dumped. The procedure +** will be applied to the argument, arg, when called. Setting the procedure +** to NULL effectively removes it. +*/ +typedef void (*PRThreadDumpProc)(PRFileDesc *fd, PRThread *t, void *arg); +NSPR_API(void) PR_SetThreadDumpProc( + PRThread* thread, PRThreadDumpProc dump, void *arg); + +/* +** Get this thread's affinity mask. The affinity mask is a 32 bit quantity +** marking a bit for each processor this process is allowed to run on. +** The processor mask is returned in the mask argument. +** The least-significant-bit represents processor 0. +** +** Returns 0 on success, -1 on failure. +*/ +NSPR_API(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask); + +/* +** Set this thread's affinity mask. +** +** Returns 0 on success, -1 on failure. +*/ +NSPR_API(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ); + +/* +** Set the default CPU Affinity mask. +** +*/ +NSPR_API(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask); + +/* +** Show status of all threads to standard error output. +*/ +NSPR_API(void) PR_ShowStatus(void); + +/* +** Set thread recycle mode to on (1) or off (0) +*/ +NSPR_API(void) PR_SetThreadRecycleMode(PRUint32 flag); + + +/*--------------------------------------------------------------------------- +** THREAD PRIVATE FUNCTIONS FOR GARBAGE COLLECTIBLE THREADS +---------------------------------------------------------------------------*/ + +/* +** Only Garbage collectible threads participate in resume all, suspend all and +** enumeration operations. They are also different during creation when +** platform specific action may be needed (For example, all Solaris GC able +** threads are bound threads). +*/ + +/* +** Same as PR_CreateThread except that the thread is marked as garbage +** collectible. +*/ +NSPR_API(PRThread*) PR_CreateThreadGCAble(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); + +/* +** Same as PR_AttachThread except that the thread being attached is marked as +** garbage collectible. +*/ +NSPR_API(PRThread*) PR_AttachThreadGCAble(PRThreadType type, + PRThreadPriority priority, + PRThreadStack *stack); + +/* +** Mark the thread as garbage collectible. +*/ +NSPR_API(void) PR_SetThreadGCAble(void); + +/* +** Unmark the thread as garbage collectible. +*/ +NSPR_API(void) PR_ClearThreadGCAble(void); + +/* +** This routine prevents all other GC able threads from running. This call is needed by +** the garbage collector. +*/ +NSPR_API(void) PR_SuspendAll(void); + +/* +** This routine unblocks all other GC able threads that were suspended from running by +** PR_SuspendAll(). This call is needed by the garbage collector. +*/ +NSPR_API(void) PR_ResumeAll(void); + +/* +** Return the thread stack pointer of the given thread. +** Needed by the garbage collector. +*/ +NSPR_API(void *) PR_GetSP(PRThread *thread); + +/* +** Save the registers that the GC would find interesting into the thread +** "t". isCurrent will be non-zero if the thread state that is being +** saved is the currently executing thread. Return the address of the +** first register to be scanned as well as the number of registers to +** scan in "np". +** +** If "isCurrent" is non-zero then it is allowed for the thread context +** area to be used as scratch storage to hold just the registers +** necessary for scanning. +** +** This function simply calls the internal function _MD_HomeGCRegisters(). +*/ +NSPR_API(PRWord *) PR_GetGCRegisters(PRThread *t, int isCurrent, int *np); + +/* +** (Get|Set)ExecutionEnvironent +** +** Used by Java to associate it's execution environment so garbage collector +** can find it. If return is NULL, then it's probably not a collectable thread. +** +** There's no locking required around these calls. +*/ +NSPR_API(void*) GetExecutionEnvironment(PRThread *thread); +NSPR_API(void) SetExecutionEnvironment(PRThread* thread, void *environment); + +/* +** Enumeration function that applies "func(thread,i,arg)" to each active +** thread in the process. The enumerator returns PR_SUCCESS if the enumeration +** should continue, any other value is considered failure, and enumeration +** stops, returning the failure value from PR_EnumerateThreads. +** Needed by the garbage collector. +*/ +typedef PRStatus (PR_CALLBACK *PREnumerator)(PRThread *t, int i, void *arg); +NSPR_API(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg); + +/* +** Signature of a thread stack scanning function. It is applied to every +** contiguous group of potential pointers within a thread. Count denotes the +** number of pointers. +*/ +typedef PRStatus +(PR_CALLBACK *PRScanStackFun)(PRThread* t, + void** baseAddr, PRUword count, void* closure); + +/* +** Applies scanFun to all contiguous groups of potential pointers +** within a thread. This includes the stack, registers, and thread-local +** data. If scanFun returns a status value other than PR_SUCCESS the scan +** is aborted, and the status value is returned. +*/ +NSPR_API(PRStatus) +PR_ThreadScanStackPointers(PRThread* t, + PRScanStackFun scanFun, void* scanClosure); + +/* +** Calls PR_ThreadScanStackPointers for every thread. +*/ +NSPR_API(PRStatus) +PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure); + +/* +** Returns a conservative estimate on the amount of stack space left +** on a thread in bytes, sufficient for making decisions about whether +** to continue recursing or not. +*/ +NSPR_API(PRUword) +PR_GetStackSpaceLeft(PRThread* t); + +/*--------------------------------------------------------------------------- +** THREAD CPU PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Get a pointer to the primordial CPU. +*/ +NSPR_API(struct _PRCPU *) _PR_GetPrimordialCPU(void); + +/*--------------------------------------------------------------------------- +** THREAD SYNCHRONIZATION PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Create a new named monitor (named for debugging purposes). +** Monitors are re-entrant locks with a built-in condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +NSPR_API(PRMonitor*) PR_NewNamedMonitor(const char* name); + +/* +** Test and then lock the lock if it's not already locked by some other +** thread. Return PR_FALSE if some other thread owned the lock at the +** time of the call. +*/ +NSPR_API(PRBool) PR_TestAndLock(PRLock *lock); + +/* +** Test and then enter the mutex associated with the monitor if it's not +** already entered by some other thread. Return PR_FALSE if some other +** thread owned the mutex at the time of the call. +*/ +NSPR_API(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon); + +/* +** Return the number of times that the current thread has entered the +** mutex. Returns zero if the current thread has not entered the mutex. +*/ +NSPR_API(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon); + +/* +** Just like PR_CEnterMonitor except that if the monitor is owned by +** another thread NULL is returned. +*/ +NSPR_API(PRMonitor*) PR_CTestAndEnterMonitor(void *address); + +/*--------------------------------------------------------------------------- +** PLATFORM-SPECIFIC THREAD SYNCHRONIZATION FUNCTIONS +---------------------------------------------------------------------------*/ +#if defined(XP_MAC) + +NSPR_API(void) PR_Mac_WaitForAsyncNotify(PRIntervalTime timeout); +NSPR_API(void) PR_Mac_PostAsyncNotify(PRThread *thread); + +#endif /* XP_MAC */ + +/*--------------------------------------------------------------------------- +** PLATFORM-SPECIFIC INITIALIZATION FUNCTIONS +---------------------------------------------------------------------------*/ +#if defined(IRIX) +/* +** Irix specific initialization funtion to be called before PR_Init +** is called by the application. Sets the CONF_INITUSERS and CONF_INITSIZE +** attributes of the shared arena set up by nspr. +** +** The environment variables _NSPR_IRIX_INITUSERS and _NSPR_IRIX_INITSIZE +** can also be used to set these arena attributes. If _NSPR_IRIX_INITUSERS +** is set, but not _NSPR_IRIX_INITSIZE, the value of the CONF_INITSIZE +** attribute of the nspr arena is scaled as a function of the +** _NSPR_IRIX_INITUSERS value. +** +** If the _PR_Irix_Set_Arena_Params() is called in addition to setting the +** environment variables, the values of the environment variables are used. +** +*/ +NSPR_API(void) _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize); + +#endif /* IRIX */ + +#if defined(XP_OS2) +/* +** These functions need to be called at the start and end of a thread. +** An EXCEPTIONREGISTRATIONRECORD must be declared on the stack and its +** address passed to the two functions. +*/ +NSPR_API(void) PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e); +NSPR_API(void) PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e); +#endif /* XP_OS2 */ + +/* I think PR_GetMonitorEntryCount is useless. All you really want is this... */ +#define PR_InMonitor(m) (PR_GetMonitorEntryCount(m) > 0) + +/*--------------------------------------------------------------------------- +** Special X-Lock hack for client +---------------------------------------------------------------------------*/ + +#ifdef XP_UNIX +extern void PR_XLock(void); +extern void PR_XUnlock(void); +extern PRBool PR_XIsLocked(void); +#endif /* XP_UNIX */ + +PR_END_EXTERN_C + +#endif /* pprthred_h___ */ diff --git a/nsprpub/pr/include/private/primpl.h b/nsprpub/pr/include/private/primpl.h new file mode 100644 index 00000000000..ff28221178d --- /dev/null +++ b/nsprpub/pr/include/private/primpl.h @@ -0,0 +1,2149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef primpl_h___ +#define primpl_h___ + +/* + * HP-UX 10.10's pthread.h (DCE threads) includes dce/cma.h, which + * has: + * #define sigaction _sigaction_sys + * This macro causes chaos if signal.h gets included before pthread.h. + * To be safe, we include pthread.h first. + */ + +#if defined(_PR_PTHREADS) +#include +#endif + +#if defined(_PR_BTHREADS) +#include +#endif + +#ifdef WINNT +/* Need to force service-pack 3 extensions to be defined by +** setting _WIN32_WINNT to NT 4.0 for winsock.h, winbase.h, winnt.h. +*/ +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#elif (_WIN32_WINNT < 0x0400) + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#endif /* _WIN32_WINNT */ +#endif /* WINNT */ + +#include "nspr.h" +#include "prpriv.h" + +typedef struct PRSegment PRSegment; + +#ifdef XP_MAC +#include "prosdep.h" +#include "probslet.h" +#else +#include "md/prosdep.h" +#include "obsolete/probslet.h" +#endif /* XP_MAC */ + +#ifdef _PR_HAVE_POSIX_SEMAPHORES +#include +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) +#include +#endif + +/************************************************************************* +***** A Word about Model Dependent Function Naming Convention *********** +*************************************************************************/ + +/* +NSPR 2.0 must implement its function across a range of platforms +including: MAC, Windows/16, Windows/95, Windows/NT, and several +variants of Unix. Each implementation shares common code as well +as having platform dependent portions. This standard describes how +the model dependent portions are to be implemented. + +In header file pr/include/primpl.h, each publicly declared +platform dependent function is declared as: + +NSPR_API void _PR_MD_FUNCTION( long arg1, long arg2 ); +#define _PR_MD_FUNCTION _MD_FUNCTION + +In header file pr/include/md//_.h, +each #define'd macro is redefined as one of: + +#define _MD_FUNCTION +#define _MD_FUNCTION +#define _MD_FUNCTION +#define _MD_FUNCTION <_MD_Function> + +Where: + + is no definition at all. In this case, the function is not implemented +and is never called for this platform. +For example: +#define _MD_INIT_CPUS() + + is a C language macro expansion. +For example: +#define _MD_CLEAN_THREAD(_thread) \ + PR_BEGIN_MACRO \ + PR_DestroyCondVar(_thread->md.asyncIOCVar); \ + PR_DestroyLock(_thread->md.asyncIOLock); \ + PR_END_MACRO + + is some function implemented by the host operating system. +For example: +#define _MD_EXIT exit + +<_MD_function> is the name of a function implemented for this platform in +pr/src/md//.c file. +For example: +#define _MD_GETFILEINFO _MD_GetFileInfo + +In .c, the implementation is: +PR_IMPLEMENT(PRInt32) _MD_GetFileInfo(const char *fn, PRFileInfo *info); +*/ + +PR_BEGIN_EXTERN_C + +typedef struct _MDLock _MDLock; +typedef struct _MDCVar _MDCVar; +typedef struct _MDSegment _MDSegment; +typedef struct _MDThread _MDThread; +typedef struct _MDThreadStack _MDThreadStack; +typedef struct _MDSemaphore _MDSemaphore; +typedef struct _MDDir _MDDir; +#ifdef MOZ_UNICODE +typedef struct _MDDirUTF16 _MDDirUTF16; +#endif /* MOZ_UNICODE */ +typedef struct _MDFileDesc _MDFileDesc; +typedef struct _MDProcess _MDProcess; +typedef struct _MDFileMap _MDFileMap; + +#if defined(_PR_PTHREADS) + +/* +** The following definitions are unique to implementing NSPR using pthreads. +** Since pthreads defines most of the thread and thread synchronization +** stuff, this is a pretty small set. +*/ + +#define PT_CV_NOTIFIED_LENGTH 6 +typedef struct _PT_Notified _PT_Notified; +struct _PT_Notified +{ + PRIntn length; /* # of used entries in this structure */ + struct + { + PRCondVar *cv; /* the condition variable notified */ + PRIntn times; /* and the number of times notified */ + } cv[PT_CV_NOTIFIED_LENGTH]; + _PT_Notified *link; /* link to another of these | NULL */ +}; + +/* + * bits defined for pthreads 'state' field + */ +#define PT_THREAD_DETACHED 0x01 /* thread can't be joined */ +#define PT_THREAD_GLOBAL 0x02 /* a global thread (unlikely) */ +#define PT_THREAD_SYSTEM 0x04 /* system (not user) thread */ +#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_FOREIGN 0x80 /* thread is not one of ours */ +#define PT_THREAD_BOUND 0x100 /* a bound-global thread */ + +#define _PT_THREAD_INTERRUPTED(thr) \ + (!(thr->interrupt_blocked) && (thr->state & PT_THREAD_ABORTED)) +#define _PT_THREAD_BLOCK_INTERRUPT(thr) \ + (thr->interrupt_blocked = 1) +#define _PT_THREAD_UNBLOCK_INTERRUPT(thr) \ + (thr->interrupt_blocked = 0) + +#ifdef GC_LEAK_DETECTOR +/* All threads are GCable. */ +#define _PT_IS_GCABLE_THREAD(thr) 1 +#else +#define _PT_IS_GCABLE_THREAD(thr) ((thr)->state & PT_THREAD_GCABLE) +#endif /* GC_LEAK_DETECTOR */ + +/* +** Possible values for thread's suspend field +** Note that the first two can be the same as they are really mutually exclusive, +** i.e. both cannot be happening at the same time. We have two symbolic names +** just as a mnemonic. +**/ +#define PT_THREAD_RESUMED 0x80 /* thread has been resumed */ +#define PT_THREAD_SETGCABLE 0x100 /* set the GCAble flag */ + +#if defined(DEBUG) + +typedef struct PTDebug +{ + PRTime timeStarted; + PRUintn locks_created, locks_destroyed; + PRUintn locks_acquired, locks_released; + PRUintn cvars_created, cvars_destroyed; + PRUintn cvars_notified, delayed_cv_deletes; +} PTDebug; + +#endif /* defined(DEBUG) */ + +NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); + +#else /* defined(_PR_PTHREADS) */ + +NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); + +/* +** This section is contains those parts needed to implement NSPR on +** platforms in general. One would assume that the pthreads implementation +** included lots of the same types, at least conceptually. +*/ + +/* + * Local threads only. No multiple CPU support and hence all the + * following routines are no-op. + */ +#ifdef _PR_LOCAL_THREADS_ONLY + +#define _PR_MD_SUSPEND_THREAD(thread) +#define _PR_MD_RESUME_THREAD(thread) +#define _PR_MD_SUSPEND_CPU(cpu) +#define _PR_MD_RESUME_CPU(cpu) +#define _PR_MD_BEGIN_SUSPEND_ALL() +#define _PR_MD_END_SUSPEND_ALL() +#define _PR_MD_BEGIN_RESUME_ALL() +#define _PR_MD_END_RESUME_ALL() +#define _PR_MD_INIT_ATTACHED_THREAD(thread) PR_FAILURE + +#endif + +typedef struct _PRCPUQueue _PRCPUQueue; +typedef struct _PRCPU _PRCPU; +typedef struct _MDCPU _MDCPU; + +struct _PRCPUQueue { + _MDLock runQLock; /* lock for the run + wait queues */ + _MDLock sleepQLock; /* lock for the run + wait queues */ + _MDLock miscQLock; /* lock for the run + wait queues */ + + PRCList runQ[PR_PRIORITY_LAST + 1]; /* run queue for this CPU */ + PRUint32 runQReadyMask; + PRCList sleepQ; + PRIntervalTime sleepQmax; + PRCList pauseQ; + PRCList suspendQ; + PRCList waitingToJoinQ; + + PRUintn numCPUs; /* number of CPUs using this Q */ +}; + +struct _PRCPU { + PRCList links; /* link list of CPUs */ + PRUint32 id; /* id for this CPU */ + + union { + PRInt32 bits; + PRUint8 missed[4]; + } u; + PRIntn where; /* index into u.missed */ + PRPackedBool paused; /* cpu is paused */ + PRPackedBool exit; /* cpu should exit */ + + PRThread *thread; /* native thread for this CPUThread */ + PRThread *idle_thread; /* user-level idle thread for this CPUThread */ + + PRIntervalTime last_clock; /* the last time we went into + * _PR_ClockInterrupt() on this CPU + */ + + _PRCPUQueue *queue; + + _MDCPU md; +}; + +typedef struct _PRInterruptTable { + const char *name; + PRUintn missed_bit; + void (*handler)(void); +} _PRInterruptTable; + +#define _PR_CPU_PTR(_qp) \ + ((_PRCPU*) ((char*) (_qp) - offsetof(_PRCPU,links))) + +#if !defined(IRIX) && !defined(WIN32) && !defined(XP_OS2) \ + && !(defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)) +#define _MD_GET_ATTACHED_THREAD() (_PR_MD_CURRENT_THREAD()) +#endif + +#ifdef _PR_LOCAL_THREADS_ONLY + +NSPR_API(struct _PRCPU *) _pr_currentCPU; +NSPR_API(PRThread *) _pr_currentThread; +NSPR_API(PRThread *) _pr_lastThread; +NSPR_API(PRInt32) _pr_intsOff; + +#define _MD_CURRENT_CPU() (_pr_currentCPU) +#define _MD_SET_CURRENT_CPU(_cpu) (_pr_currentCPU = (_cpu)) +#define _MD_CURRENT_THREAD() (_pr_currentThread) +#define _MD_SET_CURRENT_THREAD(_thread) (_pr_currentThread = (_thread)) +#define _MD_LAST_THREAD() (_pr_lastThread) +#define _MD_SET_LAST_THREAD(t) (_pr_lastThread = t) + +#ifndef XP_MAC +#define _MD_GET_INTSOFF() (_pr_intsOff) +#define _MD_SET_INTSOFF(_val) (_pr_intsOff = _val) +#endif + + +/* The unbalanced curly braces in these two macros are intentional */ +#define _PR_LOCK_HEAP() { PRIntn _is; if (_pr_currentCPU) _PR_INTSOFF(_is); +#define _PR_UNLOCK_HEAP() if (_pr_currentCPU) _PR_INTSON(_is); } + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +extern PRInt32 _native_threads_only; + +#if defined(_PR_GLOBAL_THREADS_ONLY) + +#define _MD_GET_INTSOFF() 0 +#define _MD_SET_INTSOFF(_val) +#define _PR_INTSOFF(_is) +#define _PR_FAST_INTSON(_is) +#define _PR_INTSON(_is) +#define _PR_THREAD_LOCK(_thread) +#define _PR_THREAD_UNLOCK(_thread) +#define _PR_RUNQ_LOCK(cpu) +#define _PR_RUNQ_UNLOCK(cpu) +#define _PR_SLEEPQ_LOCK(thread) +#define _PR_SLEEPQ_UNLOCK(thread) +#define _PR_MISCQ_LOCK(thread) +#define _PR_MISCQ_UNLOCK(thread) +#define _PR_CPU_LIST_LOCK() +#define _PR_CPU_LIST_UNLOCK() + +#define _PR_ADD_RUNQ(_thread, _cpu, _pri) +#define _PR_DEL_RUNQ(_thread) +#define _PR_ADD_SLEEPQ(_thread, _timeout) +#define _PR_DEL_SLEEPQ(_thread, _propogate) +#define _PR_ADD_JOINQ(_thread, _cpu) +#define _PR_DEL_JOINQ(_thread) +#define _PR_ADD_SUSPENDQ(_thread, _cpu) +#define _PR_DEL_SUSPENDQ(_thread) + +#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU) + +#define _PR_IS_NATIVE_THREAD(thread) 1 +#define _PR_IS_NATIVE_THREAD_SUPPORTED() 1 + +#else + +#ifdef XP_MAC + +#define _PR_INTSOFF(_is) _MD_INTSOFF(_is) + +#else /* XP_MAC */ + +#define _PR_INTSOFF(_is) \ + PR_BEGIN_MACRO \ + (_is) = _PR_MD_GET_INTSOFF(); \ + _PR_MD_SET_INTSOFF(1); \ + PR_END_MACRO + +#endif /* XP_MAC */ + +#define _PR_FAST_INTSON(_is) \ + PR_BEGIN_MACRO \ + _PR_MD_SET_INTSOFF(_is); \ + PR_END_MACRO + +#define _PR_INTSON(_is) \ + PR_BEGIN_MACRO \ + if ((_is == 0) && (_PR_MD_CURRENT_CPU())->u.bits) \ + _PR_IntsOn((_PR_MD_CURRENT_CPU())); \ + _PR_MD_SET_INTSOFF(_is); \ + PR_END_MACRO + +#ifdef _PR_LOCAL_THREADS_ONLY + +#define _PR_IS_NATIVE_THREAD(thread) 0 +#define _PR_THREAD_LOCK(_thread) +#define _PR_THREAD_UNLOCK(_thread) +#define _PR_RUNQ_LOCK(cpu) +#define _PR_RUNQ_UNLOCK(cpu) +#define _PR_SLEEPQ_LOCK(thread) +#define _PR_SLEEPQ_UNLOCK(thread) +#define _PR_MISCQ_LOCK(thread) +#define _PR_MISCQ_UNLOCK(thread) +#define _PR_CPU_LIST_LOCK() +#define _PR_CPU_LIST_UNLOCK() + +#define _PR_ADD_RUNQ(_thread, _cpu, _pri) \ + PR_BEGIN_MACRO \ + PR_APPEND_LINK(&(_thread)->links, &_PR_RUNQ(_cpu)[_pri]); \ + _PR_RUNQREADYMASK(_cpu) |= (1L << _pri); \ + PR_END_MACRO + +#define _PR_DEL_RUNQ(_thread) \ + PR_BEGIN_MACRO \ + _PRCPU *_cpu = _thread->cpu; \ + PRInt32 _pri = _thread->priority; \ + PR_REMOVE_LINK(&(_thread)->links); \ + if (PR_CLIST_IS_EMPTY(&_PR_RUNQ(_cpu)[_pri])) \ + _PR_RUNQREADYMASK(_cpu) &= ~(1L << _pri); \ + PR_END_MACRO + +#define _PR_ADD_SLEEPQ(_thread, _timeout) \ + _PR_AddSleepQ(_thread, _timeout); + +#define _PR_DEL_SLEEPQ(_thread, _propogate) \ + _PR_DelSleepQ(_thread, _propogate); + +#define _PR_ADD_JOINQ(_thread, _cpu) \ + PR_APPEND_LINK(&(_thread)->links, &_PR_WAITINGTOJOINQ(_cpu)); + +#define _PR_DEL_JOINQ(_thread) \ + PR_REMOVE_LINK(&(_thread)->links); + +#define _PR_ADD_SUSPENDQ(_thread, _cpu) \ + PR_APPEND_LINK(&(_thread)->links, &_PR_SUSPENDQ(_cpu)); + +#define _PR_DEL_SUSPENDQ(_thread) \ + PR_REMOVE_LINK(&(_thread)->links); + +#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU) + +#define _PR_IS_NATIVE_THREAD_SUPPORTED() 0 + +#else /* _PR_LOCAL_THREADS_ONLY */ + +/* These are for the "combined" thread model */ + +#define _PR_THREAD_LOCK(_thread) \ + _PR_MD_LOCK(&(_thread)->threadLock); + +#define _PR_THREAD_UNLOCK(_thread) \ + _PR_MD_UNLOCK(&(_thread)->threadLock); + +#define _PR_RUNQ_LOCK(_cpu) \ + PR_BEGIN_MACRO \ + _PR_MD_LOCK(&(_cpu)->queue->runQLock );\ + PR_END_MACRO + +#define _PR_RUNQ_UNLOCK(_cpu) \ + PR_BEGIN_MACRO \ + _PR_MD_UNLOCK(&(_cpu)->queue->runQLock );\ + PR_END_MACRO + +#define _PR_SLEEPQ_LOCK(_cpu) \ + _PR_MD_LOCK(&(_cpu)->queue->sleepQLock ); + +#define _PR_SLEEPQ_UNLOCK(_cpu) \ + _PR_MD_UNLOCK(&(_cpu)->queue->sleepQLock ); + +#define _PR_MISCQ_LOCK(_cpu) \ + _PR_MD_LOCK(&(_cpu)->queue->miscQLock ); + +#define _PR_MISCQ_UNLOCK(_cpu) \ + _PR_MD_UNLOCK(&(_cpu)->queue->miscQLock ); + +#define _PR_CPU_LIST_LOCK() _PR_MD_LOCK(&_pr_cpuLock) +#define _PR_CPU_LIST_UNLOCK() _PR_MD_UNLOCK(&_pr_cpuLock) + +#define QUEUE_RUN 0x1 +#define QUEUE_SLEEP 0x2 +#define QUEUE_JOIN 0x4 +#define QUEUE_SUSPEND 0x8 +#define QUEUE_LOCK 0x10 + +#define _PR_ADD_RUNQ(_thread, _cpu, _pri) \ + PR_BEGIN_MACRO \ + PR_APPEND_LINK(&(_thread)->links, &_PR_RUNQ(_cpu)[_pri]); \ + _PR_RUNQREADYMASK(_cpu) |= (1L << _pri); \ + PR_ASSERT((_thread)->queueCount == 0); \ + (_thread)->queueCount = QUEUE_RUN; \ + PR_END_MACRO + +#define _PR_DEL_RUNQ(_thread) \ + PR_BEGIN_MACRO \ + _PRCPU *_cpu = _thread->cpu; \ + PRInt32 _pri = _thread->priority; \ + PR_REMOVE_LINK(&(_thread)->links); \ + if (PR_CLIST_IS_EMPTY(&_PR_RUNQ(_cpu)[_pri])) \ + _PR_RUNQREADYMASK(_cpu) &= ~(1L << _pri); \ + PR_ASSERT((_thread)->queueCount == QUEUE_RUN);\ + (_thread)->queueCount = 0; \ + PR_END_MACRO + +#define _PR_ADD_SLEEPQ(_thread, _timeout) \ + PR_ASSERT((_thread)->queueCount == 0); \ + (_thread)->queueCount = QUEUE_SLEEP; \ + _PR_AddSleepQ(_thread, _timeout); + +#define _PR_DEL_SLEEPQ(_thread, _propogate) \ + PR_ASSERT((_thread)->queueCount == QUEUE_SLEEP);\ + (_thread)->queueCount = 0; \ + _PR_DelSleepQ(_thread, _propogate); + +#define _PR_ADD_JOINQ(_thread, _cpu) \ + PR_ASSERT((_thread)->queueCount == 0); \ + (_thread)->queueCount = QUEUE_JOIN; \ + PR_APPEND_LINK(&(_thread)->links, &_PR_WAITINGTOJOINQ(_cpu)); + +#define _PR_DEL_JOINQ(_thread) \ + PR_ASSERT((_thread)->queueCount == QUEUE_JOIN);\ + (_thread)->queueCount = 0; \ + PR_REMOVE_LINK(&(_thread)->links); + +#define _PR_ADD_SUSPENDQ(_thread, _cpu) \ + PR_ASSERT((_thread)->queueCount == 0); \ + (_thread)->queueCount = QUEUE_SUSPEND; \ + PR_APPEND_LINK(&(_thread)->links, &_PR_SUSPENDQ(_cpu)); + +#define _PR_DEL_SUSPENDQ(_thread) \ + PR_ASSERT((_thread)->queueCount == QUEUE_SUSPEND);\ + (_thread)->queueCount = 0; \ + PR_REMOVE_LINK(&(_thread)->links); + +#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU) \ + (_thread)->cpu = (_newCPU); + +#define _PR_IS_NATIVE_THREAD(thread) (thread->flags & _PR_GLOBAL_SCOPE) +#define _PR_IS_NATIVE_THREAD_SUPPORTED() 1 + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +#endif /* _PR_GLOBAL_THREADS_ONLY */ + +#define _PR_SET_RESCHED_FLAG() _PR_MD_CURRENT_CPU()->u.missed[3] = 1 +#define _PR_CLEAR_RESCHED_FLAG() _PR_MD_CURRENT_CPU()->u.missed[3] = 0 + +extern _PRInterruptTable _pr_interruptTable[]; + +/* Bits for _pr_interruptState.u.missed[0,1] */ +#define _PR_MISSED_CLOCK 0x1 +#define _PR_MISSED_IO 0x2 +#define _PR_MISSED_CHILD 0x4 + +extern void _PR_IntsOn(_PRCPU *cpu); + +NSPR_API(void) _PR_WakeupCPU(void); +NSPR_API(void) _PR_PauseCPU(void); + +/************************************************************************/ + +#define _PR_LOCK_LOCK(_lock) \ + _PR_MD_LOCK(&(_lock)->ilock); +#define _PR_LOCK_UNLOCK(_lock) \ + _PR_MD_UNLOCK(&(_lock)->ilock); + +extern void _PR_UnblockLockWaiter(PRLock *lock); + +#define _PR_LOCK_PTR(_qp) \ + ((PRLock*) ((char*) (_qp) - offsetof(PRLock,links))) + +/************************************************************************/ + +#define _PR_CVAR_LOCK(_cvar) \ + _PR_MD_LOCK(&(_cvar)->ilock); +#define _PR_CVAR_UNLOCK(_cvar) \ + _PR_MD_UNLOCK(&(_cvar)->ilock); + +extern PRStatus _PR_WaitCondVar( + PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout); +extern PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen); + +NSPR_API(void) _PR_Notify(PRMonitor *mon, PRBool all, PRBool sticky); + +/* PRThread.flags */ +#define _PR_SYSTEM 0x01 +#define _PR_INTERRUPT 0x02 +#define _PR_ATTACHED 0x04 /* created via PR_AttachThread */ +#define _PR_PRIMORDIAL 0x08 /* the thread that called PR_Init */ +#define _PR_ON_SLEEPQ 0x10 /* thread is on the sleepQ */ +#define _PR_ON_PAUSEQ 0x20 /* thread is on the pauseQ */ +#define _PR_SUSPENDING 0x40 /* thread wants to suspend */ +#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 */ +#define _PR_INTERRUPT_BLOCKED 0x1000 /* interrupts blocked */ + +/* PRThread.state */ +#define _PR_UNBORN 0 +#define _PR_RUNNABLE 1 +#define _PR_RUNNING 2 +#define _PR_LOCK_WAIT 3 +#define _PR_COND_WAIT 4 +#define _PR_JOIN_WAIT 5 +#define _PR_IO_WAIT 6 +#define _PR_SUSPENDED 7 +#define _PR_DEAD_STATE 8 /* for debugging */ + +/* PRThreadStack.flags */ +#define _PR_STACK_VM 0x1 /* using vm instead of malloc */ +#define _PR_STACK_MAPPED 0x2 /* vm is mapped */ +#define _PR_STACK_PRIMORDIAL 0x4 /* stack for primordial thread */ + +/* +** If the default stcksize from the client is zero, we need to pick a machine +** dependent value. This is only for standard user threads. For custom threads, +** 0 has a special meaning. +** Adjust stackSize. Round up to a page boundary. +*/ + +#ifndef _MD_MINIMUM_STACK_SIZE +#define _MD_MINIMUM_STACK_SIZE 0 +#endif + +#if (!defined(HAVE_CUSTOM_USER_THREADS)) +#define _PR_ADJUST_STACKSIZE(stackSize) \ + PR_BEGIN_MACRO \ + if (stackSize == 0) \ + stackSize = _MD_DEFAULT_STACK_SIZE; \ + if (stackSize < _MD_MINIMUM_STACK_SIZE) \ + stackSize = _MD_MINIMUM_STACK_SIZE; \ + stackSize = (stackSize + (1 << _pr_pageShift) - 1) >> _pr_pageShift; \ + stackSize <<= _pr_pageShift; \ + PR_END_MACRO +#else +#define _PR_ADJUST_STACKSIZE(stackSize) +#endif + +#ifdef GC_LEAK_DETECTOR +/* All threads are GCable. */ +#define _PR_IS_GCABLE_THREAD(thr) 1 +#else +#define _PR_IS_GCABLE_THREAD(thr) ((thr)->flags & _PR_GCABLE_THREAD) +#endif /* GC_LEAK_DETECTOR */ + +#define _PR_PENDING_INTERRUPT(thr) \ + (!((thr)->flags & _PR_INTERRUPT_BLOCKED) && ((thr)->flags & _PR_INTERRUPT)) +#define _PR_THREAD_BLOCK_INTERRUPT(thr) \ + (thr->flags |= _PR_INTERRUPT_BLOCKED) +#define _PR_THREAD_UNBLOCK_INTERRUPT(thr) \ + (thr->flags &= ~_PR_INTERRUPT_BLOCKED) + +#define _PR_THREAD_PTR(_qp) \ + ((PRThread*) ((char*) (_qp) - offsetof(PRThread,links))) + +#define _PR_ACTIVE_THREAD_PTR(_qp) \ + ((PRThread*) ((char*) (_qp) - offsetof(PRThread,active))) + +#define _PR_THREAD_CONDQ_PTR(_qp) \ + ((PRThread*) ((char*) (_qp) - offsetof(PRThread,waitQLinks))) + +#define _PR_THREAD_MD_TO_PTR(_md) \ + ((PRThread*) ((char*) (_md) - offsetof(PRThread,md))) + +#define _PR_THREAD_STACK_TO_PTR(_stack) \ + ((PRThread*) (_stack->thr)) + +extern PRCList _pr_active_local_threadQ; +extern PRCList _pr_active_global_threadQ; +extern PRCList _pr_cpuQ; +extern _MDLock _pr_cpuLock; +extern PRInt32 _pr_md_idle_cpus; + +#define _PR_ACTIVE_LOCAL_THREADQ() _pr_active_local_threadQ +#define _PR_ACTIVE_GLOBAL_THREADQ() _pr_active_global_threadQ +#define _PR_CPUQ() _pr_cpuQ +#define _PR_RUNQ(_cpu) ((_cpu)->queue->runQ) +#define _PR_RUNQREADYMASK(_cpu) ((_cpu)->queue->runQReadyMask) +#define _PR_SLEEPQ(_cpu) ((_cpu)->queue->sleepQ) +#define _PR_SLEEPQMAX(_cpu) ((_cpu)->queue->sleepQmax) +#define _PR_PAUSEQ(_cpu) ((_cpu)->queue->pauseQ) +#define _PR_SUSPENDQ(_cpu) ((_cpu)->queue->suspendQ) +#define _PR_WAITINGTOJOINQ(_cpu) ((_cpu)->queue->waitingToJoinQ) + +extern PRUint32 _pr_recycleThreads; /* Flag for behavior on thread cleanup */ +extern PRLock *_pr_deadQLock; +extern PRUint32 _pr_numNativeDead; +extern PRUint32 _pr_numUserDead; +extern PRCList _pr_deadNativeQ; +extern PRCList _pr_deadUserQ; +#define _PR_DEADNATIVEQ _pr_deadNativeQ +#define _PR_DEADUSERQ _pr_deadUserQ +#define _PR_DEADQ_LOCK PR_Lock(_pr_deadQLock); +#define _PR_DEADQ_UNLOCK PR_Unlock(_pr_deadQLock); +#define _PR_INC_DEADNATIVE (_pr_numNativeDead++) +#define _PR_DEC_DEADNATIVE (_pr_numNativeDead--) +#define _PR_NUM_DEADNATIVE (_pr_numNativeDead) +#define _PR_INC_DEADUSER (_pr_numUserDead++) +#define _PR_DEC_DEADUSER (_pr_numUserDead--) +#define _PR_NUM_DEADUSER (_pr_numUserDead) + +extern PRUint32 _pr_utid; + +extern struct _PRCPU *_pr_primordialCPU; + +extern PRLock *_pr_activeLock; /* lock for userActive and systemActive */ +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 + * notifying the primordial thread + * when all other user threads + * have terminated. */ + +extern PRUintn _pr_maxPTDs; + +extern PRLock *_pr_terminationCVLock; + +/************************************************************************* +* Internal routines either called by PR itself or from machine-dependent * +* code. * +*************************************************************************/ + +extern void _PR_ClockInterrupt(void); + +extern void _PR_Schedule(void); +extern void _PR_SetThreadPriority( + PRThread* thread, PRThreadPriority priority); + +/*********************************************************************** +** 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 PRThreadStack * _PR_NewStack(PRUint32 stackSize); +extern void _PR_FreeStack(PRThreadStack *stack); +extern PRBool _PR_NotifyThread (PRThread *thread, PRThread *me); +extern void _PR_NotifyLockedThread (PRThread *thread); + +NSPR_API(void) _PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout); +NSPR_API(void) _PR_DelSleepQ(PRThread *thread, PRBool propogate_time); + +extern void _PR_AddThreadToRunQ(PRThread *me, PRThread *thread); + +NSPR_API(PRThread*) _PR_CreateThread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, + PRUint32 flags); + +extern void _PR_NativeDestroyThread(PRThread *thread); +extern void _PR_UserDestroyThread(PRThread *thread); + +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) + +NSPR_API(void) _PR_MD_INIT_CPUS(); +#define _PR_MD_INIT_CPUS _MD_INIT_CPUS + +NSPR_API(void) _PR_MD_WAKEUP_CPUS(); +#define _PR_MD_WAKEUP_CPUS _MD_WAKEUP_CPUS + +/* Interrupts related */ + +NSPR_API(void) _PR_MD_START_INTERRUPTS(void); +#define _PR_MD_START_INTERRUPTS _MD_START_INTERRUPTS + +NSPR_API(void) _PR_MD_STOP_INTERRUPTS(void); +#define _PR_MD_STOP_INTERRUPTS _MD_STOP_INTERRUPTS + +NSPR_API(void) _PR_MD_ENABLE_CLOCK_INTERRUPTS(void); +#define _PR_MD_ENABLE_CLOCK_INTERRUPTS _MD_ENABLE_CLOCK_INTERRUPTS + +NSPR_API(void) _PR_MD_DISABLE_CLOCK_INTERRUPTS(void); +#define _PR_MD_DISABLE_CLOCK_INTERRUPTS _MD_DISABLE_CLOCK_INTERRUPTS + +NSPR_API(void) _PR_MD_BLOCK_CLOCK_INTERRUPTS(void); +#define _PR_MD_BLOCK_CLOCK_INTERRUPTS _MD_BLOCK_CLOCK_INTERRUPTS + +NSPR_API(void) _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(void); +#define _PR_MD_UNBLOCK_CLOCK_INTERRUPTS _MD_UNBLOCK_CLOCK_INTERRUPTS + +/* The _PR_MD_WAIT_LOCK and _PR_MD_WAKEUP_WAITER functions put to sleep and + * awaken a thread which is waiting on a lock or cvar. + */ +extern PRStatus _PR_MD_WAIT(PRThread *, PRIntervalTime timeout); +#define _PR_MD_WAIT _MD_WAIT + +extern PRStatus _PR_MD_WAKEUP_WAITER(PRThread *); +#define _PR_MD_WAKEUP_WAITER _MD_WAKEUP_WAITER + +#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */ +NSPR_API(void) _PR_MD_CLOCK_INTERRUPT(void); +#define _PR_MD_CLOCK_INTERRUPT _MD_CLOCK_INTERRUPT +#endif + +/* Stack debugging */ +NSPR_API(void) _PR_MD_INIT_STACK(PRThreadStack *ts, PRIntn redzone); +#define _PR_MD_INIT_STACK _MD_INIT_STACK + +NSPR_API(void) _PR_MD_CLEAR_STACK(PRThreadStack* ts); +#define _PR_MD_CLEAR_STACK _MD_CLEAR_STACK + +/* CPU related */ +NSPR_API(PRInt32) _PR_MD_GET_INTSOFF(void); +#define _PR_MD_GET_INTSOFF _MD_GET_INTSOFF + +NSPR_API(void) _PR_MD_SET_INTSOFF(PRInt32 _val); +#define _PR_MD_SET_INTSOFF _MD_SET_INTSOFF + +NSPR_API(_PRCPU*) _PR_MD_CURRENT_CPU(void); +#define _PR_MD_CURRENT_CPU _MD_CURRENT_CPU + +NSPR_API(void) _PR_MD_SET_CURRENT_CPU(_PRCPU *cpu); +#define _PR_MD_SET_CURRENT_CPU _MD_SET_CURRENT_CPU + +NSPR_API(void) _PR_MD_INIT_RUNNING_CPU(_PRCPU *cpu); +#define _PR_MD_INIT_RUNNING_CPU _MD_INIT_RUNNING_CPU + +/* + * Returns the number of threads awoken or 0 if a timeout occurred; + */ +extern PRInt32 _PR_MD_PAUSE_CPU(PRIntervalTime timeout); +#define _PR_MD_PAUSE_CPU _MD_PAUSE_CPU + +extern void _PR_MD_CLEANUP_BEFORE_EXIT(void); +#define _PR_MD_CLEANUP_BEFORE_EXIT _MD_CLEANUP_BEFORE_EXIT + +extern void _PR_MD_EXIT(PRIntn status); +#define _PR_MD_EXIT _MD_EXIT + +/* Locks related */ + +NSPR_API(void) _PR_MD_INIT_LOCKS(void); +#define _PR_MD_INIT_LOCKS _MD_INIT_LOCKS + +NSPR_API(PRStatus) _PR_MD_NEW_LOCK(_MDLock *md); +#define _PR_MD_NEW_LOCK _MD_NEW_LOCK + +NSPR_API(void) _PR_MD_FREE_LOCK(_MDLock *md); +#define _PR_MD_FREE_LOCK _MD_FREE_LOCK + +NSPR_API(void) _PR_MD_LOCK(_MDLock *md); +#define _PR_MD_LOCK _MD_LOCK + +/* Return 0 on success, a nonzero value on failure. */ +NSPR_API(PRIntn) _PR_MD_TEST_AND_LOCK(_MDLock *md); +#define _PR_MD_TEST_AND_LOCK _MD_TEST_AND_LOCK + +NSPR_API(void) _PR_MD_UNLOCK(_MDLock *md); +#define _PR_MD_UNLOCK _MD_UNLOCK + +NSPR_API(void) _PR_MD_IOQ_LOCK(void); +#define _PR_MD_IOQ_LOCK _MD_IOQ_LOCK + +NSPR_API(void) _PR_MD_IOQ_UNLOCK(void); +#define _PR_MD_IOQ_UNLOCK _MD_IOQ_UNLOCK + +#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */ +/* Semaphore related -- only for native threads */ +#ifdef HAVE_CVAR_BUILT_ON_SEM +NSPR_API(void) _PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value); +#define _PR_MD_NEW_SEM _MD_NEW_SEM + +NSPR_API(void) _PR_MD_DESTROY_SEM(_MDSemaphore *md); +#define _PR_MD_DESTROY_SEM _MD_DESTROY_SEM + +NSPR_API(PRStatus) _PR_MD_TIMED_WAIT_SEM( + _MDSemaphore *md, PRIntervalTime timeout); +#define _PR_MD_TIMED_WAIT_SEM _MD_TIMED_WAIT_SEM + +NSPR_API(PRStatus) _PR_MD_WAIT_SEM(_MDSemaphore *md); +#define _PR_MD_WAIT_SEM _MD_WAIT_SEM + +NSPR_API(void) _PR_MD_POST_SEM(_MDSemaphore *md); +#define _PR_MD_POST_SEM _MD_POST_SEM +#endif /* HAVE_CVAR_BUILT_ON_SEM */ + +#endif + +/* Condition Variables related -- only for native threads */ + +#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */ +NSPR_API(PRInt32) _PR_MD_NEW_CV(_MDCVar *md); +#define _PR_MD_NEW_CV _MD_NEW_CV + +NSPR_API(void) _PR_MD_FREE_CV(_MDCVar *md); +#define _PR_MD_FREE_CV _MD_FREE_CV + +NSPR_API(void) _PR_MD_WAIT_CV( + _MDCVar *mdCVar,_MDLock *mdLock,PRIntervalTime timeout); +#define _PR_MD_WAIT_CV _MD_WAIT_CV + +NSPR_API(void) _PR_MD_NOTIFY_CV(_MDCVar *md, _MDLock *lock); +#define _PR_MD_NOTIFY_CV _MD_NOTIFY_CV + +NSPR_API(void) _PR_MD_NOTIFYALL_CV(_MDCVar *md, _MDLock *lock); +#define _PR_MD_NOTIFYALL_CV _MD_NOTIFYALL_CV +#endif /* _PR_LOCAL_THREADS_ONLY */ + +/* Threads related */ +NSPR_API(PRThread*) _PR_MD_CURRENT_THREAD(void); +#define _PR_MD_CURRENT_THREAD _MD_CURRENT_THREAD + +NSPR_API(PRThread*) _PR_MD_GET_ATTACHED_THREAD(void); +#define _PR_MD_GET_ATTACHED_THREAD _MD_GET_ATTACHED_THREAD + +NSPR_API(PRThread*) _PR_MD_LAST_THREAD(void); +#define _PR_MD_LAST_THREAD _MD_LAST_THREAD + +NSPR_API(void) _PR_MD_SET_CURRENT_THREAD(PRThread *thread); +#define _PR_MD_SET_CURRENT_THREAD _MD_SET_CURRENT_THREAD + +NSPR_API(void) _PR_MD_SET_LAST_THREAD(PRThread *thread); +#define _PR_MD_SET_LAST_THREAD _MD_SET_LAST_THREAD + +extern PRStatus _PR_MD_INIT_THREAD(PRThread *thread); +#define _PR_MD_INIT_THREAD _MD_INIT_THREAD + +extern void _PR_MD_EXIT_THREAD(PRThread *thread); +#define _PR_MD_EXIT_THREAD _MD_EXIT_THREAD + +#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */ + +NSPR_API(PRStatus) _PR_MD_INIT_ATTACHED_THREAD(PRThread *thread); +#define _PR_MD_INIT_ATTACHED_THREAD _MD_INIT_ATTACHED_THREAD + +extern void _PR_MD_SUSPEND_THREAD(PRThread *thread); +#define _PR_MD_SUSPEND_THREAD _MD_SUSPEND_THREAD + +extern void _PR_MD_RESUME_THREAD(PRThread *thread); +#define _PR_MD_RESUME_THREAD _MD_RESUME_THREAD + +extern void _PR_MD_SUSPEND_CPU(_PRCPU *cpu); +#define _PR_MD_SUSPEND_CPU _MD_SUSPEND_CPU + +extern void _PR_MD_RESUME_CPU(_PRCPU *cpu); +#define _PR_MD_RESUME_CPU _MD_RESUME_CPU + +extern void _PR_MD_BEGIN_SUSPEND_ALL(void); +#define _PR_MD_BEGIN_SUSPEND_ALL _MD_BEGIN_SUSPEND_ALL + +extern void _PR_MD_END_SUSPEND_ALL(void); +#define _PR_MD_END_SUSPEND_ALL _MD_END_SUSPEND_ALL + +extern void _PR_MD_BEGIN_RESUME_ALL(void); +#define _PR_MD_BEGIN_RESUME_ALL _MD_BEGIN_RESUME_ALL + +extern void _PR_MD_END_RESUME_ALL(void); +#define _PR_MD_END_RESUME_ALL _MD_END_RESUME_ALL + +#if defined(IRIX) +NSPR_API(void) _PR_IRIX_CHILD_PROCESS(void); +#endif /* IRIX */ + +#endif /* !_PR_LOCAL_THREADS_ONLY */ + +extern void _PR_MD_CLEAN_THREAD(PRThread *thread); +#define _PR_MD_CLEAN_THREAD _MD_CLEAN_THREAD + +#ifdef HAVE_CUSTOM_USER_THREADS +extern void _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(PRThread *); +#define _PR_MD_CREATE_PRIMORDIAL_USER_THREAD _MD_CREATE_PRIMORDIAL_USER_THREAD + +extern PRThread* _PR_MD_CREATE_USER_THREAD( + PRUint32 stacksize, + void (*start)(void *), + void *arg); +#define _PR_MD_CREATE_USER_THREAD _MD_CREATE_USER_THREAD +#endif + +extern PRStatus _PR_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +#define _PR_MD_CREATE_THREAD _MD_CREATE_THREAD + +extern void _PR_MD_JOIN_THREAD(_MDThread *md); +#define _PR_MD_JOIN_THREAD _MD_JOIN_THREAD + +extern void _PR_MD_END_THREAD(void); +#define _PR_MD_END_THREAD _MD_END_THREAD + +extern void _PR_MD_YIELD(void); +#define _PR_MD_YIELD _MD_YIELD + +extern void _PR_MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri); +#define _PR_MD_SET_PRIORITY _MD_SET_PRIORITY + +NSPR_API(void) _PR_MD_SUSPENDALL(void); +#define _PR_MD_SUSPENDALL _MD_SUSPENDALL + +NSPR_API(void) _PR_MD_RESUMEALL(void); +#define _PR_MD_RESUMEALL _MD_RESUMEALL + +extern void _PR_MD_INIT_CONTEXT( + PRThread *thread, char *top, void (*start) (void), PRBool *status); +#define _PR_MD_INIT_CONTEXT _MD_INIT_CONTEXT + +extern void _PR_MD_SWITCH_CONTEXT(PRThread *thread); +#define _PR_MD_SWITCH_CONTEXT _MD_SWITCH_CONTEXT + +extern void _PR_MD_RESTORE_CONTEXT(PRThread *thread); +#define _PR_MD_RESTORE_CONTEXT _MD_RESTORE_CONTEXT + +/* Segment related */ +extern void _PR_MD_INIT_SEGS(void); +#define _PR_MD_INIT_SEGS _MD_INIT_SEGS + +extern PRStatus _PR_MD_ALLOC_SEGMENT(PRSegment *seg, PRUint32 size, void *vaddr); +#define _PR_MD_ALLOC_SEGMENT _MD_ALLOC_SEGMENT + +extern void _PR_MD_FREE_SEGMENT(PRSegment *seg); +#define _PR_MD_FREE_SEGMENT _MD_FREE_SEGMENT + +/* Directory enumeration related */ +extern PRStatus _PR_MD_OPEN_DIR(_MDDir *md,const char *name); +#define _PR_MD_OPEN_DIR _MD_OPEN_DIR + +extern char * _PR_MD_READ_DIR(_MDDir *md, PRIntn flags); +#define _PR_MD_READ_DIR _MD_READ_DIR + +extern PRInt32 _PR_MD_CLOSE_DIR(_MDDir *md); +#define _PR_MD_CLOSE_DIR _MD_CLOSE_DIR + +/* Named semaphores related */ +extern PRSem * _PR_MD_OPEN_SEMAPHORE( + const char *osname, PRIntn flags, PRIntn mode, PRUintn value); +#define _PR_MD_OPEN_SEMAPHORE _MD_OPEN_SEMAPHORE + +extern PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem); +#define _PR_MD_WAIT_SEMAPHORE _MD_WAIT_SEMAPHORE + +extern PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem); +#define _PR_MD_POST_SEMAPHORE _MD_POST_SEMAPHORE + +extern PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem); +#define _PR_MD_CLOSE_SEMAPHORE _MD_CLOSE_SEMAPHORE + +extern PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname); +#define _PR_MD_DELETE_SEMAPHORE _MD_DELETE_SEMAPHORE + +/* I/O related */ +extern void _PR_MD_INIT_FILEDESC(PRFileDesc *fd); +#define _PR_MD_INIT_FILEDESC _MD_INIT_FILEDESC + +#ifdef XP_MAC +extern void _PR_MD_FREE_FILEDESC(PRFileDesc *fd); +#define _PR_MD_FREE_FILEDESC _MD_FREE_FILEDESC +#endif + +extern void _PR_MD_MAKE_NONBLOCK(PRFileDesc *fd); +#define _PR_MD_MAKE_NONBLOCK _MD_MAKE_NONBLOCK + +/* File I/O related */ +extern PROsfd _PR_MD_OPEN(const char *name, PRIntn osflags, PRIntn mode); +#define _PR_MD_OPEN _MD_OPEN + +extern PROsfd _PR_MD_OPEN_FILE(const char *name, PRIntn osflags, PRIntn mode); +#define _PR_MD_OPEN_FILE _MD_OPEN_FILE + +extern PRInt32 _PR_MD_CLOSE_FILE(PROsfd osfd); +#define _PR_MD_CLOSE_FILE _MD_CLOSE_FILE + +extern PRInt32 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 amount); +#define _PR_MD_READ _MD_READ + +extern PRInt32 _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 amount); +#define _PR_MD_WRITE _MD_WRITE + +extern PRInt32 _PR_MD_WRITEV( + PRFileDesc *fd, const struct PRIOVec *iov, + PRInt32 iov_size, PRIntervalTime timeout); +#define _PR_MD_WRITEV _MD_WRITEV + +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_RENAME(const char *from, const char *to); +#define _PR_MD_RENAME _MD_RENAME + +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); +#define _PR_MD_STAT _MD_STAT + +extern PRInt32 _PR_MD_MKDIR(const char *name, PRIntn mode); +#define _PR_MD_MKDIR _MD_MKDIR + +extern PRInt32 _PR_MD_MAKE_DIR(const char *name, PRIntn mode); +#define _PR_MD_MAKE_DIR _MD_MAKE_DIR + +extern PRInt32 _PR_MD_RMDIR(const char *name); +#define _PR_MD_RMDIR _MD_RMDIR + +#ifdef MOZ_UNICODE +/* UTF16 File I/O related */ +extern PRStatus _PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *md, const PRUnichar *name); +#define _PR_MD_OPEN_DIR_UTF16 _MD_OPEN_DIR_UTF16 + +extern PROsfd _PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, PRIntn mode); +#define _PR_MD_OPEN_FILE_UTF16 _MD_OPEN_FILE_UTF16 + +extern PRUnichar * _PR_MD_READ_DIR_UTF16(_MDDirUTF16 *md, PRIntn flags); +#define _PR_MD_READ_DIR_UTF16 _MD_READ_DIR_UTF16 + +extern PRInt32 _PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *md); +#define _PR_MD_CLOSE_DIR_UTF16 _MD_CLOSE_DIR_UTF16 + +extern PRInt32 _PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info); +#define _PR_MD_GETFILEINFO64_UTF16 _MD_GETFILEINFO64_UTF16 +#endif /* MOZ_UNICODE */ + +/* Socket I/O related */ +extern void _PR_MD_INIT_IO(void); +#define _PR_MD_INIT_IO _MD_INIT_IO + +extern PRInt32 _PR_MD_CLOSE_SOCKET(PROsfd osfd); +#define _PR_MD_CLOSE_SOCKET _MD_CLOSE_SOCKET + +extern PRInt32 _PR_MD_CONNECT( + PRFileDesc *fd, const PRNetAddr *addr, + PRUint32 addrlen, PRIntervalTime timeout); +#define _PR_MD_CONNECT _MD_CONNECT + +extern PROsfd _PR_MD_ACCEPT( + PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen, PRIntervalTime timeout); +#define _PR_MD_ACCEPT _MD_ACCEPT + +extern PRInt32 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen); +#define _PR_MD_BIND _MD_BIND + +extern PRInt32 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog); +#define _PR_MD_LISTEN _MD_LISTEN + +extern PRInt32 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how); +#define _PR_MD_SHUTDOWN _MD_SHUTDOWN + +extern PRInt32 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +#define _PR_MD_RECV _MD_RECV + +extern PRInt32 _PR_MD_SEND( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout); +#define _PR_MD_SEND _MD_SEND + +extern PRInt32 _PR_MD_ACCEPT_READ(PRFileDesc *sd, PROsfd *newSock, + PRNetAddr **raddr, void *buf, PRInt32 amount, + PRIntervalTime timeout); +#define _PR_MD_ACCEPT_READ _MD_ACCEPT_READ + +#ifdef WIN32 +extern PROsfd _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen, PRIntervalTime timeout, + PRBool fast, + _PR_AcceptTimeoutCallback callback, + void *callbackArg); + +extern PRInt32 _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PROsfd *newSock, + PRNetAddr **raddr, void *buf, PRInt32 amount, + PRIntervalTime timeout, PRBool fast, + _PR_AcceptTimeoutCallback callback, + void *callbackArg); + +extern void _PR_MD_UPDATE_ACCEPT_CONTEXT(PROsfd s, PROsfd ls); +#define _PR_MD_UPDATE_ACCEPT_CONTEXT _MD_UPDATE_ACCEPT_CONTEXT +#endif /* WIN32 */ + +extern PRInt32 _PR_MD_SENDFILE( + PRFileDesc *sock, PRSendFileData *sfd, + PRInt32 flags, PRIntervalTime timeout); +#define _PR_MD_SENDFILE _MD_SENDFILE + +extern PRStatus _PR_MD_GETSOCKNAME( + PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen); +#define _PR_MD_GETSOCKNAME _MD_GETSOCKNAME + +extern PRStatus _PR_MD_GETPEERNAME( + PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen); +#define _PR_MD_GETPEERNAME _MD_GETPEERNAME + +extern PRStatus _PR_MD_GETSOCKOPT( + PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen); +#define _PR_MD_GETSOCKOPT _MD_GETSOCKOPT + +extern PRStatus _PR_MD_SETSOCKOPT( + PRFileDesc *fd, PRInt32 level, PRInt32 optname, + const char* optval, PRInt32 optlen); +#define _PR_MD_SETSOCKOPT _MD_SETSOCKOPT + +extern PRStatus PR_CALLBACK _PR_SocketGetSocketOption( + PRFileDesc *fd, PRSocketOptionData *data); + +extern PRStatus PR_CALLBACK _PR_SocketSetSocketOption( + PRFileDesc *fd, const PRSocketOptionData *data); + +extern PRInt32 _PR_MD_RECVFROM( + PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout); +#define _PR_MD_RECVFROM _MD_RECVFROM + +extern PRInt32 _PR_MD_SENDTO( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout); +#define _PR_MD_SENDTO _MD_SENDTO + +extern PRInt32 _PR_MD_SOCKETPAIR(int af, int type, int flags, PROsfd *osfd); +#define _PR_MD_SOCKETPAIR _MD_SOCKETPAIR + +extern PROsfd _PR_MD_SOCKET(int af, int type, int flags); +#define _PR_MD_SOCKET _MD_SOCKET + +extern PRInt32 _PR_MD_SOCKETAVAILABLE(PRFileDesc *fd); +#define _PR_MD_SOCKETAVAILABLE _MD_SOCKETAVAILABLE + +extern PRInt32 _PR_MD_PIPEAVAILABLE(PRFileDesc *fd); +#define _PR_MD_PIPEAVAILABLE _MD_PIPEAVAILABLE + +extern PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, + PRIntervalTime timeout); +#define _PR_MD_PR_POLL _MD_PR_POLL + +/* + * Initialize fd->secret->inheritable for a newly created fd. + * If 'imported' is false, the osfd (i.e., fd->secret->md.osfd) + * was created by NSPR and hence has the OS-dependent default + * inheritable attribute. If 'imported' is true, the osfd was + * not created by NSPR and hence a system call is required to + * query its inheritable attribute. Since we may never need to + * know the inheritable attribute of a fd, a platform may choose + * to initialize fd->secret->inheritable of an imported fd to + * _PR_TRI_UNKNOWN and only pay the cost of the system call + * (in _PR_MD_QUERY_FD_INHERITABLE) when necessary. + */ +extern void _PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported); +#define _PR_MD_INIT_FD_INHERITABLE _MD_INIT_FD_INHERITABLE + +extern PRStatus _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable); +#define _PR_MD_SET_FD_INHERITABLE _MD_SET_FD_INHERITABLE + + +#define _PR_PROCESS_TIMEOUT_INTERRUPT_ERRORS(me) \ + if (_PR_PENDING_INTERRUPT(me)) { \ + me->flags &= ~_PR_INTERRUPT; \ + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); \ + } else { \ + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); \ + } + +extern void *_PR_MD_GET_SP(PRThread *thread); +#define _PR_MD_GET_SP _MD_GET_SP + +#endif /* defined(_PR_PTHREADS) */ + +/************************************************************************/ +/************************************************************************* +** The remainder of the definitions are shared by pthreads and the classic +** NSPR code. These too may be conditionalized. +*************************************************************************/ +/************************************************************************/ + +extern PROffset32 _PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence); +#define _PR_MD_LSEEK _MD_LSEEK + +extern PROffset64 _PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 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; + +/* +** The PR_NETADDR_SIZE macro can only be called on a PRNetAddr union +** whose 'family' field is set. It returns the size of the union +** member corresponding to the specified address family. +*/ + +extern PRUintn _PR_NetAddrSize(const PRNetAddr* addr); + +#if defined(_PR_INET6) + +#define PR_NETADDR_SIZE(_addr) _PR_NetAddrSize(_addr) + +#elif defined(_PR_HAVE_MD_SOCKADDR_IN6) + +/* +** Under the following conditions: +** 1. _PR_INET6 is not defined; +** 2. _PR_INET6_PROBE is defined; +** 3. struct sockaddr_in6 has nonstandard fields at the end +** (e.g., on Solaris 8), +** (_addr)->ipv6 is smaller than struct sockaddr_in6, and +** hence we can't pass sizeof((_addr)->ipv6) to socket +** functions such as connect because they would fail with +** EINVAL. +** +** To pass the correct socket address length to socket +** functions, define the macro _PR_HAVE_MD_SOCKADDR_IN6 and +** define struct _md_sockaddr_in6 to be isomorphic to +** struct sockaddr_in6. +*/ + +#if defined(XP_UNIX) || defined(XP_OS2_EMX) +#define PR_NETADDR_SIZE(_addr) \ + ((_addr)->raw.family == PR_AF_INET \ + ? sizeof((_addr)->inet) \ + : ((_addr)->raw.family == PR_AF_INET6 \ + ? sizeof(struct _md_sockaddr_in6) \ + : sizeof((_addr)->local))) +#else +#define PR_NETADDR_SIZE(_addr) \ + ((_addr)->raw.family == PR_AF_INET \ + ? sizeof((_addr)->inet) \ + : sizeof(struct _md_sockaddr_in6)) +#endif /* defined(XP_UNIX) */ + +#else + +#if defined(XP_UNIX) || defined(XP_OS2_EMX) +#define PR_NETADDR_SIZE(_addr) \ + ((_addr)->raw.family == PR_AF_INET \ + ? sizeof((_addr)->inet) \ + : ((_addr)->raw.family == PR_AF_INET6 \ + ? sizeof((_addr)->ipv6) \ + : sizeof((_addr)->local))) +#else +#define PR_NETADDR_SIZE(_addr) \ + ((_addr)->raw.family == PR_AF_INET \ + ? sizeof((_addr)->inet) \ + : sizeof((_addr)->ipv6)) +#endif /* defined(XP_UNIX) */ + +#endif /* defined(_PR_INET6) */ + +extern PRStatus _PR_MapOptionName( + PRSockOption optname, PRInt32 *level, PRInt32 *name); +extern void _PR_InitThreads( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs); + +struct PRLock { +#if defined(_PR_PTHREADS) + pthread_mutex_t mutex; /* the underlying lock */ + _PT_Notified notified; /* array of conditions notified */ + PRBool locked; /* whether the mutex is locked */ + pthread_t owner; /* if locked, current lock owner */ +#elif defined(_PR_BTHREADS) + sem_id semaphoreID; /* the underlying lock */ + int32 benaphoreCount; /* number of people in lock */ + thread_id owner; /* current lock owner */ +#else /* not pthreads or Be threads */ + PRCList links; /* linkage for PRThread.lockList */ + struct PRThread *owner; /* current lock owner */ + PRCList waitQ; /* list of threads waiting for lock */ + PRThreadPriority priority; /* priority of lock */ + PRThreadPriority boostPriority; /* boosted priority of lock owner */ + _MDLock ilock; /* Internal Lock to protect user-level fields */ +#endif +}; + +extern void _PR_InitLocks(void); + +struct PRCondVar { + PRLock *lock; /* associated lock that protects the condition */ +#if defined(_PR_PTHREADS) + pthread_cond_t cv; /* underlying pthreads condition */ + PRInt32 notify_pending; /* CV has destroy pending notification */ +#elif defined(_PR_BTHREADS) + sem_id sem; /* the underlying lock */ + sem_id handshakeSem; /* the lock for 'notify'-threads waiting for confirmation */ + sem_id signalSem; /* the lock for threads waiting for someone to notify */ + volatile int32 nw; /* the number waiting */ + volatile int32 ns; /* the number signalling */ + long signalBenCount; /* the number waiting on the underlying sem */ +#else /* not pthreads or Be threads */ + PRCList condQ; /* Condition variable wait Q */ + _MDLock ilock; /* Internal Lock to protect condQ */ + _MDCVar md; +#endif +}; + +/************************************************************************/ + +struct PRMonitor { + const char* name; /* monitor name for debugging */ +#if defined(_PR_PTHREADS) + PRLock lock; /* the lock structure */ + pthread_t owner; /* the owner of the lock or invalid */ + PRCondVar *cvar; /* condition variable queue */ +#else /* defined(_PR_PTHREADS) */ + PRCondVar *cvar; /* associated lock and condition variable queue */ +#endif /* defined(_PR_PTHREADS) */ + PRUint32 entryCount; /* # of times re-entered */ +}; + +/************************************************************************/ + +struct PRSemaphore { +#if defined(_PR_BTHREADS) + sem_id sem; + int32 benaphoreCount; +#else + PRCondVar *cvar; /* associated lock and condition variable queue */ + PRUintn count; /* the value of the counting semaphore */ + PRUint32 waiters; /* threads waiting on the semaphore */ +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + _MDSemaphore md; +#endif /* defined(_PR_PTHREADS) */ +#endif /* defined(_PR_BTHREADS) */ +}; + +NSPR_API(void) _PR_InitSem(void); + +/*************************************************************************/ + +struct PRSem { +#ifdef _PR_HAVE_POSIX_SEMAPHORES + sem_t *sem; +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) + int semid; +#elif defined(WIN32) + HANDLE sem; +#else + PRInt8 notused; +#endif +}; + +/*************************************************************************/ + +struct PRStackStr { + /* head MUST be at offset 0; assembly language code relies on this */ +#if defined(AIX) + volatile PRStackElem prstk_head; +#else + PRStackElem prstk_head; +#endif + + PRLock *prstk_lock; + char *prstk_name; +}; + +/************************************************************************/ + +/* XXX this needs to be exported (sigh) */ +struct PRThreadStack { + PRCList links; + PRUintn flags; + + char *allocBase; /* base of stack's allocated memory */ + PRUint32 allocSize; /* size of stack's allocated memory */ + char *stackBottom; /* bottom of stack from C's point of view */ + char *stackTop; /* top of stack from C's point of view */ + PRUint32 stackSize; /* size of usable portion of the stack */ + + PRSegment *seg; + PRThread* thr; /* back pointer to thread owning this stack */ + +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + _MDThreadStack md; +#endif /* defined(_PR_PTHREADS) */ +}; + +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 */ + + void *arg; /* argument to the client's entry point */ + _PRStartFn startFunc; /* the root of the client's thread */ + + PRThreadStack *stack; /* info about thread's stack (for GC) */ + void *environment; /* pointer to execution environment */ + + 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 */ + PRErrorCode errorCode; /* current NSPR error code | zero */ + PRInt32 osErrorCode; /* mapping of errorCode | zero */ + PRIntn errorStringLength; /* textLength from last call to PR_SetErrorText() */ + PRInt32 errorStringSize; /* malloc()'d size of buffer | 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? */ + PRCondVar *waiting; /* where the thread is waiting | NULL */ + void *sp; /* recorded sp for garbage collection */ + PRThread *next, *prev; /* simple linked list of all threads */ + PRUint32 suspend; /* used to store suspend and resume flags */ +#ifdef PT_NO_SIGTIMEDWAIT + pthread_mutex_t suspendResumeMutex; + pthread_cond_t suspendResumeCV; +#endif + PRUint32 interrupt_blocked; /* interrupt blocked */ + struct pollfd *syspoll_list; /* Unix polling list used by PR_Poll */ + PRUint32 syspoll_count; /* number of elements in syspoll_list */ +#if defined(_PR_POLL_WITH_SELECT) + int *selectfd_list; /* Unix fd's that PR_Poll selects on */ + PRUint32 selectfd_count; /* number of elements in selectfd_list */ +#endif +#elif defined(_PR_BTHREADS) + PRUint32 flags; + _MDThread md; + PRBool io_pending; + PRInt32 io_fd; + PRBool io_suspended; +#else /* not pthreads or Be threads */ + _MDLock threadLock; /* Lock to protect thread state variables. + * Protects the following fields: + * state + * priority + * links + * wait + * cpu + */ + PRUint32 queueCount; + PRUint32 waitCount; + + PRCList active; /* on list of all active threads */ + PRCList links; + PRCList waitQLinks; /* when thread is PR_Wait'ing */ + PRCList lockList; /* list of locks currently holding */ + PRIntervalTime sleep; /* sleep time when thread is sleeping */ + struct _wait { + struct PRLock *lock; + struct PRCondVar *cvar; + } wait; + + PRUint32 id; + PRUint32 flags; + 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. + */ + + /* thread termination condition variable for join */ + PRCondVar *term; + + _PRCPU *cpu; /* cpu to which this thread is bound */ + PRUint32 threadAllocatedOnStack;/* boolean */ + + /* When an async IO is in progress and a second async IO cannot be + * initiated, the io_pending flag is set to true. Some platforms will + * not use the io_pending flag. If the io_pending flag is true, then + * io_fd is the OS-file descriptor on which IO is pending. + */ + PRBool io_pending; + PRInt32 io_fd; + + /* If a timeout occurs or if an outstanding IO is interrupted and the + * OS doesn't support a real cancellation (NT or MAC), then the + * io_suspended flag will be set to true. The thread will be resumed + * but may run into trouble issuing additional IOs until the io_pending + * flag can be cleared + */ + PRBool io_suspended; + + _MDThread md; +#endif +}; + +struct PRProcessAttr { + PRFileDesc *stdinFd; + PRFileDesc *stdoutFd; + PRFileDesc *stderrFd; + char *currentDirectory; + char *fdInheritBuffer; + PRSize fdInheritBufferSize; + PRSize fdInheritBufferUsed; +}; + +struct PRProcess { + _MDProcess md; +}; + +struct PRFileMap { + PRFileDesc *fd; + PRFileMapProtect prot; + _MDFileMap md; +}; + +/************************************************************************/ + +/* +** 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... */ +#define _PR_FILEDESC_FREED 0x11111111 + +/* +** A boolean type with an additional "unknown" state +*/ + +typedef enum { + _PR_TRI_TRUE = 1, + _PR_TRI_FALSE = 0, + _PR_TRI_UNKNOWN = -1 +} _PRTriStateBool; + +struct PRFilePrivate { + PRInt32 state; + PRBool nonblocking; + _PRTriStateBool inheritable; + PRFileDesc *next; + PRIntn lockCount; /* 0: not locked + * -1: a native lockfile call is in progress + * > 0: # times the file is locked */ +#ifdef _PR_HAVE_PEEK_BUFFER + char *peekBuffer; + PRInt32 peekBufSize; + PRInt32 peekBytes; +#endif +#if !defined(_PR_HAVE_O_APPEND) + PRBool appendMode; /* Some platforms don't have O_APPEND or its + * equivalent, so they have to seek to end of + * file on write if the file was opened in + * append mode. See Bugzilla 4090, 276330. */ +#endif + _MDFileDesc md; +#ifdef _PR_NEED_SECRET_AF + PRUint16 af; /* If the platform's implementation of accept() + * requires knowing the address family of the + * socket, we save the address family here. */ +#endif +}; + +#ifdef _WIN64 +#define PR_PRIdOSFD "lld" /* for printing PROsfd */ +#define PR_PRIxOSFD "llx" +#define PR_SCNdOSFD "lld" /* for scanning PROsfd */ +#define PR_SCNxOSFD "llx" +#else +#define PR_PRIdOSFD "ld" /* for printing PROsfd */ +#define PR_PRIxOSFD "lx" +#define PR_SCNdOSFD "ld" /* for scanning PROsfd */ +#define PR_SCNxOSFD "lx" +#endif + +struct PRDir { + PRDirEntry d; + _MDDir md; +}; + +#ifdef MOZ_UNICODE +struct PRDirUTF16 { + PRDirEntry d; + _MDDirUTF16 md; +}; +#endif /* MOZ_UNICODE */ + +extern void _PR_InitSegs(void); +extern void _PR_InitStacks(void); +extern void _PR_InitTPD(void); +extern void _PR_InitMem(void); +extern void _PR_InitEnv(void); +extern void _PR_InitCMon(void); +extern void _PR_InitIO(void); +extern void _PR_InitLog(void); +extern void _PR_InitNet(void); +extern void _PR_InitClock(void); +extern void _PR_InitLinker(void); +extern void _PR_InitAtomic(void); +extern void _PR_InitCPUs(void); +extern void _PR_InitDtoa(void); +extern void _PR_InitTime(void); +extern void _PR_InitMW(void); +extern void _PR_InitRWLocks(void); +extern void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me); +extern void _PR_CleanupThread(PRThread *thread); +extern void _PR_CleanupCallOnce(void); +extern void _PR_CleanupMW(void); +extern void _PR_CleanupTime(void); +extern void _PR_CleanupDtoa(void); +extern void _PR_ShutdownLinker(void); +extern void _PR_CleanupEnv(void); +extern void _PR_CleanupIO(void); +extern void _PR_CleanupCMon(void); +extern void _PR_CleanupNet(void); +extern void _PR_CleanupLayerCache(void); +extern void _PR_CleanupStacks(void); +#ifdef WINNT +extern void _PR_CleanupCPUs(void); +#endif +extern void _PR_CleanupThreads(void); +extern void _PR_CleanupTPD(void); +extern void _PR_Cleanup(void); +extern void _PR_LogCleanup(void); +extern void _PR_InitLayerCache(void); +#ifdef GC_LEAK_DETECTOR +extern void _PR_InitGarbageCollector(void); +#endif + +extern PRBool _pr_initialized; +extern void _PR_ImplicitInitialization(void); +extern PRBool _PR_Obsolete(const char *obsolete, const char *preferred); + +/************************************************************************/ + +struct PRSegment { + void *vaddr; + PRUint32 size; + PRUintn flags; +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + _MDSegment md; +#endif /* defined(_PR_PTHREADS) */ +}; + +/* PRSegment.flags */ +#define _PR_SEG_VM 0x1 + +/************************************************************************/ + +extern PRInt32 _pr_pageSize; +extern PRInt32 _pr_pageShift; + +extern PRLogModuleInfo *_pr_clock_lm; +extern PRLogModuleInfo *_pr_cmon_lm; +extern PRLogModuleInfo *_pr_io_lm; +extern PRLogModuleInfo *_pr_cvar_lm; +extern PRLogModuleInfo *_pr_mon_lm; +extern PRLogModuleInfo *_pr_linker_lm; +extern PRLogModuleInfo *_pr_sched_lm; +extern PRLogModuleInfo *_pr_thread_lm; +extern PRLogModuleInfo *_pr_gc_lm; + +extern PRFileDesc *_pr_stdin; +extern PRFileDesc *_pr_stdout; +extern PRFileDesc *_pr_stderr; + +/* Zone allocator */ +/* +** The zone allocator code has hardcoded pthread types and +** functions, so it can only be used in the pthreads version. +** This can be fixed by replacing the hardcoded pthread types +** and functions with macros that expand to the native thread +** types and functions on each platform. +*/ +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#define _PR_ZONE_ALLOCATOR +#endif + +#ifdef _PR_ZONE_ALLOCATOR +extern void _PR_InitZones(void); +extern void _PR_DestroyZones(void); +#endif + +/* Overriding malloc, free, etc. */ +#if !defined(_PR_NO_PREEMPT) && defined(XP_UNIX) \ + && !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY) \ + && !defined(PURIFY) \ + && !defined(DARWIN) \ + && !defined(NEXTSTEP) \ + && !defined(QNX) \ + && !(defined (UNIXWARE) && defined (USE_SVR4_THREADS)) +#define _PR_OVERRIDE_MALLOC +#endif + +/************************************************************************* +* External machine-dependent code provided by each OS. * * +*************************************************************************/ + +/* Initialization related */ +extern void _PR_MD_EARLY_INIT(void); +#define _PR_MD_EARLY_INIT _MD_EARLY_INIT + +extern void _PR_MD_INTERVAL_INIT(void); +#define _PR_MD_INTERVAL_INIT _MD_INTERVAL_INIT + +NSPR_API(void) _PR_MD_FINAL_INIT(void); +#define _PR_MD_FINAL_INIT _MD_FINAL_INIT + +/* Process control */ + +extern PRProcess * _PR_MD_CREATE_PROCESS( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); +#define _PR_MD_CREATE_PROCESS _MD_CREATE_PROCESS + +extern PRStatus _PR_MD_DETACH_PROCESS(PRProcess *process); +#define _PR_MD_DETACH_PROCESS _MD_DETACH_PROCESS + +extern PRStatus _PR_MD_WAIT_PROCESS(PRProcess *process, PRInt32 *exitCode); +#define _PR_MD_WAIT_PROCESS _MD_WAIT_PROCESS + +extern PRStatus _PR_MD_KILL_PROCESS(PRProcess *process); +#define _PR_MD_KILL_PROCESS _MD_KILL_PROCESS + +/* Current Time */ +NSPR_API(PRTime) _PR_MD_NOW(void); +#define _PR_MD_NOW _MD_NOW + +/* Environment related */ +extern char* _PR_MD_GET_ENV(const char *name); +#define _PR_MD_GET_ENV _MD_GET_ENV + +extern PRIntn _PR_MD_PUT_ENV(const char *name); +#define _PR_MD_PUT_ENV _MD_PUT_ENV + +/* Atomic operations */ + +extern void _PR_MD_INIT_ATOMIC(void); +#define _PR_MD_INIT_ATOMIC _MD_INIT_ATOMIC + +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 + +extern PRInt32 _PR_MD_ATOMIC_SET(PRInt32 *, PRInt32); +#define _PR_MD_ATOMIC_SET _MD_ATOMIC_SET + +/* Garbage collection */ + +/* +** Save the registers that the GC would find interesting into the thread +** "t". isCurrent will be non-zero if the thread state that is being +** saved is the currently executing thread. Return the address of the +** first register to be scanned as well as the number of registers to +** scan in "np". +** +** If "isCurrent" is non-zero then it is allowed for the thread context +** area to be used as scratch storage to hold just the registers +** necessary for scanning. +*/ +extern PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np); + +/* Time intervals */ + +extern PRIntervalTime _PR_MD_GET_INTERVAL(void); +#define _PR_MD_GET_INTERVAL _MD_GET_INTERVAL + +extern PRIntervalTime _PR_MD_INTERVAL_PER_SEC(void); +#define _PR_MD_INTERVAL_PER_SEC _MD_INTERVAL_PER_SEC + +/* Affinity masks */ + +extern PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ); +#define _PR_MD_SETTHREADAFFINITYMASK _MD_SETTHREADAFFINITYMASK + +extern PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask); +#define _PR_MD_GETTHREADAFFINITYMASK _MD_GETTHREADAFFINITYMASK + +/* File locking */ + +extern PRStatus _PR_MD_LOCKFILE(PROsfd osfd); +#define _PR_MD_LOCKFILE _MD_LOCKFILE + +extern PRStatus _PR_MD_TLOCKFILE(PROsfd osfd); +#define _PR_MD_TLOCKFILE _MD_TLOCKFILE + +extern PRStatus _PR_MD_UNLOCKFILE(PROsfd osfd); +#define _PR_MD_UNLOCKFILE _MD_UNLOCKFILE + +/* Memory-mapped files */ + +extern PRStatus _PR_MD_CREATE_FILE_MAP(PRFileMap *fmap, PRInt64 size); +#define _PR_MD_CREATE_FILE_MAP _MD_CREATE_FILE_MAP + +extern PRInt32 _PR_MD_GET_MEM_MAP_ALIGNMENT(void); +#define _PR_MD_GET_MEM_MAP_ALIGNMENT _MD_GET_MEM_MAP_ALIGNMENT + +extern void * _PR_MD_MEM_MAP( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len); +#define _PR_MD_MEM_MAP _MD_MEM_MAP + +extern PRStatus _PR_MD_MEM_UNMAP(void *addr, PRUint32 size); +#define _PR_MD_MEM_UNMAP _MD_MEM_UNMAP + +extern PRStatus _PR_MD_CLOSE_FILE_MAP(PRFileMap *fmap); +#define _PR_MD_CLOSE_FILE_MAP _MD_CLOSE_FILE_MAP + +/* Named Shared Memory */ + +/* +** Declare PRSharedMemory. +*/ +struct PRSharedMemory +{ + char *ipcname; /* after conversion to native */ + PRSize size; /* from open */ + PRIntn mode; /* from open */ + PRIntn flags; /* from open */ +#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY) + int id; +#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY) + int id; +#elif defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY) + HANDLE handle; +#else + PRUint32 nothing; /* placeholder, nothing behind here */ +#endif + PRUint32 ident; /* guard word at end of struct */ +#define _PR_SHM_IDENT 0xdeadbad +}; + +extern PRSharedMemory * _MD_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +); +#define _PR_MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ); +#define _PR_MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ); +#define _PR_MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ); +#define _PR_MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory + +extern PRStatus _MD_DeleteSharedMemory( const char *name ); +#define _PR_MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory + +extern PRFileMap* _md_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +); +#define _PR_MD_OPEN_ANON_FILE_MAP _md_OpenAnonFileMap + +extern PRStatus _md_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufSize, + char *buf +); +#define _PR_MD_EXPORT_FILE_MAP_AS_STRING _md_ExportFileMapAsString + +extern PRFileMap * _md_ImportFileMapFromString( + const char *fmstring +); +#define _PR_MD_IMPORT_FILE_MAP_FROM_STRING _md_ImportFileMapFromString + + + +/* Interprocess communications (IPC) */ + +/* + * The maximum length of an NSPR IPC name, including the + * terminating null byte. + */ +#define PR_IPC_NAME_SIZE 1024 + +/* + * Types of NSPR IPC objects + */ +typedef enum { + _PRIPCSem, /* semaphores */ + _PRIPCShm /* shared memory segments */ +} _PRIPCType; + +/* + * Make a native IPC name from an NSPR IPC name. + */ +extern PRStatus _PR_MakeNativeIPCName( + const char *name, /* NSPR IPC name */ + char *result, /* result buffer */ + PRIntn size, /* size of result buffer */ + _PRIPCType type /* type of IPC object */ +); + +/* Socket call error code */ + +NSPR_API(PRInt32) _PR_MD_GET_SOCKET_ERROR(void); +#define _PR_MD_GET_SOCKET_ERROR _MD_GET_SOCKET_ERROR + +/* Get name of current host */ +extern PRStatus _PR_MD_GETHOSTNAME(char *name, PRUint32 namelen); +#define _PR_MD_GETHOSTNAME _MD_GETHOSTNAME + +extern PRStatus _PR_MD_GETSYSINFO(PRSysInfo cmd, char *name, PRUint32 namelen); +#define _PR_MD_GETSYSINFO _MD_GETSYSINFO + +/* File descriptor inheritance */ + +/* + * If fd->secret->inheritable is _PR_TRI_UNKNOWN and we need to + * know the inheritable attribute of the fd, call this function + * to find that out. This typically requires a system call. + */ +extern void _PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd); +#define _PR_MD_QUERY_FD_INHERITABLE _MD_QUERY_FD_INHERITABLE + +/* --- PR_GetRandomNoise() related things --- */ + +extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ); +#define _PR_MD_GET_RANDOM_NOISE(buf,size) _PR_MD_GetRandomNoise((buf),(size)) +extern PRSize _pr_CopyLowBits( void *dest, PRSize dstlen, void *src, PRSize srclen ); + +/* end PR_GetRandomNoise() related */ + +#ifdef XP_BEOS + +extern PRLock *_connectLock; + +typedef struct _ConnectListNode { + PRInt32 osfd; + PRNetAddr addr; + PRUint32 addrlen; + PRIntervalTime timeout; +} ConnectListNode; + +extern ConnectListNode connectList[64]; + +extern PRUint32 connectCount; + +#endif /* XP_BEOS */ + +PR_END_EXTERN_C + +#endif /* primpl_h___ */ diff --git a/nsprpub/pr/include/private/prpriv.h b/nsprpub/pr/include/private/prpriv.h new file mode 100644 index 00000000000..780376e8e17 --- /dev/null +++ b/nsprpub/pr/include/private/prpriv.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prpriv_h___ +#define prpriv_h___ + +/* + * NSPR 2.0 Private API + */ + +#ifndef XP_MAC +#include "private/pprio.h" +#include "private/pprthred.h" +#else +#include "pprio.h" +#include "pprthred.h" +#endif + +#endif /* prpriv_h___ */ diff --git a/nsprpub/pr/include/prlink.h b/nsprpub/pr/include/prlink.h new file mode 100644 index 00000000000..f0cea829635 --- /dev/null +++ b/nsprpub/pr/include/prlink.h @@ -0,0 +1,260 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prlink_h___ +#define prlink_h___ + +/* +** API to static and dynamic linking. +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRLibrary PRLibrary; + +typedef struct PRStaticLinkTable { + const char *name; + void (*fp)(); +} PRStaticLinkTable; + +/* +** Change the default library path to the given string. The string is +** copied. This call will fail if it runs out of memory. +** +** The string provided as 'path' is copied. The caller can do whatever is +** convenient with the argument when the function is complete. +*/ +NSPR_API(PRStatus) PR_SetLibraryPath(const char *path); + +/* +** Return a character string which contains the path used to search for +** dynamically loadable libraries. +** +** The returned value is basically a copy of a PR_SetLibraryPath(). +** The storage is allocated by the runtime and becomes the responsibilty +** of the caller. +*/ +NSPR_API(char*) PR_GetLibraryPath(void); + +/* +** Given a directory name "dir" and a library name "lib" construct a full +** path name that will refer to the actual dynamically loaded +** library. This does not test for existance of said file, it just +** constructs the full filename. The name constructed is system dependent +** and prepared for PR_LoadLibrary. The result must be free'd when the +** caller is done with it. +** +** The storage for the result is allocated by the runtime and becomes the +** responsibility of the caller. +*/ +NSPR_API(char*) PR_GetLibraryName(const char *dir, const char *lib); + +/* +** +** Free the memory allocated, for the caller, by PR_GetLibraryName +*/ +NSPR_API(void) PR_FreeLibraryName(char *mem); + +/* +** Given a library "name" try to load the library. The argument "name" +** is a machine-dependent name for the library, such as the full pathname +** returned by PR_GetLibraryName. If the library is already loaded, +** this function will avoid loading the library twice. +** +** If the library is loaded successfully, then a pointer to the PRLibrary +** structure representing the library is returned. Otherwise, NULL is +** returned. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRLibrary*) PR_LoadLibrary(const char *name); + +/* +** Each operating system has its preferred way of specifying +** a file in the file system. Most operating systems use +** a pathname. Mac OS, on the other hand, uses the FSSpec +** structure to specify a file. PRLibSpec allows NSPR clients +** to use the type of file specification that is most efficient +** for a particular platform. +** +** On some operating systems such as Mac OS, a shared library may +** contain code fragments that can be individually loaded. +** PRLibSpec also allows NSPR clients to identify a code fragment +** in a library, if code fragments are supported by the OS. +** A code fragment can be specified by name or by an integer index. +** +** Right now PRLibSpec supports four types of library specification: +** a pathname in the native character encoding, a Mac code fragment +** by name, a Mac code fragment by index, and a UTF-16 pathname. +*/ + +typedef enum PRLibSpecType { + PR_LibSpec_Pathname, + PR_LibSpec_MacNamedFragment, /* obsolete (for Mac OS Classic) */ + PR_LibSpec_MacIndexedFragment, /* obsolete (for Mac OS Classic) */ + PR_LibSpec_PathnameU /* supported only on Win32 */ +} PRLibSpecType; + +struct FSSpec; /* Mac OS FSSpec */ + +typedef struct PRLibSpec { + PRLibSpecType type; + union { + /* if type is PR_LibSpec_Pathname */ + const char *pathname; + + /* if type is PR_LibSpec_MacNamedFragment */ + struct { + const struct FSSpec *fsspec; + const char *name; + } mac_named_fragment; /* obsolete (for Mac OS Classic) */ + + /* if type is PR_LibSpec_MacIndexedFragment */ + struct { + const struct FSSpec *fsspec; + PRUint32 index; + } mac_indexed_fragment; /* obsolete (for Mac OS Classic) */ + + /* if type is PR_LibSpec_PathnameU */ + const PRUnichar *pathname_u; /* supported only on Win32 */ + } value; +} PRLibSpec; + +/* +** The following bit flags may be or'd together and passed +** as the 'flags' argument to PR_LoadLibraryWithFlags. +** Flags not supported by the underlying OS are ignored. +*/ + +#define PR_LD_LAZY 0x1 /* equivalent to RTLD_LAZY on Unix */ +#define PR_LD_NOW 0x2 /* equivalent to RTLD_NOW on Unix */ +#define PR_LD_GLOBAL 0x4 /* equivalent to RTLD_GLOBAL on Unix */ +#define PR_LD_LOCAL 0x8 /* equivalent to RTLD_LOCAL on Unix */ +/* 0x8000 reserved for NSPR internal use */ + +/* +** Load the specified library, in the manner specified by 'flags'. +*/ + +NSPR_API(PRLibrary *) +PR_LoadLibraryWithFlags( + PRLibSpec libSpec, /* the shared library */ + PRIntn flags /* flags that affect the loading */ +); + +/* +** Unload a previously loaded library. If the library was a static +** library then the static link table will no longer be referenced. The +** associated PRLibrary object is freed. +** +** PR_FAILURE is returned if the library cannot be unloaded. +** +** This function decrements the reference count of the library. +*/ +NSPR_API(PRStatus) PR_UnloadLibrary(PRLibrary *lib); + +/* +** Given the name of a procedure, return the address of the function that +** implements the procedure, or NULL if no such function can be +** found. This does not find symbols in the main program (the ".exe"); +** use PR_LoadStaticLibrary to register symbols in the main program. +** +** This function does not modify the reference count of the library. +*/ +NSPR_API(void*) PR_FindSymbol(PRLibrary *lib, const char *name); + +/* +** Similar to PR_FindSymbol, except that the return value is a pointer to +** a function, and not a pointer to void. Casting between a data pointer +** and a function pointer is not portable according to the C standard. +** Any function pointer can be cast to any other function pointer. +** +** This function does not modify the reference count of the library. +*/ +typedef void (*PRFuncPtr)(); +NSPR_API(PRFuncPtr) PR_FindFunctionSymbol(PRLibrary *lib, const char *name); + +/* +** Finds a symbol in one of the currently loaded libraries. Given the +** name of a procedure, return the address of the function that +** implements the procedure, and return the library that contains that +** symbol, or NULL if no such function can be found. This does not find +** symbols in the main program (the ".exe"); use PR_AddStaticLibrary to +** register symbols in the main program. +** +** This increments the reference count of the library. +*/ +NSPR_API(void*) PR_FindSymbolAndLibrary(const char *name, + PRLibrary* *lib); + +/* +** Similar to PR_FindSymbolAndLibrary, except that the return value is +** a pointer to a function, and not a pointer to void. Casting between a +** data pointer and a function pointer is not portable according to the C +** standard. Any function pointer can be cast to any other function pointer. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRFuncPtr) PR_FindFunctionSymbolAndLibrary(const char *name, + PRLibrary* *lib); + +/* +** Register a static link table with the runtime under the name +** "name". The symbols present in the static link table will be made +** available to PR_FindSymbol. If "name" is null then the symbols will be +** made available to the library which represents the executable. The +** tables are not copied. +** +** Returns the library object if successful, null otherwise. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRLibrary*) PR_LoadStaticLibrary( + const char *name, const PRStaticLinkTable *table); + +/* +** Return the pathname of the file that the library "name" was loaded +** from. "addr" is the address of a function defined in the library. +** +** The caller is responsible for freeing the result with PR_Free. +*/ +NSPR_API(char *) PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr); + +PR_END_EXTERN_C + +#endif /* prlink_h___ */ diff --git a/nsprpub/pr/include/prlock.h b/nsprpub/pr/include/prlock.h new file mode 100644 index 00000000000..0805d95ba48 --- /dev/null +++ b/nsprpub/pr/include/prlock.h @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prlock.h +** Description: API to basic locking functions of NSPR. +** +** +** NSPR provides basic locking mechanisms for thread synchronization. Locks +** are lightweight resource contention controls that prevent multiple threads +** from accessing something (code/data) simultaneously. +**/ + +#ifndef prlock_h___ +#define prlock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +/* + * PRLock -- + * + * NSPR represents the lock as an opaque entity to the client of the + * API. All routines operate on a pointer to this opaque entity. + */ + +typedef struct PRLock PRLock; + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_NewLock +** DESCRIPTION: +** Returns a pointer to a newly created opaque lock object. +** INPUTS: void +** OUTPUTS: void +** RETURN: PRLock* +** If the lock can not be created because of resource constraints, NULL +** is returned. +** +***********************************************************************/ +NSPR_API(PRLock*) PR_NewLock(void); + +/*********************************************************************** +** FUNCTION: PR_DestroyLock +** DESCRIPTION: +** Destroys a given opaque lock object. +** INPUTS: PRLock *lock +** Lock to be freed. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_DestroyLock(PRLock *lock); + +/*********************************************************************** +** FUNCTION: PR_Lock +** DESCRIPTION: +** Lock a lock. +** INPUTS: PRLock *lock +** Lock to locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_Lock(PRLock *lock); + +/*********************************************************************** +** FUNCTION: PR_Unlock +** DESCRIPTION: +** Unlock a lock. Unlocking an unlocked lock has undefined results. +** INPUTS: PRLock *lock +** Lock to unlocked. +** OUTPUTS: void +** RETURN: PR_STATUS +** Returns PR_FAILURE if the caller does not own the lock. +***********************************************************************/ +NSPR_API(PRStatus) PR_Unlock(PRLock *lock); + +PR_END_EXTERN_C + +#endif /* prlock_h___ */ diff --git a/nsprpub/pr/include/prlog.h b/nsprpub/pr/include/prlog.h new file mode 100644 index 00000000000..2a65b3de933 --- /dev/null +++ b/nsprpub/pr/include/prlog.h @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prlog_h___ +#define prlog_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** prlog.h -- Declare interfaces to NSPR's Logging service +** +** NSPR provides a logging service that is used by NSPR itself and is +** available to client programs. +** +** To use the service from a client program, you should create a +** PRLogModuleInfo structure by calling PR_NewLogModule(). After +** creating the LogModule, you can write to the log using the PR_LOG() +** macro. +** +** Initialization of the log service is handled by NSPR initialization. +** +** At execution time, you must enable the log service. To enable the +** log service, set the environment variable: NSPR_LOG_MODULES +** variable. +** +** NSPR_LOG_MODULES variable has the form: +** +** :[, :]* +** +** Where: +** is the name passed to PR_NewLogModule(). +** is a numeric constant, e.g. 5. This value is the maximum +** value of a log event, enumerated by PRLogModuleLevel, that you want +** written to the log. +** +** For example: to record all events of greater value than or equal to +** PR_LOG_ERROR for a LogModule names "gizmo", say: +** +** set NSPR_LOG_MODULES=gizmo:2 +** +** Note that you must specify the numeric value of PR_LOG_ERROR. +** +** Special LogModule names are provided for controlling NSPR's log +** service at execution time. These controls should be set in the +** NSPR_LOG_MODULES environment variable at execution time to affect +** NSPR's log service for your application. +** +** The special LogModule "all" enables all LogModules. To enable all +** LogModule calls to PR_LOG(), say: +** +** set NSPR_LOG_MODULES=all:5 +** +** The special LogModule name "sync" tells the NSPR log service to do +** unbuffered logging. +** +** The special LogModule name "bufsize:" tells NSPR to set the +** log buffer to . +** +** The environment variable NSPR_LOG_FILE specifies the log file to use +** 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: +** +** PR_LOG(, , (, *)); +** +** Where is the address of a PRLogModuleInfo structure, and +** is one of the levels defined by the enumeration: +** PRLogModuleLevel. is a printf() style of argument list. That +** is: (fmtstring, ...). +** +** Example: +** +** main() { +** PRIntn one = 1; +** PRLogModuleInfo * myLm = PR_NewLogModule("gizmo"); +** PR_LOG( myLm, PR_LOG_ALWAYS, ("Log this! %d\n", one)); +** return; +** } +** +** Note the use of printf() style arguments as the third agrument(s) to +** PR_LOG(). +** +** After compiling and linking you application, set the environment: +** +** set NSPR_LOG_MODULES=gizmo:5 +** set NSPR_LOG_FILE=logfile.txt +** +** When you execute your application, the string "Log this! 1" will be +** written to the file "logfile.txt". +** +** Note to NSPR engineers: a number of PRLogModuleInfo structures are +** defined and initialized in prinit.c. See this module for ideas on +** what to log where. +** +*/ + +typedef enum PRLogModuleLevel { + PR_LOG_NONE = 0, /* nothing */ + PR_LOG_ALWAYS = 1, /* always printed */ + PR_LOG_ERROR = 2, /* error messages */ + PR_LOG_WARNING = 3, /* warning messages */ + PR_LOG_DEBUG = 4, /* debug messages */ + + PR_LOG_NOTICE = PR_LOG_DEBUG, /* notice messages */ + PR_LOG_WARN = PR_LOG_WARNING, /* warning messages */ + PR_LOG_MIN = PR_LOG_DEBUG, /* minimal debugging messages */ + PR_LOG_MAX = PR_LOG_DEBUG /* maximal debugging messages */ +} PRLogModuleLevel; + +/* +** One of these structures is created for each module that uses logging. +** "name" is the name of the module +** "level" is the debugging level selected for that module +*/ +typedef struct PRLogModuleInfo { + const char *name; + PRLogModuleLevel level; + struct PRLogModuleInfo *next; +} PRLogModuleInfo; + +/* +** Create a new log module. +*/ +NSPR_API(PRLogModuleInfo*) PR_NewLogModule(const char *name); + +/* +** Set the file to use for logging. Returns PR_FALSE if the file cannot +** be created +*/ +NSPR_API(PRBool) PR_SetLogFile(const char *name); + +/* +** Set the size of the logging buffer. If "buffer_size" is zero then the +** logging becomes "synchronous" (or unbuffered). +*/ +NSPR_API(void) PR_SetLogBuffering(PRIntn buffer_size); + +/* +** Print a string to the log. "fmt" is a PR_snprintf format type. All +** messages printed to the log are preceeded by the name of the thread +** and a time stamp. Also, the routine provides a missing newline if one +** is not provided. +*/ +NSPR_API(void) PR_LogPrint(const char *fmt, ...); + +/* +** Flush the log to its file. +*/ +NSPR_API(void) PR_LogFlush(void); + +/* +** Windoze 16 can't support a large static string space for all of the +** various debugging strings so logging is not enabled for it. +*/ +#if (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) +#define PR_LOGGING 1 + +#define PR_LOG_TEST(_module,_level) \ + ((_module)->level >= (_level)) + +/* +** Log something. +** "module" is the address of a PRLogModuleInfo structure +** "level" is the desired logging level +** "args" is a variable length list of arguments to print, in the following +** format: ("printf style format string", ...) +*/ +#define PR_LOG(_module,_level,_args) \ + PR_BEGIN_MACRO \ + if (PR_LOG_TEST(_module,_level)) { \ + PR_LogPrint _args; \ + } \ + PR_END_MACRO + +#else /* (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) */ + +#undef PR_LOGGING +#define PR_LOG_TEST(module,level) 0 +#define PR_LOG(module,level,args) + +#endif /* (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) */ + +#ifndef NO_NSPR_10_SUPPORT + +#ifdef PR_LOGGING +#define PR_LOG_BEGIN PR_LOG +#define PR_LOG_END PR_LOG +#define PR_LOG_DEFINE PR_NewLogModule +#else +#define PR_LOG_BEGIN(module,level,args) +#define PR_LOG_END(module,level,args) +#define PR_LOG_DEFINE(_name) NULL +#endif /* PR_LOGGING */ + +#endif /* NO_NSPR_10_SUPPORT */ + +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) + +NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln); +#define PR_ASSERT(_expr) \ + ((_expr)?((void)0):PR_Assert(# _expr,__FILE__,__LINE__)) + +#define PR_NOT_REACHED(_reasonStr) \ + PR_Assert(_reasonStr,__FILE__,__LINE__) + +#else + +#define PR_ASSERT(expr) ((void) 0) +#define PR_NOT_REACHED(reasonStr) + +#endif /* defined(DEBUG) || defined(FORCE_PR_ASSERT) */ + +/* +** Compile-time assert. "condition" must be a constant expression. +** The macro can be used only in places where an "extern" declaration is +** allowed. +*/ +#define PR_STATIC_ASSERT(condition) \ + extern void pr_static_assert(int arg[(condition) ? 1 : -1]) + +PR_END_EXTERN_C + +#endif /* prlog_h___ */ diff --git a/nsprpub/pr/include/prlong.h b/nsprpub/pr/include/prlong.h new file mode 100644 index 00000000000..09b432175a1 --- /dev/null +++ b/nsprpub/pr/include/prlong.h @@ -0,0 +1,445 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prlong.h +** Description: Portable access to 64 bit numerics +** +** Long-long (64-bit signed integer type) support. Some C compilers +** don't support 64 bit integers yet, so we use these macros to +** support both machines that do and don't. +**/ +#ifndef prlong_h___ +#define prlong_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/*********************************************************************** +** DEFINES: LL_MaxInt +** LL_MinInt +** LL_Zero +** LL_MaxUint +** DESCRIPTION: +** Various interesting constants and static variable +** initializer +***********************************************************************/ +#if defined(HAVE_WATCOM_BUG_2) +PRInt64 __pascal __loadds __export + LL_MaxInt(void); +PRInt64 __pascal __loadds __export + LL_MinInt(void); +PRInt64 __pascal __loadds __export + LL_Zero(void); +PRUint64 __pascal __loadds __export + LL_MaxUint(void); +#else +NSPR_API(PRInt64) LL_MaxInt(void); +NSPR_API(PRInt64) LL_MinInt(void); +NSPR_API(PRInt64) LL_Zero(void); +NSPR_API(PRUint64) LL_MaxUint(void); +#endif + +#if defined(HAVE_LONG_LONG) + +#if PR_BYTES_PER_LONG == 8 +#define LL_MAXINT 9223372036854775807L +#define LL_MININT (-LL_MAXINT - 1L) +#define LL_ZERO 0L +#define LL_MAXUINT 18446744073709551615UL +#define LL_INIT(hi, lo) ((hi ## L << 32) + lo ## L) +#elif (defined(WIN32) || defined(WIN16)) && !defined(__GNUC__) +#define LL_MAXINT 9223372036854775807i64 +#define LL_MININT (-LL_MAXINT - 1i64) +#define LL_ZERO 0i64 +#define LL_MAXUINT 18446744073709551615ui64 +#define LL_INIT(hi, lo) ((hi ## i64 << 32) + lo ## i64) +#else +#define LL_MAXINT 9223372036854775807LL +#define LL_MININT (-LL_MAXINT - 1LL) +#define LL_ZERO 0LL +#define LL_MAXUINT 18446744073709551615ULL +#define LL_INIT(hi, lo) ((hi ## LL << 32) + lo ## LL) +#endif + +/*********************************************************************** +** MACROS: LL_* +** DESCRIPTION: +** The following macros define portable access to the 64 bit +** math facilities. +** +***********************************************************************/ + +/*********************************************************************** +** MACROS: LL_ +** +** LL_IS_ZERO Test for zero +** LL_EQ Test for equality +** LL_NE Test for inequality +** LL_GE_ZERO Test for zero or positive +** LL_CMP Compare two values +***********************************************************************/ +#define LL_IS_ZERO(a) ((a) == 0) +#define LL_EQ(a, b) ((a) == (b)) +#define LL_NE(a, b) ((a) != (b)) +#define LL_GE_ZERO(a) ((a) >= 0) +#define LL_CMP(a, op, b) ((PRInt64)(a) op (PRInt64)(b)) +#define LL_UCMP(a, op, b) ((PRUint64)(a) op (PRUint64)(b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_AND Logical and +** LL_OR Logical or +** LL_XOR Logical exclusion +** LL_OR2 A disgusting deviation +** LL_NOT Negation (one's complement) +***********************************************************************/ +#define LL_AND(r, a, b) ((r) = (a) & (b)) +#define LL_OR(r, a, b) ((r) = (a) | (b)) +#define LL_XOR(r, a, b) ((r) = (a) ^ (b)) +#define LL_OR2(r, a) ((r) = (r) | (a)) +#define LL_NOT(r, a) ((r) = ~(a)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_NEG Negation (two's complement) +** LL_ADD Summation (two's complement) +** LL_SUB Difference (two's complement) +***********************************************************************/ +#define LL_NEG(r, a) ((r) = -(a)) +#define LL_ADD(r, a, b) ((r) = (a) + (b)) +#define LL_SUB(r, a, b) ((r) = (a) - (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_MUL Product (two's complement) +** LL_DIV Quotient (two's complement) +** LL_MOD Modulus (two's complement) +***********************************************************************/ +#define LL_MUL(r, a, b) ((r) = (a) * (b)) +#define LL_DIV(r, a, b) ((r) = (a) / (b)) +#define LL_MOD(r, a, b) ((r) = (a) % (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_SHL Shift left [0..64] bits +** LL_SHR Shift right [0..64] bits with sign extension +** LL_USHR Unsigned shift right [0..64] bits +** LL_ISHL Signed shift left [0..64] bits +***********************************************************************/ +#define LL_SHL(r, a, b) ((r) = (PRInt64)(a) << (b)) +#define LL_SHR(r, a, b) ((r) = (PRInt64)(a) >> (b)) +#define LL_USHR(r, a, b) ((r) = (PRUint64)(a) >> (b)) +#define LL_ISHL(r, a, b) ((r) = (PRInt64)(a) << (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_L2I Convert to signed 32 bit +** LL_L2UI Convert to unsigned 32 bit +** LL_L2F Convert to floating point +** LL_L2D Convert to floating point +** LL_I2L Convert signed to 64 bit +** LL_UI2L Convert unsigned to 64 bit +** LL_F2L Convert float to 64 bit +** LL_D2L Convert float to 64 bit +***********************************************************************/ +#define LL_L2I(i, l) ((i) = (PRInt32)(l)) +#define LL_L2UI(ui, l) ((ui) = (PRUint32)(l)) +#define LL_L2F(f, l) ((f) = (PRFloat64)(l)) +#define LL_L2D(d, l) ((d) = (PRFloat64)(l)) + +#define LL_I2L(l, i) ((l) = (PRInt64)(i)) +#define LL_UI2L(l, ui) ((l) = (PRInt64)(ui)) +#define LL_F2L(l, f) ((l) = (PRInt64)(f)) +#define LL_D2L(l, d) ((l) = (PRInt64)(d)) + +/*********************************************************************** +** MACROS: LL_UDIVMOD +** DESCRIPTION: +** Produce both a quotient and a remainder given an unsigned +** INPUTS: PRUint64 a: The dividend of the operation +** PRUint64 b: The quotient of the operation +** OUTPUTS: PRUint64 *qp: pointer to quotient +** PRUint64 *rp: pointer to remainder +***********************************************************************/ +#define LL_UDIVMOD(qp, rp, a, b) \ + (*(qp) = ((PRUint64)(a) / (b)), \ + *(rp) = ((PRUint64)(a) % (b))) + +#else /* !HAVE_LONG_LONG */ + +#define LL_MAXINT LL_MaxInt() +#define LL_MININT LL_MinInt() +#define LL_ZERO LL_Zero() +#define LL_MAXUINT LL_MaxUint() + +#ifdef IS_LITTLE_ENDIAN +#define LL_INIT(hi, lo) {PR_UINT32(lo), PR_UINT32(hi)} +#else +#define LL_INIT(hi, lo) {PR_UINT32(hi), PR_UINT32(lo)} +#endif + +#define LL_IS_ZERO(a) (((a).hi == 0) && ((a).lo == 0)) +#define LL_EQ(a, b) (((a).hi == (b).hi) && ((a).lo == (b).lo)) +#define LL_NE(a, b) (((a).hi != (b).hi) || ((a).lo != (b).lo)) +#define LL_GE_ZERO(a) (((a).hi >> 31) == 0) + +#define LL_CMP(a, op, b) (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \ + ((PRInt32)(a).hi op (PRInt32)(b).hi)) +#define LL_UCMP(a, op, b) (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \ + ((a).hi op (b).hi)) + +#define LL_AND(r, a, b) ((r).lo = (a).lo & (b).lo, \ + (r).hi = (a).hi & (b).hi) +#define LL_OR(r, a, b) ((r).lo = (a).lo | (b).lo, \ + (r).hi = (a).hi | (b).hi) +#define LL_XOR(r, a, b) ((r).lo = (a).lo ^ (b).lo, \ + (r).hi = (a).hi ^ (b).hi) +#define LL_OR2(r, a) ((r).lo = (r).lo | (a).lo, \ + (r).hi = (r).hi | (a).hi) +#define LL_NOT(r, a) ((r).lo = ~(a).lo, \ + (r).hi = ~(a).hi) + +#define LL_NEG(r, a) ((r).lo = -(PRInt32)(a).lo, \ + (r).hi = -(PRInt32)(a).hi - ((r).lo != 0)) +#define LL_ADD(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo + _b.lo; \ + (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo); \ +} + +#define LL_SUB(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo - _b.lo; \ + (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo); \ +} + +#define LL_MUL(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + LL_MUL32(r, _a.lo, _b.lo); \ + (r).hi += _a.hi * _b.lo + _a.lo * _b.hi; \ +} + +#define _lo16(a) ((a) & PR_BITMASK(16)) +#define _hi16(a) ((a) >> 16) + +#define LL_MUL32(r, a, b) { \ + PRUint32 _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3; \ + _a1 = _hi16(a), _a0 = _lo16(a); \ + _b1 = _hi16(b), _b0 = _lo16(b); \ + _y0 = _a0 * _b0; \ + _y1 = _a0 * _b1; \ + _y2 = _a1 * _b0; \ + _y3 = _a1 * _b1; \ + _y1 += _hi16(_y0); /* can't carry */ \ + _y1 += _y2; /* might carry */ \ + if (_y1 < _y2) \ + _y3 += (PRUint32)(PR_BIT(16)); /* propagate */ \ + (r).lo = (_lo16(_y1) << 16) + _lo16(_y0); \ + (r).hi = _y3 + _hi16(_y1); \ +} + +#define LL_UDIVMOD(qp, rp, a, b) ll_udivmod(qp, rp, a, b) + +NSPR_API(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b); + +#define LL_DIV(r, a, b) { \ + PRInt64 _a, _b; \ + PRUint32 _negative = (PRInt32)(a).hi < 0; \ + if (_negative) { \ + LL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((PRInt32)(b).hi < 0) { \ + _negative ^= 1; \ + LL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + LL_UDIVMOD(&(r), 0, _a, _b); \ + if (_negative) \ + LL_NEG(r, r); \ +} + +#define LL_MOD(r, a, b) { \ + PRInt64 _a, _b; \ + PRUint32 _negative = (PRInt32)(a).hi < 0; \ + if (_negative) { \ + LL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((PRInt32)(b).hi < 0) { \ + LL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + LL_UDIVMOD(0, &(r), _a, _b); \ + if (_negative) \ + LL_NEG(r, r); \ +} + +#define LL_SHL(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = _a.lo << ((b) & 31); \ + (r).hi = (_a.hi << ((b) & 31)) | (_a.lo >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = _a.lo << ((b) & 31); \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +/* a is an PRInt32, b is PRInt32, r is PRInt64 */ +#define LL_ISHL(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a.lo = (a); \ + _a.hi = 0; \ + if ((b) < 32) { \ + (r).lo = (a) << ((b) & 31); \ + (r).hi = ((a) >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = (a) << ((b) & 31); \ + } \ + } else { \ + (r).lo = (a); \ + (r).hi = 0; \ + } \ +} + +#define LL_SHR(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = (PRInt32)_a.hi >> ((b) & 31); \ + } else { \ + (r).lo = (PRInt32)_a.hi >> ((b) & 31); \ + (r).hi = (PRInt32)_a.hi >> 31; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define LL_USHR(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = _a.hi >> ((b) & 31); \ + } else { \ + (r).lo = _a.hi >> ((b) & 31); \ + (r).hi = 0; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define LL_L2I(i, l) ((i) = (l).lo) +#define LL_L2UI(ui, l) ((ui) = (l).lo) +#define LL_L2F(f, l) { double _d; LL_L2D(_d, l); (f) = (PRFloat64)_d; } + +#define LL_L2D(d, l) { \ + int _negative; \ + PRInt64 _absval; \ + \ + _negative = (l).hi >> 31; \ + if (_negative) { \ + LL_NEG(_absval, l); \ + } else { \ + _absval = l; \ + } \ + (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo; \ + if (_negative) \ + (d) = -(d); \ +} + +#define LL_I2L(l, i) { PRInt32 _i = ((PRInt32)(i)) >> 31; (l).lo = (i); (l).hi = _i; } +#define LL_UI2L(l, ui) ((l).lo = (ui), (l).hi = 0) +#define LL_F2L(l, f) { double _d = (double)f; LL_D2L(l, _d); } + +#define LL_D2L(l, d) { \ + int _negative; \ + double _absval, _d_hi; \ + PRInt64 _lo_d; \ + \ + _negative = ((d) < 0); \ + _absval = _negative ? -(d) : (d); \ + \ + (l).hi = _absval / 4.294967296e9; \ + (l).lo = 0; \ + LL_L2D(_d_hi, l); \ + _absval -= _d_hi; \ + _lo_d.hi = 0; \ + if (_absval < 0) { \ + _lo_d.lo = -_absval; \ + LL_SUB(l, l, _lo_d); \ + } else { \ + _lo_d.lo = _absval; \ + LL_ADD(l, l, _lo_d); \ + } \ + \ + if (_negative) \ + LL_NEG(l, l); \ +} + +#endif /* !HAVE_LONG_LONG */ + +PR_END_EXTERN_C + +#endif /* prlong_h___ */ diff --git a/nsprpub/pr/include/prmem.h b/nsprpub/pr/include/prmem.h new file mode 100644 index 00000000000..1cf0949c095 --- /dev/null +++ b/nsprpub/pr/include/prmem.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prmem.h +** Description: API to NSPR memory management functions +** +*/ +#ifndef prmem_h___ +#define prmem_h___ + +#include "prtypes.h" +#include + +PR_BEGIN_EXTERN_C + +/* +** Thread safe memory allocation. +** +** NOTE: pr wraps up malloc, free, calloc, realloc so they are already +** thread safe (and are not declared here - look in stdlib.h). +*/ + +/* +** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free have the same signatures +** as their libc equivalent malloc, calloc, realloc, and free, and have +** the same semantics. (Note that the argument type size_t is replaced +** by PRUint32.) Memory allocated by PR_Malloc, PR_Calloc, or PR_Realloc +** must be freed by PR_Free. +*/ + +NSPR_API(void *) PR_Malloc(PRUint32 size); + +NSPR_API(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize); + +NSPR_API(void *) PR_Realloc(void *ptr, PRUint32 size); + +NSPR_API(void) PR_Free(void *ptr); + +/* +** The following are some convenience macros defined in terms of +** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free. +*/ + +/*********************************************************************** +** FUNCTION: PR_MALLOC() +** DESCRIPTION: +** PR_NEW() allocates an untyped item of size _size from the heap. +** INPUTS: _size: size in bytes of item to be allocated +** OUTPUTS: untyped pointer to the node allocated +** RETURN: pointer to node or error returned from malloc(). +***********************************************************************/ +#define PR_MALLOC(_bytes) (PR_Malloc((_bytes))) + +/*********************************************************************** +** FUNCTION: PR_NEW() +** DESCRIPTION: +** PR_NEW() allocates an item of type _struct from the heap. +** INPUTS: _struct: a data type +** OUTPUTS: pointer to _struct +** RETURN: pointer to _struct or error returns from malloc(). +***********************************************************************/ +#define PR_NEW(_struct) ((_struct *) PR_MALLOC(sizeof(_struct))) + +/*********************************************************************** +** FUNCTION: PR_REALLOC() +** DESCRIPTION: +** PR_REALLOC() re-allocates _ptr bytes from the heap as a _size +** untyped item. +** INPUTS: _ptr: pointer to node to reallocate +** _size: size of node to allocate +** OUTPUTS: pointer to node allocated +** RETURN: pointer to node allocated +***********************************************************************/ +#define PR_REALLOC(_ptr, _size) (PR_Realloc((_ptr), (_size))) + +/*********************************************************************** +** FUNCTION: PR_CALLOC() +** DESCRIPTION: +** PR_CALLOC() allocates a _size bytes untyped item from the heap +** and sets the allocated memory to all 0x00. +** INPUTS: _size: size of node to allocate +** OUTPUTS: pointer to node allocated +** RETURN: pointer to node allocated +***********************************************************************/ +#define PR_CALLOC(_size) (PR_Calloc(1, (_size))) + +/*********************************************************************** +** FUNCTION: PR_NEWZAP() +** DESCRIPTION: +** PR_NEWZAP() allocates an item of type _struct from the heap +** and sets the allocated memory to all 0x00. +** INPUTS: _struct: a data type +** OUTPUTS: pointer to _struct +** RETURN: pointer to _struct +***********************************************************************/ +#define PR_NEWZAP(_struct) ((_struct*)PR_Calloc(1, sizeof(_struct))) + +/*********************************************************************** +** FUNCTION: PR_DELETE() +** DESCRIPTION: +** PR_DELETE() unallocates an object previosly allocated via PR_NEW() +** or PR_NEWZAP() to the heap. +** INPUTS: pointer to previously allocated object +** OUTPUTS: the referenced object is returned to the heap +** RETURN: void +***********************************************************************/ +#define PR_DELETE(_ptr) { PR_Free(_ptr); (_ptr) = NULL; } + +/*********************************************************************** +** FUNCTION: PR_FREEIF() +** DESCRIPTION: +** PR_FREEIF() conditionally unallocates an object previously allocated +** vial PR_NEW() or PR_NEWZAP(). If the pointer to the object is +** equal to zero (0), the object is not released. +** INPUTS: pointer to previously allocated object +** OUTPUTS: the referenced object is conditionally returned to the heap +** RETURN: void +***********************************************************************/ +#define PR_FREEIF(_ptr) if (_ptr) PR_DELETE(_ptr) + +PR_END_EXTERN_C + +#endif /* prmem_h___ */ diff --git a/nsprpub/pr/include/prmon.h b/nsprpub/pr/include/prmon.h new file mode 100644 index 00000000000..d2a1971cfee --- /dev/null +++ b/nsprpub/pr/include/prmon.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prmon_h___ +#define prmon_h___ + +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRMonitor PRMonitor; + +/* +** Create a new monitor. Monitors are re-entrant locks with a single built-in +** condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +NSPR_API(PRMonitor*) PR_NewMonitor(void); + +/* +** Destroy a monitor. The caller is responsible for guaranteeing that the +** monitor is no longer in use. There must be no thread waiting on the monitor's +** condition variable and that the lock is not held. +** +*/ +NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon); + +/* +** Enter the lock associated with the monitor. If the calling thread currently +** is in the monitor, the call to enter will silently succeed. In either case, +** it will increment the entry count by one. +*/ +NSPR_API(void) PR_EnterMonitor(PRMonitor *mon); + +/* +** Decrement the entry count associated with the monitor. If the decremented +** entry count is zero, the monitor is exited. Returns PR_FAILURE if the +** calling thread has not entered the monitor. +*/ +NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon); + +/* +** Wait for a notify on the monitor's condition variable. Sleep for "ticks" +** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is +** indefinite). +** +** While the thread is waiting it exits the monitor (as if it called +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When +** the wait has finished the thread regains control of the monitors lock +** with the same entry count as before the wait began. +** +** The thread waiting on the monitor will be resumed when the monitor is +** notified (assuming the thread is the next in line to receive the +** notify) or when the "ticks" timeout elapses. +** +** Returns PR_FAILURE if the caller has not entered the monitor. +*/ +NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks); + +/* +** Notify a thread waiting on the monitor's condition variable. If a thread +** is waiting on the condition variable (using PR_Wait) then it is awakened +** and attempts to reenter the monitor. +*/ +NSPR_API(PRStatus) PR_Notify(PRMonitor *mon); + +/* +** Notify all of the threads waiting on the monitor's condition variable. +** All of threads waiting on the condition are scheduled to reenter the +** monitor. +*/ +NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon); + +PR_END_EXTERN_C + +#endif /* prmon_h___ */ diff --git a/nsprpub/pr/include/prmwait.h b/nsprpub/pr/include/prmwait.h new file mode 100644 index 00000000000..e4cabda408f --- /dev/null +++ b/nsprpub/pr/include/prmwait.h @@ -0,0 +1,412 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if defined(_PRMWAIT_H) +#else +#define _PRMWAIT_H + +#include "prio.h" +#include "prtypes.h" +#include "prclist.h" + +PR_BEGIN_EXTERN_C + +/********************************************************************************/ +/********************************************************************************/ +/********************************************************************************/ +/****************************** WARNING ****************************/ +/********************************************************************************/ +/**************************** This is work in progress. *************************/ +/************************** Do not make any assumptions *************************/ +/************************** about the stability of this *************************/ +/************************** API or the underlying imple- ************************/ +/************************** mentation. ************************/ +/********************************************************************************/ +/********************************************************************************/ + +/* +** STRUCTURE: PRWaitGroup +** DESCRIPTION: +** The client may define several wait groups in order to semantically +** tie a collection of file descriptors for a single purpose. This allows +** easier dispatching of threads that returned with active file descriptors +** from the wait function. +*/ +typedef struct PRWaitGroup PRWaitGroup; + +/* +** ENUMERATION: PRMWStatus +** DESCRIPTION: +** This enumeration is used to indicate the completion status of +** 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 +** by calling PR_GetError(). +** +** PR_MW_PENDING The operation is still pending. None of the other +** fields of the object are currently valid. +** PR_MW_SUCCESS The operation is complete and it was successful. +** PR_MW_FAILURE The operation failed. The reason for the failure +** can be retrieved by calling PR_GetError(). +** PR_MW_TIMEOUT The amount of time allowed for by the object's +** 'timeout' field has expired w/o the operation +** otherwise coming to closure. +** PR_MW_INTERRUPT The operation was cancelled, either by the client +** calling PR_CancelWaitFileDesc() or destroying the +** entire wait group (PR_DestroyWaitGroup()). +*/ +typedef enum PRMWStatus +{ + PR_MW_PENDING = 1, + PR_MW_SUCCESS = 0, + PR_MW_FAILURE = -1, + PR_MW_TIMEOUT = -2, + PR_MW_INTERRUPT = -3 +} PRMWStatus; + +/* +** STRUCTURE: PRMemoryDescriptor +** DESCRIPTION: +** THis is a descriptor for an interval of memory. It contains a +** pointer to the first byte of that memory and the length (in +** bytes) of the interval. +*/ +typedef struct PRMemoryDescriptor +{ + void *start; /* pointer to first byte of memory */ + PRSize length; /* length (in bytes) of memory interval */ +} 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 +** to the wait and the amount of time (beginning epoch established +** when the object is presented to the runtime) the the channel should +** block before abandoning the process. +** +** The success of the wait operation will be noted in the object's +** 'outcome' field. The fields are not valid when the NSPR runtime +** is in possession of the object. +** +** The memory descriptor describes an interval of writable memory +** in the caller's address space where data from an initial read +** can be placed. The description may indicate a null interval. +*/ +typedef struct PRRecvWait +{ + PRCList internal; /* internal runtime linkages */ + + PRFileDesc *fd; /* file descriptor associated w/ object */ + PRMWStatus outcome; /* outcome of the current/last operation */ + PRIntervalTime timeout; /* time allowed for entire operation */ + + 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 +** DESCRIPTION: +** This function will effectively add a file descriptor to the +** list of those waiting for network receive. The new descriptor +** will be semantically tied to the wait group specified. +** +** The ownership for the storage pointed to by 'desc' is temporarily +** passed over the the NSPR runtime. It will be handed back by the +** function PR_WaitRecvReady(). +** +** INPUTS +** group A reference to a PRWaitGroup or NULL. Wait groups are +** created by calling PR_CreateWaitGroup() and are used +** 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 not be modified +** until its ownership is returned to the client. +** RETURN +** PRStatus An indication of success. If equal to PR_FAILUE details +** of the failure are avaiable via PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** Invalid 'group' identifier or duplicate 'desc' object. +** PR_OUT_OF_MEMORY_ERROR +** Insuffient memory for internal data structures. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRStatus) PR_AddWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); + +/* +** FUNCTION: PR_WaitRecvReady +** DESCRIPTION: +** PR_WaitRecvReady will block the calling thread until one of the +** file descriptors that have been added via PR_AddWaitFileDesc is +** available for input I/O. +** INPUT +** group A pointer to a valid PRWaitGroup or NULL (the null +** group. The function will block the caller until a +** channel from the wait group becomes ready for receive +** or there is some sort of error. +** RETURN +** PRReciveWait +** When the caller is resumed it is either returned a +** valid pointer to a previously added receive wait or +** a NULL. If the latter, the function has terminated +** for a reason that can be determined by calling +** PR_GetError(). +** If a valid pointer is returned, the reference is to the +** file descriptor contained in the receive wait object. +** The outcome of the wait operation may still fail, and +** if it has, that fact will be noted in the object's +** outcome field. Details can be retrieved from PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' is not known by the runtime. +** PR_PENDING_INTERRUPT_ERROR + The thread was interrupted. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group); + +/* +** FUNCTION: PR_CancelWaitFileDesc +** DESCRIPTION: +** PR_CancelWaitFileDesc is provided as a means for cancelling operations +** on objects previously submitted by use of PR_AddWaitFileDesc(). If +** the runtime knows of the object, it will be marked as having failed +** because it was interrupted (similar to PR_Interrupt()). The first +** available thread waiting on the group will be made to return the +** PRRecvWait object with the outcome noted. +** +** INPUTS +** group The wait group under which the wait receive object was +** added. +** desc A pointer to the wait receive object that is to be +** cancelled. +** RETURN +** PRStatus If the wait receive object was located and associated +** with the specified wait group, the status returned will +** be PR_SUCCESS. There is still a race condition that would +** permit the offected object to complete normally, but it +** is assured that it will complete in the near future. +** If the receive object or wait group are invalid, the +** function will return with a status of PR_FAILURE. +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument is not recognized as a valid group. +** PR_COLLECTION_EMPTY_ERROR +** There are no more receive wait objects in the group's +** collection. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); + +/* +** FUNCTION: PR_CancelWaitGroup +** DESCRIPTION: +** PR_CancelWaitGroup is provided as a means for cancelling operations +** on objects previously submitted by use of PR_AddWaitFileDesc(). Each +** successive call will return a pointer to a PRRecvWait object that +** was previously registered via PR_AddWaitFileDesc(). If no wait +** objects are associated with the wait group, a NULL will be returned. +** This function should be called in a loop until a NULL is returned +** to reclaim all the wait objects prior to calling PR_DestroyWaitGroup(). +** +** INPUTS +** group The wait group under which the wait receive object was +** added. +** RETURN +** PRRecvWait* If the wait group is valid and at least one receive wait +** object is present in the group, that object will be +** marked as PR_MW_INTERRUPT'd and removed from the group's +** queues. Otherwise a NULL will be returned and the reason +** for the NULL may be retrieved by calling PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** PR_GROUP_EMPTY_ERROR +*/ +NSPR_API(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group); + +/* +** FUNCTION: PR_CreateWaitGroup +** DESCRIPTION: +** A wait group is an opaque object that a client may create in order +** to semantically group various wait requests. Each wait group is +** unique, including the default wait group (NULL). A wait request +** that was added under a wait group will only be serviced by a caller +** that specified the same wait group. +** +** INPUT +** size The size of the hash table to be used to contain the +** receive wait objects. This is just the initial size. +** It will grow as it needs to, but to avoid that hassle +** one can suggest a suitable size initially. It should +** be ~30% larger than the maximum number of receive wait +** objects expected. +** RETURN +** PRWaitGroup If successful, the function will return a pointer to an +** object that was allocated by and owned by the runtime. +** The reference remains valid until it is explicitly destroyed +** by calling PR_DestroyWaitGroup(). +** +** ERRORS +** PR_OUT_OF_MEMORY_ERROR +*/ +NSPR_API(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size); + +/* +** FUNCTION: PR_DestroyWaitGroup +** DESCRIPTION: +** Undo the effects of PR_CreateWaitGroup(). Any receive wait operations +** on the group will be treated as if the each had been the target of a +** PR_CancelWaitFileDesc(). +** +** INPUT +** group Reference to a wait group previously allocated using +** PR_CreateWaitGroup(). +** RETURN +** PRStatus Will be PR_SUCCESS if the wait group was valid and there +** are no receive wait objects in that group. Otherwise +** will indicate PR_FAILURE. +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument does not reference a known object. +** PR_INVALID_STATE_ERROR +** The group still contains receive wait objects. +*/ +NSPR_API(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 +*/ +NSPR_API(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. +*/ +NSPR_API(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. +*/ +NSPR_API(PRRecvWait*) PR_EnumerateWaitGroup( + PRMWaitEnumerator *enumerator, const PRRecvWait *previous); + +PR_END_EXTERN_C + +#endif /* defined(_PRMWAIT_H) */ + +/* prmwait.h */ diff --git a/nsprpub/pr/include/prnetdb.h b/nsprpub/pr/include/prnetdb.h new file mode 100644 index 00000000000..685efbbc145 --- /dev/null +++ b/nsprpub/pr/include/prnetdb.h @@ -0,0 +1,499 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prnetdb_h___ +#define prnetdb_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + + +/* + ********************************************************************* + * Translate an Internet address to/from a character string + ********************************************************************* + */ +NSPR_API(PRStatus) PR_StringToNetAddr( + const char *string, PRNetAddr *addr); + +NSPR_API(PRStatus) PR_NetAddrToString( + const PRNetAddr *addr, char *string, PRUint32 size); + +/* +** Structures returned by network data base library. All addresses are +** supplied in host order, and returned in network order (suitable for +** use in system calls). +*/ +/* +** Beware that WINSOCK.H defines h_addrtype and h_length as short. +** Client code does direct struct copies of hostent to PRHostEnt and +** hence the ifdef. +*/ +typedef struct PRHostEnt { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ +#if defined(WIN32) || defined(WIN16) + PRInt16 h_addrtype; /* host address type */ + PRInt16 h_length; /* length of address */ +#else + PRInt32 h_addrtype; /* host address type */ + PRInt32 h_length; /* length of address */ +#endif + char **h_addr_list; /* list of addresses from name server */ +} PRHostEnt; + +/* A safe size to use that will mostly work... */ +#if (defined(AIX) && defined(_THREAD_SAFE)) || defined(OSF1) +#define PR_NETDB_BUF_SIZE sizeof(struct protoent_data) +#else +#define PR_NETDB_BUF_SIZE 1024 +#endif + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetHostByName() +** Lookup a host by name. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetHostByName( + const char *hostname, char *buf, PRIntn bufsize, PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetIPNodeByName() +** Lookup a host by name. Equivalent to getipnodebyname(AI_DEFAULT) +** of RFC 2553. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** PRUint16 af Address family (either PR_AF_INET or PR_AF_INET6) +** PRIntn flags Specifies the types of addresses that are searched +** for and the types of addresses that are returned. +** The only supported flag is PR_AI_DEFAULT. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ + + +#define PR_AI_ALL 0x08 +#define PR_AI_V4MAPPED 0x10 +#define PR_AI_ADDRCONFIG 0x20 +#define PR_AI_NOCANONNAME 0x8000 +#define PR_AI_DEFAULT (PR_AI_V4MAPPED | PR_AI_ADDRCONFIG) + +NSPR_API(PRStatus) PR_GetIPNodeByName( + const char *hostname, + PRUint16 af, + PRIntn flags, + char *buf, + PRIntn bufsize, + PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetHostByAddr() +** Lookup a host entry by its network address. +** +** INPUTS: +** char *hostaddr IP address of host in question +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetHostByAddr( + const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: PR_EnumerateHostEnt() +** DESCRIPTION: +** A stateless enumerator over a PRHostEnt structure acquired from +** PR_GetHostByName() PR_GetHostByAddr() to evaluate the possible +** network addresses. +** +** INPUTS: +** PRIntn enumIndex Index of the enumeration. The enumeration starts +** and ends with a value of zero. +** +** PRHostEnt *hostEnt A pointer to a host entry struct that was +** previously returned by PR_GetHostByName() or +** PR_GetHostByAddr(). +** +** PRUint16 port The port number to be assigned as part of the +** PRNetAddr. +** +** OUTPUTS: +** PRNetAddr *address A pointer to an address structure that will be +** filled in by the call to the enumeration if the +** result of the call is greater than zero. +** +** RETURN: +** PRIntn The value that should be used for the next call +** of the enumerator ('enumIndex'). The enumeration +** is ended if this value is returned zero. +** If a value of -1 is returned, the enumeration +** has failed. The reason for the failure can be +** retrieved by calling PR_GetError(). +***********************************************************************/ +NSPR_API(PRIntn) PR_EnumerateHostEnt( + PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address); + +/*********************************************************************** +** FUNCTION: PR_InitializeNetAddr(), +** DESCRIPTION: +** Initialize the fields of a PRNetAddr, assigning well known values as +** appropriate. +** +** INPUTS +** PRNetAddrValue val The value to be assigned to the IP Address portion +** of the network address. This can only specify the +** special well known values that are equivalent to +** INADDR_ANY and INADDR_LOOPBACK. +** +** PRUint16 port The port number to be assigned in the structure. +** +** OUTPUTS: +** PRNetAddr *addr The address to be manipulated. +** +** RETURN: +** PRStatus To indicate success or failure. If the latter, the +** reason for the failure can be retrieved by calling +** PR_GetError(); +***********************************************************************/ +typedef enum PRNetAddrValue +{ + PR_IpAddrNull, /* do NOT overwrite the IP address */ + PR_IpAddrAny, /* assign logical INADDR_ANY to IP address */ + PR_IpAddrLoopback, /* assign logical INADDR_LOOPBACK */ + PR_IpAddrV4Mapped /* IPv4 mapped address */ +} PRNetAddrValue; + +NSPR_API(PRStatus) PR_InitializeNetAddr( + PRNetAddrValue val, PRUint16 port, PRNetAddr *addr); + +/*********************************************************************** +** FUNCTION: PR_SetNetAddr(), +** DESCRIPTION: +** Set the fields of a PRNetAddr, assigning well known values as +** appropriate. This function is similar to PR_InitializeNetAddr +** but differs in that the address family is specified. +** +** INPUTS +** PRNetAddrValue val The value to be assigned to the IP Address portion +** of the network address. This can only specify the +** special well known values that are equivalent to +** INADDR_ANY and INADDR_LOOPBACK. +** +** PRUint16 af The address family (either PR_AF_INET or PR_AF_INET6) +** +** PRUint16 port The port number to be assigned in the structure. +** +** OUTPUTS: +** PRNetAddr *addr The address to be manipulated. +** +** RETURN: +** PRStatus To indicate success or failure. If the latter, the +** reason for the failure can be retrieved by calling +** PR_GetError(); +***********************************************************************/ +NSPR_API(PRStatus) PR_SetNetAddr( + PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_IsNetAddrType() +** Determine if the network address is of the specified type. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** PRNetAddrValue The type of network address +** +** RETURN: +** PRBool PR_TRUE if the network address is of the +** specified type, else PR_FALSE. +***********************************************************************/ +NSPR_API(PRBool) PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_ConvertIPv4AddrToIPv6() +** Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr +** +** INPUTS: +** PRUint32 v4addr IPv4 address +** +** OUTPUTS: +** PRIPv6Addr *v6addr The converted IPv6 address +** +** RETURN: +** void +** +***********************************************************************/ +NSPR_API(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr); + +/*********************************************************************** +** MACRO: +** DESCRIPTION: PR_NetAddrFamily() +** Get the 'family' field of a PRNetAddr union. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** +** RETURN: +** PRUint16 The 'family' field of 'addr'. +***********************************************************************/ +#define PR_NetAddrFamily(addr) ((addr)->raw.family) + +/*********************************************************************** +** MACRO: +** DESCRIPTION: PR_NetAddrInetPort() +** Get the 'port' field of a PRNetAddr union. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** +** RETURN: +** PRUint16 The 'port' field of 'addr'. +***********************************************************************/ +#define PR_NetAddrInetPort(addr) \ + ((addr)->raw.family == PR_AF_INET6 ? (addr)->ipv6.port : (addr)->inet.port) + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetProtoByName() +** Lookup a protocol entry based on protocol's name +** +** INPUTS: +** char *protocolname Character string of the protocol's name. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *PRProtoEnt +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ + +typedef struct PRProtoEnt { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ +#if defined(WIN32) || defined(WIN16) + PRInt16 p_num; /* protocol # */ +#else + PRInt32 p_num; /* protocol # */ +#endif +} PRProtoEnt; + +NSPR_API(PRStatus) PR_GetProtoByName( + const char* protocolname, char* buffer, PRInt32 bufsize, PRProtoEnt* result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetProtoByNumber() +** Lookup a protocol entry based on protocol's number +** +** INPUTS: +** PRInt32 protocolnumber +** Number assigned to the protocol. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *PRProtoEnt +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetProtoByNumber( + PRInt32 protocolnumber, char* buffer, PRInt32 bufsize, PRProtoEnt* result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetAddrInfoByName() +** Lookup a host by name. Equivalent to getaddrinfo(host, NULL, ...) of +** RFC 3493. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** PRUint16 af May be PR_AF_UNSPEC or PR_AF_INET. +** PRIntn flags May be either PR_AI_ADDRCONFIG or +** PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME. Include +** PR_AI_NOCANONNAME to suppress the determination of +** the canonical name corresponding to hostname. +** RETURN: +** PRAddrInfo* Handle to a data structure containing the results +** of the host lookup. Use PR_EnumerateAddrInfo to +** inspect the PRNetAddr values stored in this object. +** When no longer needed, this handle must be destroyed +** with a call to PR_FreeAddrInfo. If a lookup error +** occurs, then NULL will be returned. +***********************************************************************/ +typedef struct PRAddrInfo PRAddrInfo; + +NSPR_API(PRAddrInfo*) PR_GetAddrInfoByName( + const char *hostname, PRUint16 af, PRIntn flags); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_FreeAddrInfo() +** Destroy the PRAddrInfo handle allocated by PR_GetAddrInfoByName(). +** +** INPUTS: +** PRAddrInfo *addrInfo +** The handle resulting from a successful call to +** PR_GetAddrInfoByName(). +** RETURN: +** void +***********************************************************************/ +NSPR_API(void) PR_FreeAddrInfo(PRAddrInfo *addrInfo); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_EnumerateAddrInfo() +** A stateless enumerator over a PRAddrInfo handle acquired from +** PR_GetAddrInfoByName() to inspect the possible network addresses. +** +** INPUTS: +** void *enumPtr Index pointer of the enumeration. The enumeration +** starts and ends with a value of NULL. +** PRAddrInfo *addrInfo +** The PRAddrInfo handle returned by a successful +** call to PR_GetAddrInfoByName(). +** PRUint16 port The port number to be assigned as part of the +** PRNetAddr. +** OUTPUTS: +** PRNetAddr *result A pointer to an address structure that will be +** filled in by the call to the enumeration if the +** result of the call is greater than zero. +** RETURN: +** void* The value that should be used for the next call +** of the enumerator ('enumPtr'). The enumeration +** is ended if this value is returned NULL. +***********************************************************************/ +NSPR_API(void *) PR_EnumerateAddrInfo( + void *enumPtr, const PRAddrInfo *addrInfo, PRUint16 port, PRNetAddr *result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetCanonNameFromAddrInfo() +** Extracts the canonical name of the hostname passed to +** PR_GetAddrInfoByName(). +** +** INPUTS: +** PRAddrInfo *addrInfo +** The PRAddrInfo handle returned by a successful +** call to PR_GetAddrInfoByName(). +** RETURN: +** const char * A const pointer to the canonical hostname stored +** in the given PRAddrInfo handle. This pointer is +** invalidated once the PRAddrInfo handle is destroyed +** by a call to PR_FreeAddrInfo(). +***********************************************************************/ +NSPR_API(const char *) PR_GetCanonNameFromAddrInfo( + const PRAddrInfo *addrInfo); + +/*********************************************************************** +** FUNCTIONS: PR_ntohs, PR_ntohl, PR_ntohll, PR_htons, PR_htonl, PR_htonll +** +** DESCRIPTION: API entries for the common byte ordering routines. +** +** PR_ntohs 16 bit conversion from network to host +** PR_ntohl 32 bit conversion from network to host +** PR_ntohll 64 bit conversion from network to host +** PR_htons 16 bit conversion from host to network +** PR_htonl 32 bit conversion from host to network +** PR_ntonll 64 bit conversion from host to network +** +***********************************************************************/ +NSPR_API(PRUint16) PR_ntohs(PRUint16); +NSPR_API(PRUint32) PR_ntohl(PRUint32); +NSPR_API(PRUint64) PR_ntohll(PRUint64); +NSPR_API(PRUint16) PR_htons(PRUint16); +NSPR_API(PRUint32) PR_htonl(PRUint32); +NSPR_API(PRUint64) PR_htonll(PRUint64); + +PR_END_EXTERN_C + +#endif /* prnetdb_h___ */ diff --git a/nsprpub/pr/include/prolock.h b/nsprpub/pr/include/prolock.h new file mode 100644 index 00000000000..d8aece986c5 --- /dev/null +++ b/nsprpub/pr/include/prolock.h @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prolock_h___ +#define prolock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** 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. +** +*/ + +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +typedef void * PROrderedLock; +#else +/* +** Map PROrderedLock and methods onto PRLock when ordered locking +** is not compiled in. +** +*/ +#include "prlock.h" + +typedef PRLock PROrderedLock; +#endif + +/* ----------------------------------------------------------------------- +** 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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_CREATE_ORDERED_LOCK(order,name)\ + PR_CreateOrderedLock((order),(name)) +#else +#define PR_CREATE_ORDERED_LOCK(order) PR_NewLock() +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyOrderedLock((lock)) +#else +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyLock((lock)) +#endif + +NSPR_API(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 function asserts. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_LOCK_ORDERED_LOCK(lock) PR_LockOrderedLock((lock)) +#else +#define PR_LOCK_ORDERED_LOCK(lock) PR_Lock((lock)) +#endif + +NSPR_API(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: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_UnlockOrderedLock((lock)) +#else +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_Unlock((lock)) +#endif + +NSPR_API(PRStatus) + PR_UnlockOrderedLock( + PROrderedLock *lock +); + +PR_END_EXTERN_C + +#endif /* prolock_h___ */ diff --git a/nsprpub/pr/include/prpdce.h b/nsprpub/pr/include/prpdce.h new file mode 100644 index 00000000000..ebd595ac52d --- /dev/null +++ b/nsprpub/pr/include/prpdce.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: prpdce.h + * Description: This file is the API defined to allow for DCE (aka POSIX) + * thread emulation in an NSPR environment. It is not the + * intent that this be a fully supported API. + */ + +#if !defined(PRPDCE_H) +#define PRPDCE_H + +#include "prlock.h" +#include "prcvar.h" +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +#define _PR_NAKED_CV_LOCK (PRLock*)0xdce1dce1 + +/* +** Test and acquire a lock. +** +** If the lock is acquired by the calling thread, the +** return value will be PR_SUCCESS. If the lock is +** already held, by another thread or this thread, the +** result will be PR_FAILURE. +*/ +NSPR_API(PRStatus) PRP_TryLock(PRLock *lock); + +/* +** Create a naked condition variable +** +** A "naked" condition variable is one that is not created bound +** to a lock. The CV created with this function is the only type +** that may be used in the subsequent "naked" condition variable +** operations (see PRP_NakedWait, PRP_NakedNotify, PRP_NakedBroadcast); +*/ +NSPR_API(PRCondVar*) PRP_NewNakedCondVar(void); + +/* +** Destroy a naked condition variable +** +** Destroy the condition variable created by PR_NewNakedCondVar. +*/ +NSPR_API(void) PRP_DestroyNakedCondVar(PRCondVar *cvar); + +/* +** Wait on a condition +** +** Wait on the condition variable 'cvar'. It is asserted that +** the lock protecting the condition 'lock' is held by the +** calling thread. If more time expires than that declared in +** 'timeout' the condition will be notified. Waits can be +** interrupted by another thread. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedWait( + PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout); + +/* +** Notify a thread waiting on a condition +** +** Notify the condition specified 'cvar'. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedNotify(PRCondVar *cvar); + +/* +** Notify all threads waiting on a condition +** +** Notify the condition specified 'cvar'. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar); + +PR_END_EXTERN_C + +#endif /* PRPDCE_H */ diff --git a/nsprpub/pr/include/prprf.h b/nsprpub/pr/include/prprf.h new file mode 100644 index 00000000000..7336d97f2d7 --- /dev/null +++ b/nsprpub/pr/include/prprf.h @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prprf_h___ +#define prprf_h___ + +/* +** API for PR printf like routines. Supports the following formats +** %d - decimal +** %u - unsigned decimal +** %x - unsigned hex +** %X - unsigned uppercase hex +** %o - unsigned octal +** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above +** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above +** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above +** %s - string +** %c - character +** %p - pointer (deals with machine dependent pointer size) +** %f - float +** %g - float +*/ +#include "prtypes.h" +#include "prio.h" +#include +#include + +PR_BEGIN_EXTERN_C + +/* +** sprintf into a fixed size buffer. Guarantees that a NUL is at the end +** of the buffer. Returns the length of the written output, NOT including +** the NUL, or (PRUint32)-1 if an error occurs. +*/ +NSPR_API(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...); + +/* +** sprintf into a PR_MALLOC'd buffer. Return a pointer to the malloc'd +** buffer on success, NULL on failure. Call "PR_smprintf_free" to release +** the memory returned. +*/ +NSPR_API(char*) PR_smprintf(const char *fmt, ...); + +/* +** Free the memory allocated, for the caller, by PR_smprintf +*/ +NSPR_API(void) PR_smprintf_free(char *mem); + +/* +** "append" sprintf into a PR_MALLOC'd buffer. "last" is the last value of +** the PR_MALLOC'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is NULL, PR_sprintf_append +** will allocate the initial string. The return value is the new value of +** last for subsequent calls, or NULL if there is a malloc failure. +*/ +NSPR_API(char*) PR_sprintf_append(char *last, const char *fmt, ...); + +/* +** sprintf into a function. The function "f" is called with a string to +** place into the output. "arg" is an opaque pointer used by the stuff +** function to hold any state needed to do the storage of the output +** data. The return value is a count of the number of characters fed to +** the stuff function, or (PRUint32)-1 if an error occurs. +*/ +typedef PRIntn (*PRStuffFunc)(void *arg, const char *s, PRUint32 slen); + +NSPR_API(PRUint32) PR_sxprintf(PRStuffFunc f, void *arg, const char *fmt, ...); + +/* +** fprintf to a PRFileDesc +*/ +NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...); + +/* +** va_list forms of the above. +*/ +NSPR_API(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen, const char *fmt, va_list ap); +NSPR_API(char*) PR_vsmprintf(const char *fmt, va_list ap); +NSPR_API(char*) PR_vsprintf_append(char *last, const char *fmt, va_list ap); +NSPR_API(PRUint32) PR_vsxprintf(PRStuffFunc f, void *arg, const char *fmt, va_list ap); +NSPR_API(PRUint32) PR_vfprintf(struct PRFileDesc* fd, const char *fmt, va_list ap); + +/* +*************************************************************************** +** FUNCTION: PR_sscanf +** DESCRIPTION: +** PR_sscanf() scans the input character string, performs data +** conversions, and stores the converted values in the data objects +** pointed to by its arguments according to the format control +** string. +** +** PR_sscanf() behaves the same way as the sscanf() function in the +** Standard C Library (stdio.h), with the following exceptions: +** - PR_sscanf() handles the NSPR integer and floating point types, +** such as PRInt16, PRInt32, PRInt64, and PRFloat64, whereas +** sscanf() handles the standard C types like short, int, long, +** and double. +** - PR_sscanf() has no multibyte character support, while sscanf() +** does. +** INPUTS: +** const char *buf +** a character string holding the input to scan +** const char *fmt +** the format control string for the conversions +** ... +** variable number of arguments, each of them is a pointer to +** a data object in which the converted value will be stored +** OUTPUTS: none +** RETURNS: PRInt32 +** The number of values converted and stored. +** RESTRICTIONS: +** Multibyte characters in 'buf' or 'fmt' are not allowed. +*************************************************************************** +*/ + +NSPR_API(PRInt32) PR_sscanf(const char *buf, const char *fmt, ...); + +PR_END_EXTERN_C + +#endif /* prprf_h___ */ diff --git a/nsprpub/pr/include/prproces.h b/nsprpub/pr/include/prproces.h new file mode 100644 index 00000000000..0c1e8a65fd1 --- /dev/null +++ b/nsprpub/pr/include/prproces.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prproces_h___ +#define prproces_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/*****************************PROCESS OPERATIONS*************************/ +/************************************************************************/ + +typedef struct PRProcess PRProcess; +typedef struct PRProcessAttr PRProcessAttr; + +NSPR_API(PRProcessAttr *) PR_NewProcessAttr(void); + +NSPR_API(void) PR_ResetProcessAttr(PRProcessAttr *attr); + +NSPR_API(void) PR_DestroyProcessAttr(PRProcessAttr *attr); + +NSPR_API(void) PR_ProcessAttrSetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd +); + +/* + * OBSOLETE -- use PR_ProcessAttrSetStdioRedirect instead. + */ +NSPR_API(void) PR_SetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd +); + +NSPR_API(PRStatus) PR_ProcessAttrSetCurrentDirectory( + PRProcessAttr *attr, + const char *dir +); + +NSPR_API(PRStatus) PR_ProcessAttrSetInheritableFD( + PRProcessAttr *attr, + PRFileDesc *fd, + const char *name +); + +/* +** Create a new process +** +** Create a new process executing the file specified as 'path' and with +** the supplied arguments and environment. +** +** This function may fail because of illegal access (permissions), +** invalid arguments or insufficient resources. +** +** A process may be created such that the creator can later synchronize its +** termination using PR_WaitProcess(). +*/ + +NSPR_API(PRProcess*) PR_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); + +NSPR_API(PRStatus) PR_CreateProcessDetached( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); + +NSPR_API(PRStatus) PR_DetachProcess(PRProcess *process); + +NSPR_API(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode); + +NSPR_API(PRStatus) PR_KillProcess(PRProcess *process); + +PR_END_EXTERN_C + +#endif /* prproces_h___ */ diff --git a/nsprpub/pr/include/prrng.h b/nsprpub/pr/include/prrng.h new file mode 100644 index 00000000000..e94b806b8c9 --- /dev/null +++ b/nsprpub/pr/include/prrng.h @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* +** prrng.h -- NSPR Random Number Generator +** +** +** lth. 29-Oct-1999. +*/ + +#ifndef prrng_h___ +#define prrng_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_GetRandomNoise() -- Get random noise from the host platform +** +** Description: +** PR_GetRandomNoise() provides, depending on platform, a random value. +** The length of the random value is dependent on platform and the +** platform's ability to provide a random value at that moment. +** +** The intent of PR_GetRandomNoise() is to provide a "seed" value for a +** another random number generator that may be suitable for +** cryptographic operations. This implies that the random value +** provided may not be, by itself, cryptographically secure. The value +** generated by PR_GetRandomNoise() is at best, extremely difficult to +** predict and is as non-deterministic as the underlying platfrom can +** provide. +** +** Inputs: +** buf -- pointer to a caller supplied buffer to contain the +** generated random number. buf must be at least as large as +** is specified in the 'size' argument. +** +** size -- the requested size of the generated random number +** +** Outputs: +** a random number provided in 'buf'. +** +** Returns: +** PRSize value equal to the size of the random number actually +** generated, or zero. The generated size may be less than the size +** requested. A return value of zero means that PR_GetRandomNoise() is +** not implemented on this platform, or there is no available noise +** available to be returned at the time of the call. +** +** Restrictions: +** Calls to PR_GetRandomNoise() may use a lot of CPU on some platforms. +** Some platforms may block for up to a few seconds while they +** accumulate some noise. Busy machines generate lots of noise, but +** care is advised when using PR_GetRandomNoise() frequently in your +** application. +** +** History: +** Parts of the model dependent implementation for PR_GetRandomNoise() +** were taken in whole or part from code previously in Netscape's NSS +** component. +** +*/ +NSPR_API(PRSize) PR_GetRandomNoise( + void *buf, + PRSize size +); + +PR_END_EXTERN_C + +#endif /* prrng_h___ */ +/* end prrng.h */ diff --git a/nsprpub/pr/include/prrwlock.h b/nsprpub/pr/include/prrwlock.h new file mode 100644 index 00000000000..945e5f88d21 --- /dev/null +++ b/nsprpub/pr/include/prrwlock.h @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prrwlock.h +** Description: API to basic reader-writer lock functions of NSPR. +** +**/ + +#ifndef prrwlock_h___ +#define prrwlock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* + * PRRWLock -- + * + * The reader writer lock, PRRWLock, is an opaque object to the clients + * of NSPR. All routines operate on a pointer to this opaque entity. + */ + + +typedef struct PRRWLock PRRWLock; + +#define PR_RWLOCK_RANK_NONE 0 + + +/*********************************************************************** +** FUNCTION: PR_NewRWLock +** DESCRIPTION: +** Returns a pointer to a newly created reader-writer lock object. +** INPUTS: Lock rank +** Lock name +** OUTPUTS: void +** RETURN: PRRWLock* +** If the lock cannot be created because of resource constraints, NULL +** is returned. +** +***********************************************************************/ +NSPR_API(PRRWLock*) PR_NewRWLock(PRUint32 lock_rank, const char *lock_name); + +/*********************************************************************** +** FUNCTION: PR_DestroyRWLock +** DESCRIPTION: +** Destroys a given RW lock object. +** INPUTS: PRRWLock *lock - Lock to be freed. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_DestroyRWLock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Rlock +** DESCRIPTION: +** Apply a read lock (non-exclusive) on a RWLock +** INPUTS: PRRWLock *lock - Lock to be read-locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_RWLock_Rlock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Wlock +** DESCRIPTION: +** Apply a write lock (exclusive) on a RWLock +** INPUTS: PRRWLock *lock - Lock to write-locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_RWLock_Wlock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Unlock +** DESCRIPTION: +** Release a RW lock. Unlocking an unlocked lock has undefined results. +** INPUTS: PRRWLock *lock - Lock to unlocked. +** OUTPUTS: void +** RETURN: void +***********************************************************************/ +NSPR_API(void) PR_RWLock_Unlock(PRRWLock *lock); + +PR_END_EXTERN_C + +#endif /* prrwlock_h___ */ diff --git a/nsprpub/pr/include/prshm.h b/nsprpub/pr/include/prshm.h new file mode 100644 index 00000000000..098566ec7fe --- /dev/null +++ b/nsprpub/pr/include/prshm.h @@ -0,0 +1,289 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** prshm.h -- NSPR Shared Memory +** +** NSPR Named Shared Memory API provides a cross-platform named +** shared-memory interface. NSPR Named Shared Memory is modeled on +** similar constructs in Unix and Windows operating systems. Shared +** memory allows multiple processes to access one or more common shared +** memory regions, using it as an inter-process communication channel. +** +** Notes on Platform Independence: +** NSPR Named Shared Memory is built on the native services offered +** by most platforms. The NSPR Named Shared Memory API tries to +** provide a least common denominator interface so that it works +** across all supported platforms. To ensure that it works everywhere, +** some platform considerations must be accomodated and the protocol +** for using NSPR Shared Memory API must be observed. +** +** Protocol: +** Multiple shared memories can be created using NSPR's Shared Memory +** feature. For each named shared memory, as defined by the name +** given in the PR_OpenSharedMemory() call, a protocol for using the +** shared memory API is required to ensure desired behavior. Failing +** to follow the protocol may yield unpredictable results. +** +** PR_OpenSharedMemory() will create the shared memory segment, if it +** does not already exist, or open a connection that the existing +** shared memory segment if it already exists. +** +** PR_AttachSharedMemory() should be called following +** PR_OpenSharedMemory() to map the memory segment to an address in +** the application's address space. +** +** PR_AttachSharedMemory() may be called to re-map a shared memory +** segment after detaching the same PRSharedMemory object. Be +** sure to detach it when done. +** +** PR_DetachSharedMemory() should be called to un-map the shared +** memory segment from the application's address space. +** +** PR_CloseSharedMemory() should be called when no further use of the +** PRSharedMemory object is required within a process. Following a +** call to PR_CloseSharedMemory() the PRSharedMemory object is +** invalid and cannot be reused. +** +** PR_DeleteSharedMemory() should be called before process +** termination. After calling PR_DeleteSharedMemory() any further use +** of the shared memory associated with the name may cause +** unpredictable results. +** +** Files: +** The name passed to PR_OpenSharedMemory() should be a valid filename +** for a unix platform. PR_OpenSharedMemory() creates file using the +** name passed in. Some platforms may mangle the name before creating +** the file and the shared memory. +** +** The unix implementation may use SysV IPC shared memory, Posix +** shared memory, or memory mapped files; the filename may used to +** define the namespace. On Windows, the name is significant, but +** there is no file associated with name. +** +** No assumptions about the persistence of data in the named file +** should be made. Depending on platform, the shared memory may be +** mapped onto system paging space and be discarded at process +** termination. +** +** All names provided to PR_OpenSharedMemory() should be valid +** filename syntax or name syntax for shared memory for the target +** platform. Referenced directories should have permissions +** appropriate for writing. +** +** Limits: +** Different platforms have limits on both the number and size of +** shared memory resources. The default system limits on some +** platforms may be smaller than your requirements. These limits may +** be adjusted on some platforms either via boot-time options or by +** setting the size of the system paging space to accomodate more +** and/or larger shared memory segment(s). +** +** Security: +** On unix platforms, depending on implementation, contents of the +** backing store for the shared memory can be exposed via the file +** system. Set permissions and or access controls at create and attach +** time to ensure you get the desired security. +** +** On windows platforms, no special security measures are provided. +** +** Example: +** The test case pr/tests/nameshm1.c provides an example of use as +** well as testing the operation of NSPR's Named Shared Memory. +** +** lth. 18-Aug-1999. +*/ + +#ifndef prshm_h___ +#define prshm_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/* +** Declare opaque type PRSharedMemory. +*/ +typedef struct PRSharedMemory PRSharedMemory; + +/* +** FUNCTION: PR_OpenSharedMemory() +** +** DESCRIPTION: +** PR_OpenSharedMemory() creates a new shared-memory segment or +** associates a previously created memory segment with name. +** +** When parameter create is (PR_SHM_EXCL | PR_SHM_CREATE) and the +** shared memory already exists, the function returns NULL with the +** error set to PR_FILE_EXISTS_ERROR. +** +** When parameter create is PR_SHM_CREATE and the shared memory +** already exists, a handle to that memory segment is returned. If +** the segment does not exist, it is created and a pointer to the +** related PRSharedMemory structure is returned. +** +** When parameter create is 0, and the shared memory exists, a +** pointer to a PRSharedMemory is returned. If the shared memory does +** not exist, NULL is returned with the error set to +** PR_FILE_NOT_FOUND_ERROR. +** +** INPUTS: +** name -- the name the shared-memory segment is known as. +** size -- the size of the shared memory segment. +** flags -- Options for creating the shared memory +** mode -- Same as is passed to PR_Open() +** +** OUTPUTS: +** The shared memory is allocated. +** +** RETURNS: Pointer to opaque structure PRSharedMemory or NULL. +** NULL is returned on error. The reason for the error can be +** retrieved via PR_GetError() and PR_GetOSError(); +** +*/ +NSPR_API( PRSharedMemory * ) + PR_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +); +/* Define values for PR_OpenShareMemory(...,create) */ +#define PR_SHM_CREATE 0x1 /* create if not exist */ +#define PR_SHM_EXCL 0x2 /* fail if already exists */ + +/* +** FUNCTION: PR_AttachSharedMemory() +** +** DESCRIPTION: +** PR_AttachSharedMemory() maps the shared-memory described by +** shm to the current process. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** flags -- options for mapping the shared memory. +** PR_SHM_READONLY causes the memory to be attached +** read-only. +** +** OUTPUTS: +** On success, the shared memory segment represented by shm is mapped +** into the process' address space. +** +** RETURNS: Address where shared memory is mapped, or NULL. +** NULL is returned on error. The reason for the error can be +** retrieved via PR_GetError() and PR_GetOSError(); +** +** +*/ +NSPR_API( void * ) + PR_AttachSharedMemory( + PRSharedMemory *shm, + PRIntn flags +); +/* Define values for PR_AttachSharedMemory(...,flags) */ +#define PR_SHM_READONLY 0x01 + +/* +** FUNCTION: PR_DetachSharedMemory() +** +** DESCRIPTION: +** PR_DetachSharedMemory() detaches the shared-memory described +** by shm. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** addr -- The address at which the memory was attached. +** +** OUTPUTS: +** The shared memory mapped to an address via a previous call to +** PR_AttachSharedMemory() is unmapped. +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_DetachSharedMemory( + PRSharedMemory *shm, + void *addr +); + +/* +** FUNCTION: PR_CloseSharedMemory() +** +** DESCRIPTION: +** PR_CloseSharedMemory() closes the shared-memory described by +** shm. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** +** OUTPUTS: +** the shared memory represented by shm is closed +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_CloseSharedMemory( + PRSharedMemory *shm +); + +/* +** FUNCTION: PR_DeleteSharedMemory() +** +** DESCRIPTION: +** The shared memory resource represented by name is released. +** +** INPUTS: +** name -- the name the shared-memory segment +** +** OUTPUTS: +** depending on platform, resources may be returned to the underlying +** operating system. +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_DeleteSharedMemory( + const char *name +); + +PR_END_EXTERN_C + +#endif /* prshm_h___ */ diff --git a/nsprpub/pr/include/prshma.h b/nsprpub/pr/include/prshma.h new file mode 100644 index 00000000000..e72ee85fa48 --- /dev/null +++ b/nsprpub/pr/include/prshma.h @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** prshma.h -- NSPR Anonymous Shared Memory +** +** NSPR provides an anonymous shared memory based on NSPR's PRFileMap +** type. The anonymous file-mapped shared memory provides an inheritable +** shared memory, as in: the child process inherits the shared memory. +** Compare the file-mapped anonymous shared memory to to a named shared +** memory described in prshm.h. The intent is to provide a shared +** memory that is accessable only by parent and child processes. ... +** It's a security thing. +** +** Depending on the underlying platform, the file-mapped shared memory +** may be backed by a file. ... surprise! ... On some platforms, no +** real file backs the shared memory. On platforms where the shared +** memory is backed by a file, the file's name in the filesystem is +** visible to other processes for only the duration of the creation of +** the file, hopefully a very short time. This restricts processess +** that do not inherit the shared memory from opening the file and +** reading or writing its contents. Further, when all processes +** using an anonymous shared memory terminate, the backing file is +** deleted. ... If you are not paranoid, you're not paying attention. +** +** The file-mapped shared memory requires a protocol for the parent +** process and child process to share the memory. NSPR provides two +** protocols. Use one or the other; don't mix and match. +** +** In the first protocol, the job of passing the inheritable shared +** memory is done via helper-functions with PR_CreateProcess(). In the +** second protocol, the parent process is responsible for creating the +** child process; the parent and child are mutually responsible for +** passing a FileMap string. NSPR provides helper functions for +** extracting data from the PRFileMap object. ... See the examples +** below. +** +** Both sides should adhere strictly to the protocol for proper +** operation. The pseudo-code below shows the use of a file-mapped +** shared memory by a parent and child processes. In the examples, the +** server creates the file-mapped shared memory, the client attaches to +** it. +** +** First protocol. +** Server: +** +** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); +** addr = PR_MemMap(fm); +** attr = PR_NewProcessAttr(); +** PR_ProcessAttrSetInheritableFileMap( attr, fm, shmname ); +** PR_CreateProcess(Client); +** PR_DestroyProcessAttr(attr); +** ... yadda ... +** PR_MemUnmap( addr ); +** PR_CloseFileMap(fm); +** +** +** Client: +** ... started by server via PR_CreateProcess() +** fm = PR_GetInheritedFileMap( shmname ); +** addr = PR_MemMap(fm); +** ... yadda ... +** PR_MemUnmap(addr); +** PR_CloseFileMap(fm); +** +** +** Second Protocol: +** Server: +** +** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); +** fmstring = PR_ExportFileMapAsString( fm ); +** addr = PR_MemMap(fm); +** ... application specific technique to pass fmstring to child +** ... yadda ... Server uses his own magic to create child +** PR_MemUnmap( addr ); +** PR_CloseFileMap(fm); +** +** +** Client: +** ... started by server via his own magic +** ... application specific technique to find fmstring from parent +** fm = PR_ImportFileMapFromString( fmstring ) +** addr = PR_MemMap(fm); +** ... yadda ... +** PR_MemUnmap(addr); +** PR_CloseFileMap(fm); +** +** +** lth. 2-Jul-1999. +** +** Note: The second protocol was requested by NelsonB (7/1999); this is +** to accomodate servers which already create their own child processes +** using platform native methods. +** +*/ + +#ifndef prshma_h___ +#define prshma_h___ + +#include "prtypes.h" +#include "prio.h" +#include "prproces.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory +** +** Description: +** PR_OpenAnonFileMap() creates an anonymous shared memory. If the +** shared memory already exists, a handle is returned to that shared +** memory object. +** +** On Unix platforms, PR_OpenAnonFileMap() uses 'dirName' as a +** directory name, without the trailing '/', to contain the anonymous +** file. A filename is generated for the name. +** +** On Windows platforms, dirName is ignored. +** +** Inputs: +** dirName -- A directory name to contain the anonymous file. +** size -- The size of the shared memory +** prot -- How the shared memory is mapped. See prio.h +** +** Outputs: +** PRFileMap * +** +** Returns: +** Pointer to PRFileMap or NULL on error. +** +*/ +NSPR_API( PRFileMap *) +PR_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +); + +/* +** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export +** to my children processes via PR_CreateProcess() +** +** Description: +** PR_ProcessAttrSetInheritableFileMap() connects the PRFileMap to +** PRProcessAttr with shmname. A subsequent call to PR_CreateProcess() +** makes the PRFileMap importable by the child process. +** +** Inputs: +** attr -- PRProcessAttr, used to pass data to PR_CreateProcess() +** fm -- PRFileMap structure to be passed to the child process +** shmname -- The name for the PRFileMap; used by child. +** +** Outputs: +** PRFileMap * +** +** Returns: +** PRStatus +** +*/ +NSPR_API(PRStatus) +PR_ProcessAttrSetInheritableFileMap( + PRProcessAttr *attr, + PRFileMap *fm, + const char *shmname +); + +/* +** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported +** by my parent process via PR_CreateProcess() +** +** Description: +** PR_GetInheritedFileMap() retrieves a PRFileMap object exported from +** its parent process via PR_CreateProcess(). +** +** Inputs: +** shmname -- The name provided to PR_ProcessAttrSetInheritableFileMap() +** +** Outputs: +** PRFileMap * +** +** Returns: +** PRFileMap pointer or NULL. +** +*/ +NSPR_API( PRFileMap *) +PR_GetInheritedFileMap( + const char *shmname +); + +/* +** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap +** +** Description: +** Creates an identifier, as a string, from a PRFileMap object +** previously created with PR_OpenAnonFileMap(). +** +** Inputs: +** fm -- PRFileMap pointer to be represented as a string. +** bufsize -- sizeof(buf) +** buf -- a buffer of length PR_FILEMAP_STRING_BUFSIZE +** +** Outputs: +** buf contains the stringized PRFileMap identifier +** +** Returns: +** PRStatus +** +*/ +NSPR_API( PRStatus ) +PR_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufsize, + char *buf +); +#define PR_FILEMAP_STRING_BUFSIZE 128 + +/* +** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string +** +** Description: +** PR_ImportFileMapFromString() creates a PRFileMap object from a +** string previously created by PR_ExportFileMapAsString(). +** +** Inputs: +** fmstring -- string created by PR_ExportFileMapAsString() +** +** Returns: +** PRFileMap pointer or NULL. +** +*/ +NSPR_API( PRFileMap * ) +PR_ImportFileMapFromString( + const char *fmstring +); + +PR_END_EXTERN_C +#endif /* prshma_h___ */ diff --git a/nsprpub/pr/include/prsystem.h b/nsprpub/pr/include/prsystem.h new file mode 100644 index 00000000000..13cf8babddf --- /dev/null +++ b/nsprpub/pr/include/prsystem.h @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prsystem_h___ +#define prsystem_h___ + +/* +** API to NSPR functions returning system info. +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** Get the host' directory separator. +** Pathnames are then assumed to be of the form: +** []*() +*/ + +NSPR_API(char) PR_GetDirectorySeparator(void); + +/* +** OBSOLETE -- the function name is misspelled. +** Use PR_GetDirectorySeparator instead. +*/ + +NSPR_API(char) PR_GetDirectorySepartor(void); + +/* +** Get the host' path separator. +** Paths are assumed to be of the form: +** []* +*/ + +NSPR_API(char) PR_GetPathSeparator(void); + +/* Types of information available via PR_GetSystemInfo(...) */ +typedef enum { + PR_SI_HOSTNAME, /* the hostname with the domain name (if any) + * removed */ + PR_SI_SYSNAME, + PR_SI_RELEASE, + PR_SI_ARCHITECTURE, + PR_SI_HOSTNAME_UNTRUNCATED /* the hostname exactly as configured + * on the system */ +} PRSysInfo; + + +/* +** If successful returns a null termintated string in 'buf' for +** the information indicated in 'cmd'. If unseccussful the reason for +** the failure can be retrieved from PR_GetError(). +** +** The buffer is allocated by the caller and should be at least +** SYS_INFO_BUFFER_LENGTH bytes in length. +*/ + +#define SYS_INFO_BUFFER_LENGTH 256 + +NSPR_API(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen); + +/* +** Return the number of bytes in a page +*/ +NSPR_API(PRInt32) PR_GetPageSize(void); + +/* +** Return log2 of the size of a page +*/ +NSPR_API(PRInt32) PR_GetPageShift(void); + +/* +** PR_GetNumberOfProcessors() -- returns the number of CPUs +** +** Description: +** PR_GetNumberOfProcessors() extracts the number of processors +** (CPUs available in an SMP system) and returns the number. +** +** Parameters: +** none +** +** Returns: +** The number of available processors or -1 on error +** +*/ +NSPR_API(PRInt32) PR_GetNumberOfProcessors( void ); + +/* +** PR_GetPhysicalMemorySize() -- returns the amount of system RAM +** +** Description: +** PR_GetPhysicalMemorySize() determines the amount of physical RAM +** in the system and returns the size in bytes. +** +** Parameters: +** none +** +** Returns: +** The amount of system RAM, or 0 on failure. +** +*/ +NSPR_API(PRUint64) PR_GetPhysicalMemorySize(void); + +PR_END_EXTERN_C + +#endif /* prsystem_h___ */ diff --git a/nsprpub/pr/include/prthread.h b/nsprpub/pr/include/prthread.h new file mode 100644 index 00000000000..dba1c9b8597 --- /dev/null +++ b/nsprpub/pr/include/prthread.h @@ -0,0 +1,286 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prthread_h___ +#define prthread_h___ + +/* +** API for NSPR threads. On some architectures (MAC and WIN16 +** notably) pre-emptibility is not guaranteed. Hard priority scheduling +** is not guaranteed, so programming using priority based synchronization +** is a no-no. +** +** NSPR threads are scheduled based loosely on their client set priority. +** In general, a thread of a higher priority has a statistically better +** chance of running relative to threads of lower priority. However, +** NSPR uses multiple strategies to provide execution vehicles for thread +** abstraction of various host platforms. As it turns out, there is little +** NSPR can do to affect the scheduling attributes of "GLOBAL" threads. +** However, a semblance of GLOBAL threads is used to implement "LOCAL" +** threads. An arbitrary number of such LOCAL threads can be assigned to +** a single GLOBAL thread. +** +** For scheduling, NSPR will attempt to run the highest priority LOCAL +** thread associated with a given GLOBAL thread. It is further assumed +** that the host OS will apply some form of "fair" scheduling on the +** GLOBAL threads. +** +** Threads have a "system flag" which when set indicates the thread +** doesn't count for determining when the process should exit (the +** process exits when the last user thread exits). +** +** Threads also have a "scope flag" which controls whether the threads +** are scheduled in the local scope or scheduled by the OS globally. This +** indicates whether a thread is permanently bound to a native OS thread. +** An unbound thread competes for scheduling resources in the same process. +** +** Another flag is "state flag" which control whether the thread is joinable. +** It allows other threads to wait for the created thread to reach completion. +** +** Threads can have "per-thread-data" attached to them. Each thread has a +** per-thread error number and error string which are updated when NSPR +** operations fail. +*/ +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRThread PRThread; +typedef struct PRThreadStack PRThreadStack; + +typedef enum PRThreadType { + PR_USER_THREAD, + PR_SYSTEM_THREAD +} PRThreadType; + +typedef enum PRThreadScope { + PR_LOCAL_THREAD, + PR_GLOBAL_THREAD, + PR_GLOBAL_BOUND_THREAD +} PRThreadScope; + +typedef enum PRThreadState { + PR_JOINABLE_THREAD, + PR_UNJOINABLE_THREAD +} PRThreadState; + +typedef enum PRThreadPriority +{ + PR_PRIORITY_FIRST = 0, /* just a placeholder */ + PR_PRIORITY_LOW = 0, /* the lowest possible priority */ + PR_PRIORITY_NORMAL = 1, /* most common expected priority */ + PR_PRIORITY_HIGH = 2, /* slightly more aggressive scheduling */ + PR_PRIORITY_URGENT = 3, /* it does little good to have more than one */ + PR_PRIORITY_LAST = 3 /* this is just a placeholder */ +} PRThreadPriority; + +/* +** Create a new thread: +** "type" is the type of thread to create +** "start(arg)" will be invoked as the threads "main" +** "priority" will be created thread's priority +** "scope" will specify whether the thread is local or global +** "state" will specify whether the thread is joinable or not +** "stackSize" the size of the stack, in bytes. The value can be zero +** and then a machine specific stack size will be chosen. +** +** This can return NULL if some kind of error occurs, such as if memory is +** tight. +** +** If you want the thread to start up waiting for the creator to do +** something, enter a lock before creating the thread and then have the +** threads start routine enter and exit the same lock. When you are ready +** for the thread to run, exit the lock. +** +** If you want to detect the completion of the created thread, the thread +** should be created joinable. Then, use PR_JoinThread to synchrnoize the +** termination of another thread. +** +** When the start function returns the thread exits. If it is the last +** PR_USER_THREAD to exit then the process exits. +*/ +NSPR_API(PRThread*) PR_CreateThread(PRThreadType type, + void (PR_CALLBACK *start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); + +/* +** Wait for thread termination: +** "thread" is the target thread +** +** This can return PR_FAILURE if no joinable thread could be found +** corresponding to the specified target thread. +** +** The calling thread is blocked until the target thread completes. +** Several threads cannot wait for the same thread to complete; one thread +** will operate successfully and others will terminate with an error PR_FAILURE. +** The calling thread will not be blocked if the target thread has already +** terminated. +*/ +NSPR_API(PRStatus) PR_JoinThread(PRThread *thread); + +/* +** Return the current thread object for the currently running code. +** Never returns NULL. +*/ +NSPR_API(PRThread*) PR_GetCurrentThread(void); +#ifndef NO_NSPR_10_SUPPORT +#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */ +#endif /* NO_NSPR_10_SUPPORT */ + +/* +** Get the priority of "thread". +*/ +NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); + +/* +** Change the priority of the "thread" to "priority". +*/ +NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority); + +/* +** This routine returns a new index for per-thread-private data table. +** The index is visible to all threads within a process. This index can +** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines +** to save and retrieve data associated with the index for a thread. +** +** Each index is associationed with a destructor function ('dtor'). The function +** may be specified as NULL when the index is created. If it is not NULL, the +** function will be called when: +** - the thread exits and the private data for the associated index +** is not NULL, +** - new thread private data is set and the current private data is +** not NULL. +** +** The index independently maintains specific values for each binding thread. +** A thread can only get access to its own thread-specific-data. +** +** Upon a new index return the value associated with the index for all threads +** is NULL, and upon thread creation the value associated with all indices for +** that thread is NULL. +** +** Returns PR_FAILURE if the total number of indices will exceed the maximun +** allowed. +*/ +typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv); + +NSPR_API(PRStatus) PR_NewThreadPrivateIndex( + PRUintn *newIndex, PRThreadPrivateDTOR destructor); + +/* +** Define some per-thread-private data. +** "tpdIndex" 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, +** the destructor function is invoked. +** +** This can return PR_FAILURE if the index is invalid. +*/ +NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv); + +/* +** Recover the per-thread-private data for the current thread. "tpdIndex" is +** the index into the per-thread private data table. +** +** The returned value may be NULL which is indistinguishable from an error +** condition. +** +** A thread can only get access to its own thread-specific-data. +*/ +NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex); + +/* +** This routine sets the interrupt request for a target thread. The interrupt +** request remains in the thread's state until it is delivered exactly once +** or explicitly canceled. +** +** A thread that has been interrupted will fail all NSPR blocking operations +** that return a PRStatus (I/O, waiting on a condition, etc). +** +** PR_Interrupt may itself fail if the target thread is invalid. +*/ +NSPR_API(PRStatus) PR_Interrupt(PRThread *thread); + +/* +** Clear the interrupt request for the calling thread. If no such request +** is pending, this operation is a noop. +*/ +NSPR_API(void) PR_ClearInterrupt(void); + +/* +** Block the interrupt for the calling thread. +*/ +NSPR_API(void) PR_BlockInterrupt(void); + +/* +** Unblock the interrupt for the calling thread. +*/ +NSPR_API(void) PR_UnblockInterrupt(void); + +/* +** Make the current thread sleep until "ticks" time amount of time +** has expired. If "ticks" is PR_INTERVAL_NO_WAIT then the call is +** equivalent to calling PR_Yield. Calling PR_Sleep with an argument +** equivalent to PR_INTERVAL_NO_TIMEOUT is an error and will result +** in a PR_FAILURE error return. +*/ +NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks); + +/* +** Get the scoping of this thread. +*/ +NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread); + +/* +** Get the type of this thread. +*/ +NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread); + +/* +** Get the join state of this thread. +*/ +NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread); + +PR_END_EXTERN_C + +#endif /* prthread_h___ */ diff --git a/nsprpub/pr/include/prtime.h b/nsprpub/pr/include/prtime.h new file mode 100644 index 00000000000..7a2a26d53fa --- /dev/null +++ b/nsprpub/pr/include/prtime.h @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + *---------------------------------------------------------------------- + * + * prtime.h -- + * + * NSPR date and time functions + * + *----------------------------------------------------------------------- + */ + +#ifndef prtime_h___ +#define prtime_h___ + +#include "prlong.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +#define PR_MSEC_PER_SEC 1000UL +#define PR_USEC_PER_SEC 1000000UL +#define PR_NSEC_PER_SEC 1000000000UL +#define PR_USEC_PER_MSEC 1000UL +#define PR_NSEC_PER_MSEC 1000000UL + +/* + * PRTime -- + * + * NSPR represents basic time as 64-bit signed integers relative + * to midnight (00:00:00), January 1, 1970 Greenwich Mean Time (GMT). + * (GMT is also known as Coordinated Universal Time, UTC.) + * The units of time are in microseconds. Negative times are allowed + * to represent times prior to the January 1970 epoch. Such values are + * intended to be exported to other systems or converted to human + * readable form. + * + * Notes on porting: PRTime corresponds to time_t in ANSI C. NSPR 1.0 + * simply uses PRInt64. + */ + +typedef PRInt64 PRTime; + +/* + * Time zone and daylight saving time corrections applied to GMT to + * obtain the local time of some geographic location + */ + +typedef struct PRTimeParameters { + PRInt32 tp_gmt_offset; /* the offset from GMT in seconds */ + PRInt32 tp_dst_offset; /* contribution of DST in seconds */ +} PRTimeParameters; + +/* + * PRExplodedTime -- + * + * Time broken down into human-readable components such as year, month, + * day, hour, minute, second, and microsecond. Time zone and daylight + * saving time corrections may be applied. If they are applied, the + * offsets from the GMT must be saved in the 'tm_params' field so that + * all the information is available to reconstruct GMT. + * + * Notes on porting: PRExplodedTime corrresponds to struct tm in + * ANSI C, with the following differences: + * - an additional field tm_usec; + * - replacing tm_isdst by tm_params; + * - the month field is spelled tm_month, not tm_mon; + * - we use absolute year, AD, not the year since 1900. + * The corresponding type in NSPR 1.0 is called PRTime. Below is + * a table of date/time type correspondence in the three APIs: + * API time since epoch time in components + * ANSI C time_t struct tm + * NSPR 1.0 PRInt64 PRTime + * NSPR 2.0 PRTime PRExplodedTime + */ + +typedef struct PRExplodedTime { + PRInt32 tm_usec; /* microseconds past tm_sec (0-99999) */ + PRInt32 tm_sec; /* seconds past tm_min (0-61, accomodating + up to two leap seconds) */ + PRInt32 tm_min; /* minutes past tm_hour (0-59) */ + PRInt32 tm_hour; /* hours past tm_day (0-23) */ + PRInt32 tm_mday; /* days past tm_mon (1-31, note that it + starts from 1) */ + PRInt32 tm_month; /* months past tm_year (0-11, Jan = 0) */ + PRInt16 tm_year; /* absolute year, AD (note that we do not + count from 1900) */ + + PRInt8 tm_wday; /* calculated day of the week + (0-6, Sun = 0) */ + PRInt16 tm_yday; /* calculated day of the year + (0-365, Jan 1 = 0) */ + + PRTimeParameters tm_params; /* time parameters used by conversion */ +} PRExplodedTime; + +/* + * PRTimeParamFn -- + * + * A function of PRTimeParamFn type returns the time zone and + * daylight saving time corrections for some geographic location, + * given the current time in GMT. The input argument gmt should + * point to a PRExplodedTime that is in GMT, i.e., whose + * tm_params contains all 0's. + * + * For any time zone other than GMT, the computation is intended to + * consist of two steps: + * - Figure out the time zone correction, tp_gmt_offset. This number + * usually depends on the geographic location only. But it may + * also depend on the current time. For example, all of China + * is one time zone right now. But this situation may change + * in the future. + * - Figure out the daylight saving time correction, tp_dst_offset. + * This number depends on both the geographic location and the + * current time. Most of the DST rules are expressed in local + * current time. If so, one should apply the time zone correction + * to GMT before applying the DST rules. + */ + +typedef PRTimeParameters (PR_CALLBACK *PRTimeParamFn)(const PRExplodedTime *gmt); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/* + * The PR_Now routine returns the current time relative to the + * epoch, midnight, January 1, 1970 UTC. The units of the returned + * value are microseconds since the epoch. + * + * The values returned are not guaranteed to advance in a linear fashion + * due to the application of time correction protocols which synchronize + * computer clocks to some external time source. Consequently it should + * not be depended on for interval timing. + * + * The implementation is machine dependent. + * Cf. time_t time(time_t *tp) in ANSI C. + */ +#if defined(HAVE_WATCOM_BUG_2) +PRTime __pascal __export __loadds +#else +NSPR_API(PRTime) +#endif +PR_Now(void); + +/* + * Expand time binding it to time parameters provided by PRTimeParamFn. + * The calculation is envisoned to proceed in the following steps: + * - From given PRTime, calculate PRExplodedTime in GMT + * - Apply the given PRTimeParamFn to the GMT that we just calculated + * to obtain PRTimeParameters. + * - Add the PRTimeParameters offsets to GMT to get the local time + * as PRExplodedTime. + */ + +NSPR_API(void) PR_ExplodeTime( + PRTime usecs, PRTimeParamFn params, PRExplodedTime *exploded); + +/* Reverse operation of PR_ExplodeTime */ +#if defined(HAVE_WATCOM_BUG_2) +PRTime __pascal __export __loadds +#else +NSPR_API(PRTime) +#endif +PR_ImplodeTime(const PRExplodedTime *exploded); + +/* + * Adjust exploded time to normalize field overflows after manipulation. + * Note that the following fields of PRExplodedTime should not be + * manipulated: + * - tm_month and tm_year: because the number of days in a month and + * number of days in a year are not constant, it is ambiguous to + * manipulate the month and year fields, although one may be tempted + * to. For example, what does "a month from January 31st" mean? + * - tm_wday and tm_yday: these fields are calculated by NSPR. Users + * should treat them as "read-only". + */ + +NSPR_API(void) PR_NormalizeTime( + PRExplodedTime *exploded, PRTimeParamFn params); + +/**********************************************************************/ +/*********************** TIME PARAMETER FUNCTIONS *********************/ +/**********************************************************************/ + +/* Time parameters that suit current host machine */ +NSPR_API(PRTimeParameters) PR_LocalTimeParameters(const PRExplodedTime *gmt); + +/* Time parameters that represent Greenwich Mean Time */ +NSPR_API(PRTimeParameters) PR_GMTParameters(const PRExplodedTime *gmt); + +/* + * Time parameters that represent the US Pacific Time Zone, with the + * current daylight saving time rules (for testing only) + */ +NSPR_API(PRTimeParameters) PR_USPacificTimeParameters(const PRExplodedTime *gmt); + +/* + * This parses a time/date string into a PRExplodedTime + * struct. It populates all fields but it can't split + * the offset from UTC into tp_gmt_offset and tp_dst_offset in + * most cases (exceptions: PST/PDT, MST/MDT, CST/CDT, EST/EDT, GMT/BST). + * In those cases tp_gmt_offset will be the sum of these two and + * tp_dst_offset will be 0. + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + * + * Many formats are handled, including: + * + * 14 Apr 89 03:20:12 + * 14 Apr 89 03:20 GMT + * Fri, 17 Mar 89 4:01:33 + * Fri, 17 Mar 89 4:01 GMT + * Mon Jan 16 16:12 PDT 1989 + * Mon Jan 16 16:12 +0130 1989 + * 6 May 1992 16:41-JST (Wednesday) + * 22-AUG-1993 10:59:12.82 + * 22-AUG-1993 10:59pm + * 22-AUG-1993 12:59am + * 22-AUG-1993 12:59 PM + * Friday, August 04, 1995 3:54 PM + * 06/21/95 04:24:34 PM + * 20/06/95 21:07 + * 95-06-08 19:32:48 EDT + * + * If the input string doesn't contain a description of the timezone, + * we consult the `default_to_gmt' to decide whether the string should + * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE). + * The correct value for this argument depends on what standard specified + * the time string which you are parsing. + */ + +NSPR_API(PRStatus) PR_ParseTimeStringToExplodedTime ( + const char *string, + PRBool default_to_gmt, + PRExplodedTime *result); + +/* + * This uses PR_ParseTimeStringToExplodedTime to parse + * a time/date string and PR_ImplodeTime to transform it into + * a PRTime (microseconds after "1-Jan-1970 00:00:00 GMT"). + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + */ + +NSPR_API(PRStatus) PR_ParseTimeString ( + const char *string, + PRBool default_to_gmt, + PRTime *result); + +/* + * FIXME: should we also have a formatting function, such as asctime, ctime, + * and strftime in standard C library? But this would involve + * internationalization issues. Might want to provide a US English version. + */ + +/**********************************************************************/ +/*********************** OLD COMPATIBILITYFUNCTIONS *******************/ +/**********************************************************************/ +#ifndef NO_NSPR_10_SUPPORT + +/* Format a time value into a buffer. Same semantics as strftime() */ +NSPR_API(PRUint32) PR_FormatTime(char *buf, int buflen, const char *fmt, + const PRExplodedTime *tm); + +/* Format a time value into a buffer. Time is always in US English format, regardless + * of locale setting. + */ +NSPR_API(PRUint32) +PR_FormatTimeUSEnglish( char* buf, PRUint32 bufSize, + const char* format, const PRExplodedTime* tm ); + +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* prtime_h___ */ diff --git a/nsprpub/pr/include/prtpool.h b/nsprpub/pr/include/prtpool.h new file mode 100644 index 00000000000..2e1f6ddb37e --- /dev/null +++ b/nsprpub/pr/include/prtpool.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prtpool_h___ +#define prtpool_h___ + +#include "prtypes.h" +#include "prthread.h" +#include "prio.h" +#include "prerror.h" + +/* + * NOTE: + * THIS API IS A PRELIMINARY VERSION IN NSPR 4.0 AND IS SUBJECT TO + * CHANGE + */ + +PR_BEGIN_EXTERN_C + +typedef struct PRJobIoDesc { + PRFileDesc *socket; + PRErrorCode error; + PRIntervalTime timeout; +} PRJobIoDesc; + +typedef struct PRThreadPool PRThreadPool; +typedef struct PRJob PRJob; +typedef void (PR_CALLBACK *PRJobFn) (void *arg); + +/* Create thread pool */ +NSPR_API(PRThreadPool *) +PR_CreateThreadPool(PRInt32 initial_threads, PRInt32 max_threads, + PRUint32 stacksize); + +/* queue a job */ +NSPR_API(PRJob *) +PR_QueueJob(PRThreadPool *tpool, PRJobFn fn, void *arg, PRBool joinable); + +/* queue a job, when a socket is readable */ +NSPR_API(PRJob *) +PR_QueueJob_Read(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a socket is writeable */ +NSPR_API(PRJob *) +PR_QueueJob_Write(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a socket has a pending connection */ +NSPR_API(PRJob *) +PR_QueueJob_Accept(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when the socket connection to addr succeeds or fails */ +NSPR_API(PRJob *) +PR_QueueJob_Connect(PRThreadPool *tpool, PRJobIoDesc *iod, + const PRNetAddr *addr, PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a timer exipres */ +NSPR_API(PRJob *) +PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, + PRJobFn fn, void * arg, PRBool joinable); +/* cancel a job */ +NSPR_API(PRStatus) +PR_CancelJob(PRJob *job); + +/* join a job */ +NSPR_API(PRStatus) +PR_JoinJob(PRJob *job); + +/* shutdown pool */ +NSPR_API(PRStatus) +PR_ShutdownThreadPool(PRThreadPool *tpool); + +/* join pool, wait for exit of all threads */ +NSPR_API(PRStatus) +PR_JoinThreadPool(PRThreadPool *tpool); + +PR_END_EXTERN_C + +#endif /* prtpool_h___ */ diff --git a/nsprpub/pr/include/prtrace.h b/nsprpub/pr/include/prtrace.h new file mode 100644 index 00000000000..42f88e93b77 --- /dev/null +++ b/nsprpub/pr/include/prtrace.h @@ -0,0 +1,678 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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; + +/* +** 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 ); +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_INIT_TRACE_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) +#else +#define PR_INIT_TRACE_HANDLE(handle,value) +#endif + + +/* ----------------------------------------------------------------------- +** 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 + +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_CREATE_TRACE(handle,qName,rName,description)\ + (handle) = PR_CreateTrace((qName),(rName),(description)) +#else +#define PR_CREATE_TRACE(handle,qName,rName,description) +#endif + +NSPR_API(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: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_DESTROY_TRACE(handle)\ + PR_DestroyTrace((handle)) +#else +#define PR_DESTROY_TRACE(handle) +#endif + +NSPR_API(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: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7)\ + PR_Trace((handle),(ud0),(ud1),(ud2),(ud3),(ud4),(ud5),(ud6),(ud7)) +#else +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7) +#endif + +NSPR_API(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: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_SET_TRACE_OPTION(command,value)\ + PR_SetTraceOption((command),(value)) +#else +#define PR_SET_TRACE_OPTION(command,value) +#endif + +NSPR_API(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: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_OPTION(command,value)\ + PR_GetTraceOption((command),(value)) +#else +#define PR_GET_TRACE_OPTION(command,value) +#endif + +NSPR_API(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: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetTraceHandleFromName((qName),(rName)) +#else +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName) +#endif + +NSPR_API(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: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetTraceNameFromHandle((handle),(qName),(rName),(description)) +#else +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description) +#endif + +NSPR_API(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 ). +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_FIND_NEXT_TRACE_QNAME(next,handle)\ + (next) = PR_FindNextTraceQname((handle)) +#else +#define PR_FIND_NEXT_TRACE_QNAME(next,handle) +#endif + +NSPR_API(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 ). +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextTraceRname((rhandle),(qhandle)) +#else +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle) +#endif + +NSPR_API(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. +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_RECORD_TRACE_ENTRIES()\ + PR_RecordTraceEntries() +#else +#define PR_RECORD_TRACE_ENTRIES() +#endif + +NSPR_API(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. +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_ENTRIES(buffer,count,found)\ + PR_GetTraceEntries((buffer),(count),(found)) +#else +#define PR_GET_TRACE_ENTRIES(buffer,count,found) +#endif + +NSPR_API(PRIntn) + PR_GetTraceEntries( + PRTraceEntry *buffer, /* where to write output */ + PRInt32 count, /* number to get */ + PRInt32 *found /* number you got */ +); + +PR_END_EXTERN_C + +#endif /* prtrace_h___ */ + diff --git a/nsprpub/pr/include/prtypes.h b/nsprpub/pr/include/prtypes.h new file mode 100644 index 00000000000..6850d6f9ac1 --- /dev/null +++ b/nsprpub/pr/include/prtypes.h @@ -0,0 +1,569 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prtypes.h +** Description: Definitions of NSPR's basic types +** +** Prototypes and macros used to make up for deficiencies that we have found +** in ANSI environments. +** +** Since we do not wrap and all the other standard headers, authors +** of portable code will not know in general that they need these definitions. +** Instead of requiring these authors to find the dependent uses in their code +** and take the following steps only in those C files, we take steps once here +** for all C files. +**/ + +#ifndef prtypes_h___ +#define prtypes_h___ + +#ifdef MDCPUCFG +#include MDCPUCFG +#else +#include "prcpucfg.h" +#endif + +#include + +/*********************************************************************** +** MACROS: PR_EXTERN +** PR_IMPLEMENT +** DESCRIPTION: +** These are only for externally visible routines and globals. For +** internal routines, just use "extern" for type checking and that +** will not export internal cross-file or forward-declared symbols. +** Define a macro for declaring procedures return types. We use this to +** deal with windoze specific type hackery for DLL definitions. Use +** PR_EXTERN when the prototype for the method is declared. Use +** PR_IMPLEMENT for the implementation of the method. +** +** Example: +** in dowhim.h +** PR_EXTERN( void ) DoWhatIMean( void ); +** in dowhim.c +** PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; } +** +** +***********************************************************************/ +#if defined(WIN32) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_BEOS) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(WIN16) + +#define PR_CALLBACK_DECL __cdecl + +#if defined(_WINDLL) +#define PR_EXPORT(__type) extern __type _cdecl _export _loadds +#define PR_IMPORT(__type) extern __type _cdecl _export _loadds +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export _loadds +#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* this must be .EXE */ +#define PR_EXPORT(__type) extern __type _cdecl _export +#define PR_IMPORT(__type) extern __type _cdecl _export +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export +#define PR_IMPLEMENT(__type) __type _cdecl _export +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK +#endif /* _WINDLL */ + +#elif defined(XP_MAC) + +#define PR_EXPORT(__type) extern __declspec(export) __type +#define PR_EXPORT_DATA(__type) extern __declspec(export) __type +#define PR_IMPORT(__type) extern __declspec(export) __type +#define PR_IMPORT_DATA(__type) extern __declspec(export) __type + +#define PR_EXTERN(__type) extern __declspec(export) __type +#define PR_IMPLEMENT(__type) __declspec(export) __type +#define PR_EXTERN_DATA(__type) extern __declspec(export) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2) && defined(__declspec) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2_VACPP) + +#define PR_EXPORT(__type) extern __type +#define PR_EXPORT_DATA(__type) extern __type +#define PR_IMPORT(__type) extern __type +#define PR_IMPORT_DATA(__type) extern __type + +#define PR_EXTERN(__type) extern __type +#define PR_IMPLEMENT(__type) __type +#define PR_EXTERN_DATA(__type) extern __type +#define PR_IMPLEMENT_DATA(__type) __type +#define PR_CALLBACK _Optlink +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* Unix */ + +/* GCC 3.3 and later support the visibility attribute. */ +#if (__GNUC__ >= 4) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default"))) +#else +#define PR_VISIBILITY_DEFAULT +#endif + +#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type + +#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type +#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#endif + +#if defined(_NSPR_BUILD_) +#define NSPR_API(__type) PR_EXPORT(__type) +#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) +#else +#define NSPR_API(__type) PR_IMPORT(__type) +#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) +#endif + +/*********************************************************************** +** MACROS: PR_BEGIN_MACRO +** PR_END_MACRO +** DESCRIPTION: +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +***********************************************************************/ +#define PR_BEGIN_MACRO do { +#define PR_END_MACRO } while (0) + +/*********************************************************************** +** MACROS: PR_BEGIN_EXTERN_C +** PR_END_EXTERN_C +** DESCRIPTION: +** Macro shorthands for conditional C++ extern block delimiters. +***********************************************************************/ +#ifdef __cplusplus +#define PR_BEGIN_EXTERN_C extern "C" { +#define PR_END_EXTERN_C } +#else +#define PR_BEGIN_EXTERN_C +#define PR_END_EXTERN_C +#endif + +/*********************************************************************** +** MACROS: PR_BIT +** PR_BITMASK +** DESCRIPTION: +** Bit masking macros. XXX n must be <= 31 to be portable +***********************************************************************/ +#define PR_BIT(n) ((PRUint32)1 << (n)) +#define PR_BITMASK(n) (PR_BIT(n) - 1) + +/*********************************************************************** +** MACROS: PR_ROUNDUP +** PR_MIN +** PR_MAX +** PR_ABS +** DESCRIPTION: +** Commonly used macros for operations on compatible types. +***********************************************************************/ +#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) +#define PR_MIN(x,y) ((x)<(y)?(x):(y)) +#define PR_MAX(x,y) ((x)>(y)?(x):(y)) +#define PR_ABS(x) ((x)<0?-(x):(x)) + +PR_BEGIN_EXTERN_C + +/************************************************************************ +** TYPES: PRUint8 +** PRInt8 +** DESCRIPTION: +** The int8 types are known to be 8 bits each. There is no type that +** is equivalent to a plain "char". +************************************************************************/ +#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 + +/************************************************************************ + * MACROS: PR_INT8_MAX + * PR_INT8_MIN + * PR_UINT8_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt8 or PRUint8. +************************************************************************/ + +#define PR_INT8_MAX 127 +#define PR_INT8_MIN (-128) +#define PR_UINT8_MAX 255U + +/************************************************************************ +** TYPES: PRUint16 +** PRInt16 +** DESCRIPTION: +** The int16 types are known to be 16 bits each. +************************************************************************/ +#if PR_BYTES_PER_SHORT == 2 +typedef unsigned short PRUint16; +typedef short PRInt16; +#else +#error No suitable type for PRInt16/PRUint16 +#endif + +/************************************************************************ + * MACROS: PR_INT16_MAX + * PR_INT16_MIN + * PR_UINT16_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt16 or PRUint16. +************************************************************************/ + +#define PR_INT16_MAX 32767 +#define PR_INT16_MIN (-32768) +#define PR_UINT16_MAX 65535U + +/************************************************************************ +** TYPES: PRUint32 +** PRInt32 +** DESCRIPTION: +** The int32 types are known to be 32 bits each. +************************************************************************/ +#if PR_BYTES_PER_INT == 4 +typedef unsigned int PRUint32; +typedef int PRInt32; +#define PR_INT32(x) x +#define PR_UINT32(x) x ## U +#elif PR_BYTES_PER_LONG == 4 +typedef unsigned long PRUint32; +typedef long PRInt32; +#define PR_INT32(x) x ## L +#define PR_UINT32(x) x ## UL +#else +#error No suitable type for PRInt32/PRUint32 +#endif + +/************************************************************************ + * MACROS: PR_INT32_MAX + * PR_INT32_MIN + * PR_UINT32_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt32 or PRUint32. +************************************************************************/ + +#define PR_INT32_MAX PR_INT32(2147483647) +#define PR_INT32_MIN (-PR_INT32_MAX - 1) +#define PR_UINT32_MAX PR_UINT32(4294967295) + +/************************************************************************ +** TYPES: PRUint64 +** PRInt64 +** DESCRIPTION: +** The int64 types are known to be 64 bits each. Care must be used when +** declaring variables of type PRUint64 or PRInt64. Different hardware +** architectures and even different compilers have varying support for +** 64 bit values. The only guaranteed portability requires the use of +** the LL_ macros (see prlong.h). +************************************************************************/ +#ifdef HAVE_LONG_LONG +#if PR_BYTES_PER_LONG == 8 +typedef long PRInt64; +typedef unsigned long PRUint64; +#elif defined(WIN16) +typedef __int64 PRInt64; +typedef unsigned __int64 PRUint64; +#elif defined(WIN32) && !defined(__GNUC__) +typedef __int64 PRInt64; +typedef unsigned __int64 PRUint64; +#else +typedef long long PRInt64; +typedef unsigned long long PRUint64; +#endif /* PR_BYTES_PER_LONG == 8 */ +#else /* !HAVE_LONG_LONG */ +typedef struct { +#ifdef IS_LITTLE_ENDIAN + PRUint32 lo, hi; +#else + PRUint32 hi, lo; +#endif +} PRInt64; +typedef PRInt64 PRUint64; +#endif /* !HAVE_LONG_LONG */ + +/************************************************************************ +** TYPES: PRUintn +** PRIntn +** DESCRIPTION: +** The PRIntn types are most appropriate for automatic variables. They are +** guaranteed to be at least 16 bits, though various architectures may +** define them to be wider (e.g., 32 or even 64 bits). These types are +** never valid for fields of a structure. +************************************************************************/ +#if PR_BYTES_PER_INT >= 2 +typedef int PRIntn; +typedef unsigned int PRUintn; +#else +#error 'sizeof(int)' not sufficient for platform use +#endif + +/************************************************************************ +** TYPES: PRFloat64 +** DESCRIPTION: +** NSPR's floating point type is always 64 bits. +************************************************************************/ +typedef double PRFloat64; + +/************************************************************************ +** TYPES: PRSize +** DESCRIPTION: +** A type for representing the size of objects. +************************************************************************/ +typedef size_t PRSize; + + +/************************************************************************ +** TYPES: PROffset32, PROffset64 +** DESCRIPTION: +** A type for representing byte offsets from some location. +************************************************************************/ +typedef PRInt32 PROffset32; +typedef PRInt64 PROffset64; + +/************************************************************************ +** TYPES: PRPtrDiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer subtraction. +************************************************************************/ +typedef ptrdiff_t PRPtrdiff; + +/************************************************************************ +** TYPES: PRUptrdiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +#ifdef _WIN64 +typedef unsigned __int64 PRUptrdiff; +#else +typedef unsigned long PRUptrdiff; +#endif + +/************************************************************************ +** TYPES: PRBool +** DESCRIPTION: +** Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE +** for clarity of target type in assignments and actual arguments. Use +** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans +** just as you would C int-valued conditions. +************************************************************************/ +typedef PRIntn PRBool; +#define PR_TRUE 1 +#define PR_FALSE 0 + +/************************************************************************ +** TYPES: PRPackedBool +** DESCRIPTION: +** Use PRPackedBool within structs where bitfields are not desirable +** but minimum and consistant overhead matters. +************************************************************************/ +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ +#if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +#else +typedef PRUint16 PRUnichar; +#endif +#endif + +/* +** WARNING: The undocumented data types PRWord and PRUword are +** only used in the garbage collection and arena code. Do not +** use PRWord and PRUword in new code. +** +** A PRWord is an integer that is the same size as a void*. +** It implements the notion of a "word" in the Java Virtual +** Machine. (See Sec. 3.4 "Words", The Java Virtual Machine +** Specification, Addison-Wesley, September 1996. +** http://java.sun.com/docs/books/vmspec/index.html.) +*/ +#ifdef _WIN64 +typedef __int64 PRWord; +typedef unsigned __int64 PRUword; +#else +typedef long PRWord; +typedef unsigned long PRUword; +#endif + +#if defined(NO_NSPR_10_SUPPORT) +#else +/********* ???????????????? FIX ME ??????????????????????????? *****/ +/********************** Some old definitions until pr=>ds transition is done ***/ +/********************** Also, we are still using NSPR 1.0. GC ******************/ +/* +** 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. +*/ +#define NSPR_BEGIN_MACRO do { +#define NSPR_END_MACRO } while (0) + +/* +** Macro shorthands for conditional C++ extern block delimiters. +*/ +#ifdef NSPR_BEGIN_EXTERN_C +#undef NSPR_BEGIN_EXTERN_C +#endif +#ifdef NSPR_END_EXTERN_C +#undef NSPR_END_EXTERN_C +#endif + +#ifdef __cplusplus +#define NSPR_BEGIN_EXTERN_C extern "C" { +#define NSPR_END_EXTERN_C } +#else +#define NSPR_BEGIN_EXTERN_C +#define NSPR_END_EXTERN_C +#endif + +#ifdef XP_MAC +#include "protypes.h" +#else +#include "obsolete/protypes.h" +#endif + +/********* ????????????? End Fix me ?????????????????????????????? *****/ +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* prtypes_h___ */ + diff --git a/nsprpub/pr/include/prvrsion.h b/nsprpub/pr/include/prvrsion.h new file mode 100755 index 00000000000..eb8e1e61cf2 --- /dev/null +++ b/nsprpub/pr/include/prvrsion.h @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* 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. + * + * For example, for a library named libfoo, we would have: + * + * PRVersionDescription prVersionDescription_libfoo = + * { + * ... + * }; + * + * PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void) + * { + * return &prVersionDescription_libfoo; + * } + */ +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/nsprpub/pr/include/prwin16.h b/nsprpub/pr/include/prwin16.h new file mode 100644 index 00000000000..215b051404f --- /dev/null +++ b/nsprpub/pr/include/prwin16.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prwin16_h___ +#define prwin16_h___ + +/* +** Condition use of this header on platform. +*/ +#if (defined(XP_PC) && !defined(_WIN32) && !defined(XP_OS2) && defined(MOZILLA_CLIENT)) || defined(WIN16) +#include + +PR_BEGIN_EXTERN_C +/* +** Win16 stdio special case. +** To get stdio to work for Win16, all calls to printf() and related +** things must be called from the environment of the .EXE; calls to +** printf() from the .DLL send output to the bit-bucket. +** +** To make sure that PR_fprintf(), and related functions, work correctly, +** the actual stream I/O to stdout, stderr, stdin must be done in the +** .EXE. To do this, a hack is placed in _MD_Write() such that the +** fd for stdio handles results in a call to the .EXE. +** +** file w16stdio.c contains the functions that get called from NSPR +** to do the actual I/O. w16stdio.o must be statically linked with +** any application needing stdio for Win16. +** +** The address of these functions must be made available to the .DLL +** so he can call back to the .EXE. To do this, function +** PR_MD_RegisterW16StdioCallbacks() is called from the .EXE. +** The arguments are the functions defined in w16stdio.c +** At runtime, MD_Write() calls the registered functions, if any +** were registered. +** +** prinit.h contains a macro PR_STDIO_INIT() that calls the registration +** function for Win16; For other platforms, the macro is a No-Op. +** +** Note that stdio is not operational at all on Win16 GUI applications. +** This special case exists to provide stdio capability from the NSPR +** .DLL for command line applications only. NSPR's test cases are +** almost exclusively command line applications. +** +** See also: w16io.c, w16stdio.c +*/ +typedef PRInt32 (PR_CALLBACK *PRStdinRead)( void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRStdoutWrite)( void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRStderrWrite)( void *buf, PRInt32 amount); + +NSPR_API(PRStatus) +PR_MD_RegisterW16StdioCallbacks( + PRStdinRead inReadf, /* i: function pointer for stdin read */ + PRStdoutWrite outWritef, /* i: function pointer for stdout write */ + PRStderrWrite errWritef /* i: function pointer for stderr write */ + ); + +NSPR_API(PRInt32) +_PL_W16StdioWrite( void *buf, PRInt32 amount ); + +NSPR_API(PRInt32) +_PL_W16StdioRead( void *buf, PRInt32 amount ); + +#define PR_STDIO_INIT() PR_MD_RegisterW16StdioCallbacks( \ + _PL_W16StdioRead, _PL_W16StdioWrite, _PL_W16StdioWrite ); \ + PR_INIT_CALLBACKS(); + +/* +** Win16 hackery. +** +*/ +struct PRMethodCallbackStr { + int (PR_CALLBACK *auxOutput)(const char *outputString); + size_t (PR_CALLBACK *strftime)(char *s, size_t len, const char *fmt, const struct tm *p); + void * (PR_CALLBACK *malloc)( size_t size ); + void * (PR_CALLBACK *calloc)(size_t n, size_t size ); + void * (PR_CALLBACK *realloc)( void* old_blk, size_t size ); + void (PR_CALLBACK *free)( void *ptr ); + void * (PR_CALLBACK *getenv)( const char *name); + int (PR_CALLBACK *putenv)( const char *assoc); +/* void * (PR_CALLBACK *perror)( const char *prefix ); */ +}; + +NSPR_API(void) PR_MDRegisterCallbacks(struct PRMethodCallbackStr *); + +int PR_CALLBACK _PL_W16CallBackPuts( const char *outputString ); +size_t PR_CALLBACK _PL_W16CallBackStrftime( + char *s, + size_t len, + const char *fmt, + const struct tm *p ); +void * PR_CALLBACK _PL_W16CallBackMalloc( size_t size ); +void * PR_CALLBACK _PL_W16CallBackCalloc( size_t n, size_t size ); +void * PR_CALLBACK _PL_W16CallBackRealloc( + void *old_blk, + size_t size ); +void PR_CALLBACK _PL_W16CallBackFree( void *ptr ); +void * PR_CALLBACK _PL_W16CallBackGetenv( const char *name ); +int PR_CALLBACK _PL_W16CallBackPutenv( const char *assoc ); + +/* +** Hackery! +** +** These functions are provided as static link points. +** This is to satisfy the quick port of Gromit to NSPR 2.0 +** ... Don't do this! ... alas, It may never go away. +** +*/ +NSPR_API(int) PR_MD_printf(const char *, ...); +NSPR_API(void) PR_MD_exit(int); +NSPR_API(size_t) PR_MD_strftime(char *, size_t, const char *, const struct tm *); +NSPR_API(int) PR_MD_sscanf(const char *, const char *, ...); +NSPR_API(void*) PR_MD_malloc( size_t size ); +NSPR_API(void*) PR_MD_calloc( size_t n, size_t size ); +NSPR_API(void*) PR_MD_realloc( void* old_blk, size_t size ); +NSPR_API(void) PR_MD_free( void *ptr ); +NSPR_API(char*) PR_MD_getenv( const char *name ); +NSPR_API(int) PR_MD_putenv( const char *assoc ); +NSPR_API(int) PR_MD_fprintf(FILE *fPtr, const char *fmt, ...); + +#define PR_INIT_CALLBACKS() \ + { \ + static struct PRMethodCallbackStr cbf = { \ + _PL_W16CallBackPuts, \ + _PL_W16CallBackStrftime, \ + _PL_W16CallBackMalloc, \ + _PL_W16CallBackCalloc, \ + _PL_W16CallBackRealloc, \ + _PL_W16CallBackFree, \ + _PL_W16CallBackGetenv, \ + _PL_W16CallBackPutenv, \ + }; \ + PR_MDRegisterCallbacks( &cbf ); \ + } + + +/* +** Get the exception context for Win16 MFC applications threads +*/ +NSPR_API(void *) PR_W16GetExceptionContext(void); +/* +** Set the exception context for Win16 MFC applications threads +*/ +NSPR_API(void) PR_W16SetExceptionContext(void *context); + +PR_END_EXTERN_C +#else +/* +** For platforms other than Win16, define +** PR_STDIO_INIT() as a No-Op. +*/ +#define PR_STDIO_INIT() +#endif /* WIN16 || MOZILLA_CLIENT */ + +#endif /* prwin16_h___ */ + + + + + + + + diff --git a/nsprpub/pr/src/.cvsignore b/nsprpub/pr/src/.cvsignore new file mode 100644 index 00000000000..41a1bd2b783 --- /dev/null +++ b/nsprpub/pr/src/.cvsignore @@ -0,0 +1,2 @@ +Makefile +_pr_bld.h diff --git a/nsprpub/pr/src/Makefile.in b/nsprpub/pr/src/Makefile.in new file mode 100644 index 00000000000..76e7f2355aa --- /dev/null +++ b/nsprpub/pr/src/Makefile.in @@ -0,0 +1,424 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = io linking malloc md memory misc threads + +# For VAC++ 4 geticcdata rule in config/OS2.mk +ifeq ($(MOZ_OS2_TOOLS),VACPP) +CSRCS = prvrsion.c +endif + +ifeq ($(USE_PTHREADS), 1) + DIRS += pthreads +endif + +ifeq ($(USE_BTHREADS), 1) + DIRS += bthreads +endif + +ifeq ($(USE_CPLUS), 1) + DIRS += cplus +endif + +# +# Define platform-dependent OS_LIBS +# + +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OS_LIBS = -lm +else # 4.1.3_U1 +MAPFILE = $(OBJDIR)/nsprmap.sun +GARBAGE += $(MAPFILE) +ifdef NS_USE_GCC +ifdef GCC_USE_GNU_LD +MKSHLIB += -Wl,--version-script,$(MAPFILE) +else +MKSHLIB += -Wl,-M,$(MAPFILE) +endif +else +MKSHLIB += -M $(MAPFILE) +endif +# +# In Solaris 2.6 or earlier, -lrt is called -lposix4. +# +LIBRT_TEST=$(firstword $(sort 5.7 $(OS_RELEASE))) +ifeq (5.7, $(LIBRT_TEST)) +LIBRT=-lrt +else +LIBRT=-lposix4 +endif + +ifdef USE_PTHREADS +OS_LIBS = -lpthread ${LIBRT} -lsocket -lnsl -ldl -lc +else +ifdef LOCAL_THREADS_ONLY +OS_LIBS = -lsocket -lnsl -ldl -lc +else +OS_LIBS = -lthread ${LIBRT} -lsocket -lnsl -ldl -lc +endif # LOCAL_THREADS_ONLY +endif # USE_PTHREADS +ifeq ($(OS_TEST),sun4u) +ifndef USE_64 +DSO_LDOPTS += -Wl,-f,\$$ORIGIN/cpu/\$$ISALIST/lib$(ULTRASPARC_LIBRARY)$(LIBRARY_VERSION).so +endif +endif # sun4u +endif # 4.1.3_U1 +endif # SunOS + +ifeq ($(OS_ARCH), IRIX) +ifeq ($(USE_PTHREADS), 1) +OS_LIBS = -lpthread +endif +OS_LIBS += -lc +endif + +ifeq ($(OS_ARCH),AIX) +DSO_LDOPTS += -binitfini::_PR_Fini +OS_LIBS = -lodm -lcfg +ifeq ($(CLASSIC_NSPR),1) +ifeq ($(OS_RELEASE),4.1) +OS_LIBS += -lsvld -lc +else +OS_LIBS += -ldl -lc +endif +else +ifeq ($(OS_RELEASE),4.1) +OS_LIBS += -lpthreads -lsvld -lC_r -lC -lc_r -lm /usr/lib/libc.a +else +OS_LIBS += -lpthreads -ldl -lC_r -lC -lc_r -lm /usr/lib/libc.a +endif +endif +endif + +# On AIX, we override malloc in non-pthread versions. On AIX 4.2 or +# above, this requires that we use the rtl-enabled version of libc.a. +ifeq ($(OS_ARCH),AIX) +ifneq (,$(filter-out 3.2 4.1,$(OS_RELEASE))) +ifneq ($(USE_PTHREADS),1) +BUILD_AIX_RTL_LIBC = 1 +AIX_RTL_LIBC = $(OBJDIR)/libc.a +endif +endif +endif + +ifeq ($(OS_ARCH),OS2) +MAPFILE = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).def +ADD_TO_DEF_FILE = cat $(srcdir)/os2extra.def >> $(MAPFILE) +GARBAGE += $(MAPFILE) +MKSHLIB += $(MAPFILE) +endif + +ifeq ($(OS_ARCH),OSF1) +ifeq ($(USE_PTHREADS), 1) +OS_LIBS = -lpthread -lrt +endif +ifneq ($(OS_RELEASE),V2.0) +OS_LIBS += -lc_r +endif +endif + +ifeq ($(OS_ARCH),Linux) +ifeq ($(USE_PTHREADS), 1) +OS_LIBS = -lpthread -ldl +else +OS_LIBS = -ldl +endif +endif + +ifeq ($(OS_ARCH),HP-UX) +ifeq ($(USE_PTHREADS), 1) +ifeq (,$(filter-out B.10.10 B.10.20,$(OS_RELEASE))) +OS_LIBS = -ldce +else +OS_LIBS = -lpthread -lrt +endif +endif +ifeq ($(PTHREADS_USER), 1) +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 +ifneq ($(OS_TEST),ia64) +ifndef USE_64 +DSO_LDOPTS += +I PR_HPUX10xInit +endif +endif +endif + +ifeq ($(OS_ARCH),UNIXWARE) +OS_LIBS = -lsocket -lc +endif + +ifeq ($(OS_ARCH),NEWS-OS) +OS_LIBS = -lsocket -lnsl -lgen -lresolv +endif + +ifeq ($(OS_ARCH),WINNT) +ifdef NS_USE_GCC +OS_LIBS = -ladvapi32 -lwsock32 -lwinmm +else +OS_LIBS = advapi32.lib wsock32.lib winmm.lib +endif +endif + +ifeq ($(OS_TARGET),MacOSX) +OS_LIBS = -framework CoreServices -framework CoreFoundation +endif + +ifdef GC_LEAK_DETECTOR +EXTRA_LIBS = -L$(dist_libdir) -lboehm +endif + +EXTRA_LIBS += $(OS_LIBS) + +# +# Define platform-dependent OBJS +# + +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)/pripv6.$(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)/prrwlock.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prtpd.$(OBJ_SUFFIX) \ + linking/$(OBJDIR)/prlink.$(OBJ_SUFFIX) \ + malloc/$(OBJDIR)/prmem.$(OBJ_SUFFIX) \ + md/$(OBJDIR)/prosdep.$(OBJ_SUFFIX) \ + memory/$(OBJDIR)/prshm.$(OBJ_SUFFIX) \ + memory/$(OBJDIR)/prshma.$(OBJ_SUFFIX) \ + 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)/prerr.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prerror.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prerrortable.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prinit.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prinrval.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/pripc.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prlog2.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prlong.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prnetdb.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prolock.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prrng.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prsystem.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prthinfo.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prtpool.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prtrace.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prtime.$(OBJ_SUFFIX) + +# ilib now rejects empty objects +ifneq ($(MOZ_OS2_TOOLS),VACPP) +OBJS += malloc/$(OBJDIR)/prmalloc.$(OBJ_SUFFIX) +endif + +ifdef USE_PTHREADS +OBJS += \ + pthreads/$(OBJDIR)/ptsynch.$(OBJ_SUFFIX) \ + pthreads/$(OBJDIR)/ptio.$(OBJ_SUFFIX) \ + pthreads/$(OBJDIR)/ptthread.$(OBJ_SUFFIX) \ + pthreads/$(OBJDIR)/ptmisc.$(OBJ_SUFFIX) +else +OBJS += \ + io/$(OBJDIR)/prdir.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prfile.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prio.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prsocket.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/pripcsem.$(OBJ_SUFFIX) + +ifndef USE_BTHREADS +OBJS += \ + threads/$(OBJDIR)/prcthr.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prdump.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prmon.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prsem.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/prucpu.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/prucv.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/prulock.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/prustack.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/pruthr.$(OBJ_SUFFIX) +endif + +endif + +ifeq ($(USE_CPLUS), 1) +OBJS += \ + cplus/$(OBJDIR)/rcbase.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rccv.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcfileio.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcinrval.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcio.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rclock.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcnetdb.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcnetio.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcthread.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rctime.$(OBJ_SUFFIX) +endif + +ifdef GC_LEAK_DETECTOR +OBJS += memory/$(OBJDIR)/prgcleak.$(OBJ_SUFFIX) +endif + +ifeq ($(OS_ARCH), WINNT) +RES=$(OBJDIR)/nspr.res +RESNAME=nspr.rc +endif # WINNT + +include $(srcdir)/md/$(PR_MD_ARCH_DIR)/objs.mk +ifdef USE_BTHREADS +include $(srcdir)/bthreads/objs.mk +endif + +LIBRARY_NAME = nspr +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_LIBS = $(TARGETS) + +include $(topsrcdir)/config/rules.mk + +ifeq ($(BUILD_AIX_RTL_LIBC),1) +TARGETS += $(AIX_RTL_LIBC) +# XXX is this a shared library? +endif + +# +# Version information generation (begin) +# +ECHO = echo +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private +TINC = $(OBJDIR)/_pr_bld.h + +ifeq ($(OS_TARGET),OS2) +PROD = nspr$(MOD_MAJOR_VERSION).$(DLL_SUFFIX) +else +PROD = $(notdir $(SHARED_LIBRARY)) +endif + +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date "+%Y-%m-%d %T") +SH_NOW = $(shell $(NOW)) + +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + SUF = i64 +else + SUF = LL +endif + +DEFINES += -D_NSPR_BUILD_ + +GARBAGE += $(TINC) + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) '#define _BUILD_STRING "$(SH_DATE)"' > $(TINC) + @if test ! -z "$(SH_NOW)"; then \ + $(ECHO) '#define _BUILD_TIME $(SH_NOW)$(SUF)' >> $(TINC); \ + else \ + true; \ + fi + @$(ECHO) '#define _PRODUCTION "$(PROD)"' >> $(TINC) + + +$(OBJDIR)/prvrsion.$(OBJ_SUFFIX): prvrsion.c $(TINC) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else +ifeq ($(MOZ_OS2_TOOLS), VACPP) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +endif +endif +# +# Version information generation (end) +# + + +# +# The Client build wants the shared libraries in $(dist_bindir) +# so we also install them there. +# + +export:: $(TARGETS) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifdef SHARED_LIBRARY +ifeq ($(OS_ARCH),HP-UX) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_libdir) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_bindir) +else + $(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_bindir) +endif +endif +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin +endif + +ifeq ($(BUILD_AIX_RTL_LIBC),1) +$(AIX_RTL_LIBC): /usr/ccs/lib/libc.a + rtl_enable -o $@ $< +endif + + diff --git a/nsprpub/pr/src/bthreads/.cvsignore b/nsprpub/pr/src/bthreads/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/bthreads/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/bthreads/Makefile.in b/nsprpub/pr/src/bthreads/Makefile.in new file mode 100644 index 00000000000..285f217d6ab --- /dev/null +++ b/nsprpub/pr/src/bthreads/Makefile.in @@ -0,0 +1,63 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +include $(srcdir)/bsrcs.mk +CSRCS += $(BTCSRCS) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_NSPR_BUILD_ + +export:: $(TARGETS) + + diff --git a/nsprpub/pr/src/bthreads/bsrcs.mk b/nsprpub/pr/src/bthreads/bsrcs.mk new file mode 100644 index 00000000000..af01bb7d48f --- /dev/null +++ b/nsprpub/pr/src/bthreads/bsrcs.mk @@ -0,0 +1,49 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# this file lists the source files to be compiled (used in Makefile) and +# then enumerated as object files (in objs.mk) for inclusion in the NSPR +# shared library + +BTCSRCS = \ + btthread.c \ + btlocks.c \ + btcvar.c \ + btmon.c \ + btsem.c \ + btmisc.c \ + $(NULL) diff --git a/nsprpub/pr/src/bthreads/btcvar.c b/nsprpub/pr/src/bthreads/btcvar.c new file mode 100644 index 00000000000..f615bf5b3a8 --- /dev/null +++ b/nsprpub/pr/src/bthreads/btcvar.c @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include "primpl.h" + +/* +** Create a new condition variable. +** +** "lock" is the lock used to protect the condition variable. +** +** Condition variables are synchronization objects that threads can use +** to wait for some condition to occur. +** +** This may fail if memory is tight or if some operating system resource +** is low. In such cases, a NULL will be returned. +*/ +PR_IMPLEMENT(PRCondVar*) + PR_NewCondVar (PRLock *lock) +{ + PRCondVar *cv = PR_NEW( PRCondVar ); + PR_ASSERT( NULL != lock ); + if( NULL != cv ) + { + cv->lock = lock; + cv->sem = create_sem(0, "CVSem"); + cv->handshakeSem = create_sem(0, "CVHandshake"); + cv->signalSem = create_sem( 0, "CVSignal"); + cv->signalBenCount = 0; + cv->ns = cv->nw = 0; + PR_ASSERT( cv->sem >= B_NO_ERROR ); + PR_ASSERT( cv->handshakeSem >= B_NO_ERROR ); + PR_ASSERT( cv->signalSem >= B_NO_ERROR ); + } + return cv; +} /* PR_NewCondVar */ + +/* +** Destroy a condition variable. There must be no thread +** waiting on the condvar. The caller is responsible for guaranteeing +** that the condvar is no longer in use. +** +*/ +PR_IMPLEMENT(void) + PR_DestroyCondVar (PRCondVar *cvar) +{ + status_t result = delete_sem( cvar->sem ); + PR_ASSERT( result == B_NO_ERROR ); + + result = delete_sem( cvar->handshakeSem ); + PR_ASSERT( result == B_NO_ERROR ); + + result = delete_sem( cvar->signalSem ); + PR_ASSERT( result == B_NO_ERROR ); + + PR_DELETE( cvar ); +} + +/* +** The thread that waits on a condition is blocked in a "waiting on +** condition" state until another thread notifies the condition or a +** caller specified amount of time expires. The lock associated with +** the condition variable will be released, which must have be held +** prior to the call to wait. +** +** Logically a notified thread is moved from the "waiting on condition" +** state and made "ready." When scheduled, it will attempt to reacquire +** the lock that it held when wait was called. +** +** The timeout has two well known values, PR_INTERVAL_NO_TIMEOUT and +** PR_INTERVAL_NO_WAIT. The former value requires that a condition be +** notified (or the thread interrupted) before it will resume from the +** wait. If the timeout has a value of PR_INTERVAL_NO_WAIT, the effect +** is to release the lock, possibly causing a rescheduling within the +** runtime, then immediately attempting to reacquire the lock and resume. +** +** Any other value for timeout will cause the thread to be rescheduled +** either due to explicit notification or an expired interval. The latter +** must be determined by treating time as one part of the monitored data +** being protected by the lock and tested explicitly for an expired +** interval. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable or the thread was interrupted (PR_Interrupt()). +** The particular reason can be extracted with PR_GetError(). +*/ +PR_IMPLEMENT(PRStatus) + PR_WaitCondVar (PRCondVar *cvar, PRIntervalTime timeout) +{ + status_t err; + if( timeout == PR_INTERVAL_NO_WAIT ) + { + PR_Unlock( cvar->lock ); + PR_Lock( cvar->lock ); + return PR_SUCCESS; + } + + if( atomic_add( &cvar->signalBenCount, 1 ) > 0 ) + { + if (acquire_sem(cvar->signalSem) == B_INTERRUPTED) + { + atomic_add( &cvar->signalBenCount, -1 ); + return PR_FAILURE; + } + } + cvar->nw += 1; + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem_etc(cvar->signalSem, 1, B_DO_NOT_RESCHEDULE); + } + + PR_Unlock( cvar->lock ); + if( timeout==PR_INTERVAL_NO_TIMEOUT ) + { + err = acquire_sem(cvar->sem); + } + else + { + err = acquire_sem_etc(cvar->sem, 1, B_RELATIVE_TIMEOUT, PR_IntervalToMicroseconds(timeout) ); + } + + if( atomic_add( &cvar->signalBenCount, 1 ) > 0 ) + { + while (acquire_sem(cvar->signalSem) == B_INTERRUPTED); + } + + if (cvar->ns > 0) + { + release_sem_etc(cvar->handshakeSem, 1, B_DO_NOT_RESCHEDULE); + cvar->ns -= 1; + } + cvar->nw -= 1; + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem_etc(cvar->signalSem, 1, B_DO_NOT_RESCHEDULE); + } + + PR_Lock( cvar->lock ); + if(err!=B_NO_ERROR) + { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +/* +** Notify ONE thread that is currently waiting on 'cvar'. Which thread is +** dependent on the implementation of the runtime. Common sense would dictate +** that all threads waiting on a single condition have identical semantics, +** therefore which one gets notified is not significant. +** +** The calling thead must hold the lock that protects the condition, as +** well as the invariants that are tightly bound to the condition, when +** notify is called. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +PR_IMPLEMENT(PRStatus) + PR_NotifyCondVar (PRCondVar *cvar) +{ + status_t err ; + if( atomic_add( &cvar->signalBenCount, 1 ) > 0 ) + { + if (acquire_sem(cvar->signalSem) == B_INTERRUPTED) + { + atomic_add( &cvar->signalBenCount, -1 ); + return PR_FAILURE; + } + } + if (cvar->nw > cvar->ns) + { + cvar->ns += 1; + release_sem_etc(cvar->sem, 1, B_DO_NOT_RESCHEDULE); + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem_etc(cvar->signalSem, 1, B_DO_NOT_RESCHEDULE); + } + + while (acquire_sem(cvar->handshakeSem) == B_INTERRUPTED) + { + err = B_INTERRUPTED; + } + } + else + { + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem_etc(cvar->signalSem, 1, B_DO_NOT_RESCHEDULE); + } + } + return PR_SUCCESS; +} + +/* +** Notify all of the threads waiting on the condition variable. The order +** that the threads are notified is indeterminant. The lock that protects +** the condition must be held. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +PR_IMPLEMENT(PRStatus) + PR_NotifyAllCondVar (PRCondVar *cvar) +{ + int32 handshakes; + status_t err = B_OK; + + if( atomic_add( &cvar->signalBenCount, 1 ) > 0 ) + { + if (acquire_sem(cvar->signalSem) == B_INTERRUPTED) + { + atomic_add( &cvar->signalBenCount, -1 ); + return PR_FAILURE; + } + } + + if (cvar->nw > cvar->ns) + { + handshakes = cvar->nw - cvar->ns; + cvar->ns = cvar->nw; + release_sem_etc(cvar->sem, handshakes, B_DO_NOT_RESCHEDULE); + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem_etc(cvar->signalSem, 1, B_DO_NOT_RESCHEDULE); + } + + while (acquire_sem_etc(cvar->handshakeSem, handshakes, 0, 0) == B_INTERRUPTED) + { + err = B_INTERRUPTED; + } + } + else + { + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem_etc(cvar->signalSem, 1, B_DO_NOT_RESCHEDULE); + } + } + return PR_SUCCESS; +} diff --git a/nsprpub/pr/src/bthreads/btlocks.c b/nsprpub/pr/src/bthreads/btlocks.c new file mode 100644 index 00000000000..bf8bfd474bd --- /dev/null +++ b/nsprpub/pr/src/bthreads/btlocks.c @@ -0,0 +1,116 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: btlocks.c +** Description: Implemenation for thread locks using bthreads +** Exports: prlock.h +*/ + +#include "primpl.h" + +#include +#include + +void +_PR_InitLocks (void) +{ +} + +PR_IMPLEMENT(PRLock*) + PR_NewLock (void) +{ + PRLock *lock; + status_t semresult; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + lock = PR_NEWZAP(PRLock); + if (lock != NULL) { + + lock->benaphoreCount = 0; + lock->semaphoreID = create_sem( 0, "nsprLockSem" ); + if( lock->semaphoreID < B_NO_ERROR ) { + + PR_DELETE( lock ); + lock = NULL; + } + } + + return lock; +} + +PR_IMPLEMENT(void) + PR_DestroyLock (PRLock* lock) +{ + status_t result; + + PR_ASSERT(NULL != lock); + result = delete_sem(lock->semaphoreID); + PR_ASSERT(result == B_NO_ERROR); + PR_DELETE(lock); +} + +PR_IMPLEMENT(void) + PR_Lock (PRLock* lock) +{ + PR_ASSERT(lock != NULL); + + if( atomic_add( &lock->benaphoreCount, 1 ) > 0 ) { + + if( acquire_sem(lock->semaphoreID ) != B_NO_ERROR ) { + + atomic_add( &lock->benaphoreCount, -1 ); + return; + } + } + + lock->owner = find_thread( NULL ); +} + +PR_IMPLEMENT(PRStatus) + PR_Unlock (PRLock* lock) +{ + PR_ASSERT(lock != NULL); + lock->owner = NULL; + if( atomic_add( &lock->benaphoreCount, -1 ) > 1 ) { + + release_sem_etc( lock->semaphoreID, 1, B_DO_NOT_RESCHEDULE ); + } + + return PR_SUCCESS; +} diff --git a/nsprpub/pr/src/bthreads/btmisc.c b/nsprpub/pr/src/bthreads/btmisc.c new file mode 100644 index 00000000000..2d678a9d14c --- /dev/null +++ b/nsprpub/pr/src/bthreads/btmisc.c @@ -0,0 +1,104 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include + +// void _PR_InitCPUs(void) {PT_LOG("_PR_InitCPUs")} +// void _MD_StartInterrupts(void) {PT_LOG("_MD_StartInterrupts")} + +/* this is a total hack.. */ + +struct protoent* getprotobyname(const char* name) +{ + return 0; +} + +struct protoent* getprotobynumber(int number) +{ + return 0; +} + +/* this is needed by prinit for some reason */ +void +_PR_InitStacks (void) +{ +} + +/* this is needed by prinit for some reason */ +void +_PR_InitTPD (void) +{ +} + +/* +** Create extra virtual processor threads. Generally used with MP systems. +*/ +PR_IMPLEMENT(void) + PR_SetConcurrency (PRUintn numCPUs) +{ +} + +/* +** Set thread recycle mode to on (1) or off (0) +*/ +PR_IMPLEMENT(void) + PR_SetThreadRecycleMode (PRUint32 flag) +{ +} + +/* +** Get context registers, return with error for now. +*/ + +PR_IMPLEMENT(PRWord *) +_MD_HomeGCRegisters( PRThread *t, int isCurrent, int *np ) +{ + return 0; +} + +PR_IMPLEMENT(void *) +PR_GetSP( PRThread *t ) +{ + return 0; +} + +PR_IMPLEMENT(PRStatus) +PR_EnumerateThreads( PREnumerator func, void *arg ) +{ + return PR_FAILURE; +} diff --git a/nsprpub/pr/src/bthreads/btmon.c b/nsprpub/pr/src/bthreads/btmon.c new file mode 100644 index 00000000000..f14d1379b72 --- /dev/null +++ b/nsprpub/pr/src/bthreads/btmon.c @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include "primpl.h" + +/* +** Create a new monitor. Monitors are re-entrant locks with a single built-in +** condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +PR_IMPLEMENT(PRMonitor*) + PR_NewMonitor (void) +{ + PRMonitor *mon; + PRCondVar *cvar; + PRLock *lock; + + mon = PR_NEWZAP( PRMonitor ); + if( mon ) + { + lock = PR_NewLock(); + if( !lock ) + { + PR_DELETE( mon ); + return( 0 ); + } + + cvar = PR_NewCondVar( lock ); + if( !cvar ) + { + PR_DestroyLock( lock ); + PR_DELETE( mon ); + return( 0 ); + } + + mon->cvar = cvar; + mon->name = NULL; + } + + return( mon ); +} + +PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) +{ + PRMonitor* mon = PR_NewMonitor(); + if( mon ) + { + mon->name = name; + } + return mon; +} + +/* +** Destroy a monitor. The caller is responsible for guaranteeing that the +** monitor is no longer in use. There must be no thread waiting on the +** monitor's condition variable and that the lock is not held. +** +*/ +PR_IMPLEMENT(void) + PR_DestroyMonitor (PRMonitor *mon) +{ + PR_DestroyLock( mon->cvar->lock ); + PR_DestroyCondVar( mon->cvar ); + PR_DELETE( mon ); +} + +/* +** Enter the lock associated with the monitor. If the calling thread currently +** is in the monitor, the call to enter will silently succeed. In either case, +** it will increment the entry count by one. +*/ +PR_IMPLEMENT(void) + PR_EnterMonitor (PRMonitor *mon) +{ + if( mon->cvar->lock->owner == find_thread( NULL ) ) + { + mon->entryCount++; + + } else + { + PR_Lock( mon->cvar->lock ); + mon->entryCount = 1; + } +} + +/* +** Decrement the entry count associated with the monitor. If the decremented +** entry count is zero, the monitor is exited. Returns PR_FAILURE if the +** calling thread has not entered the monitor. +*/ +PR_IMPLEMENT(PRStatus) + PR_ExitMonitor (PRMonitor *mon) +{ + if( mon->cvar->lock->owner != find_thread( NULL ) ) + { + return( PR_FAILURE ); + } + if( --mon->entryCount == 0 ) + { + return( PR_Unlock( mon->cvar->lock ) ); + } + return( PR_SUCCESS ); +} + +/* +** Wait for a notify on the monitor's condition variable. Sleep for "ticks" +** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is +** indefinite). +** +** While the thread is waiting it exits the monitor (as if it called +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When +** the wait has finished the thread regains control of the monitors lock +** with the same entry count as before the wait began. +** +** The thread waiting on the monitor will be resumed when the monitor is +** notified (assuming the thread is the next in line to receive the +** notify) or when the "ticks" timeout elapses. +** +** Returns PR_FAILURE if the caller has not entered the monitor. +*/ +PR_IMPLEMENT(PRStatus) + PR_Wait (PRMonitor *mon, PRIntervalTime ticks) +{ + PRUint32 entryCount; + PRUintn status; + PRThread *meThread; + thread_id me = find_thread( NULL ); + meThread = PR_GetCurrentThread(); + + if( mon->cvar->lock->owner != me ) return( PR_FAILURE ); + + entryCount = mon->entryCount; + mon->entryCount = 0; + + status = PR_WaitCondVar( mon->cvar, ticks ); + + mon->entryCount = entryCount; + + return( status ); +} + +/* +** Notify a thread waiting on the monitor's condition variable. If a thread +** is waiting on the condition variable (using PR_Wait) then it is awakened +** and attempts to reenter the monitor. +*/ +PR_IMPLEMENT(PRStatus) + PR_Notify (PRMonitor *mon) +{ + if( mon->cvar->lock->owner != find_thread( NULL ) ) + { + return( PR_FAILURE ); + } + + PR_NotifyCondVar( mon->cvar ); + return( PR_SUCCESS ); +} + +/* +** Notify all of the threads waiting on the monitor's condition variable. +** All of threads waiting on the condition are scheduled to reenter the +** monitor. +*/ +PR_IMPLEMENT(PRStatus) + PR_NotifyAll (PRMonitor *mon) +{ + if( mon->cvar->lock->owner != find_thread( NULL ) ) + { + return( PR_FAILURE ); + } + + PR_NotifyAllCondVar( mon->cvar ); + return( PR_SUCCESS ); +} + +PR_IMPLEMENT(PRIntn) + PR_GetMonitorEntryCount(PRMonitor *mon) +{ + return( mon->entryCount ); +} + diff --git a/nsprpub/pr/src/bthreads/btsem.c b/nsprpub/pr/src/bthreads/btsem.c new file mode 100644 index 00000000000..bce28142bca --- /dev/null +++ b/nsprpub/pr/src/bthreads/btsem.c @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include "primpl.h" + +/* +** Create a new semaphore object. +*/ +PR_IMPLEMENT(PRSemaphore*) + PR_NewSem (PRUintn value) +{ + PRSemaphore *semaphore; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + semaphore = PR_NEWZAP(PRSemaphore); + if (NULL != semaphore) { + if ((semaphore->sem = create_sem(value, "nspr_sem")) < B_NO_ERROR) + return NULL; + else + return semaphore; + } + return NULL; +} + +/* +** Destroy the given semaphore object. +** +*/ +PR_IMPLEMENT(void) + PR_DestroySem (PRSemaphore *sem) +{ + status_t result; + + PR_ASSERT(sem != NULL); + result = delete_sem(sem->sem); + PR_ASSERT(result == B_NO_ERROR); + PR_DELETE(sem); +} + +/* +** Wait on a Semaphore. +** +** This routine allows a calling thread to wait or proceed depending upon +** the state of the semahore sem. The thread can proceed only if the +** counter value of the semaphore sem is currently greater than 0. If the +** value of semaphore sem is positive, it is decremented by one and the +** routine returns immediately allowing the calling thread to continue. If +** the value of semaphore sem is 0, the calling thread blocks awaiting the +** semaphore to be released by another thread. +** +** This routine can return PR_PENDING_INTERRUPT if the waiting thread +** has been interrupted. +*/ +PR_IMPLEMENT(PRStatus) + PR_WaitSem (PRSemaphore *sem) +{ + PR_ASSERT(sem != NULL); + if (acquire_sem(sem->sem) == B_NO_ERROR) + return PR_SUCCESS; + else + return PR_FAILURE; +} + +/* +** This routine increments the counter value of the semaphore. If other +** threads are blocked for the semaphore, then the scheduler will +** determine which ONE thread will be unblocked. +*/ +PR_IMPLEMENT(void) + PR_PostSem (PRSemaphore *sem) +{ + status_t result; + + PR_ASSERT(sem != NULL); + result = release_sem_etc(sem->sem, 1, B_DO_NOT_RESCHEDULE); + PR_ASSERT(result == B_NO_ERROR); +} + +/* +** Returns the value of the semaphore referenced by sem without affecting +** the state of the semaphore. The value represents the semaphore value +** at the time of the call, but may not be the actual value when the +** caller inspects it. +*/ +PR_IMPLEMENT(PRUintn) + PR_GetValueSem (PRSemaphore *sem) +{ + sem_info info; + + PR_ASSERT(sem != NULL); + get_sem_info(sem->sem, &info); + return info.count; +} diff --git a/nsprpub/pr/src/bthreads/btthread.c b/nsprpub/pr/src/bthreads/btthread.c new file mode 100644 index 00000000000..33bdfcc70e7 --- /dev/null +++ b/nsprpub/pr/src/bthreads/btthread.c @@ -0,0 +1,694 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include + +#include "prlog.h" +#include "primpl.h" +#include "prcvar.h" +#include "prpdce.h" + +#include +#include +#include + +/* values for PRThread.state */ +#define BT_THREAD_PRIMORD 0x01 /* this is the primordial thread */ +#define BT_THREAD_SYSTEM 0x02 /* this is a system thread */ +#define BT_THREAD_JOINABLE 0x04 /* this is a joinable thread */ + +struct _BT_Bookeeping +{ + PRLock *ml; /* a lock to protect ourselves */ + sem_id cleanUpSem; /* the primoridal thread will block on this + sem while waiting for the user threads */ + PRInt32 threadCount; /* user thred count */ + +} bt_book = { NULL, B_ERROR, 0 }; + + +#define BT_TPD_LIMIT 128 /* number of TPD slots we'll provide (arbitrary) */ + +/* these will be used to map an index returned by PR_NewThreadPrivateIndex() + to the corresponding beos native TLS slot number, and to the destructor + for that slot - note that, because it is allocated globally, this data + will be automatically zeroed for us when the program begins */ +static int32 tpd_beosTLSSlots[BT_TPD_LIMIT]; +static PRThreadPrivateDTOR tpd_dtors[BT_TPD_LIMIT]; + +static vint32 tpd_slotsUsed=0; /* number of currently-allocated TPD slots */ +static int32 tls_prThreadSlot; /* TLS slot in which PRThread will be stored */ + +/* this mutex will be used to synchronize access to every + PRThread.md.joinSem and PRThread.md.is_joining (we could + actually allocate one per thread, but that seems a bit excessive, + especially considering that there will probably be little + contention, PR_JoinThread() is allowed to block anyway, and the code + protected by the mutex is short/fast) */ +static PRLock *joinSemLock; + +static PRUint32 _bt_MapNSPRToNativePriority( PRThreadPriority priority ); +static PRThreadPriority _bt_MapNativeToNSPRPriority( PRUint32 priority ); +static void _bt_CleanupThread(void *arg); +static PRThread *_bt_AttachThread(); + +void +_PR_InitThreads (PRThreadType type, PRThreadPriority priority, + PRUintn maxPTDs) +{ + PRThread *primordialThread; + PRUint32 beThreadPriority; + + /* allocate joinSem mutex */ + joinSemLock = PR_NewLock(); + if (joinSemLock == NULL) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return; + } + + /* + ** Create and initialize NSPR structure for our primordial thread. + */ + + primordialThread = PR_NEWZAP(PRThread); + if( NULL == primordialThread ) + { + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); + return; + } + + primordialThread->md.joinSem = B_ERROR; + + /* + ** Set the priority to the desired level. + */ + + beThreadPriority = _bt_MapNSPRToNativePriority( priority ); + + set_thread_priority( find_thread( NULL ), beThreadPriority ); + + primordialThread->priority = priority; + + + /* set the thread's state - note that the thread is not joinable */ + primordialThread->state |= BT_THREAD_PRIMORD; + if (type == PR_SYSTEM_THREAD) + primordialThread->state |= BT_THREAD_SYSTEM; + + /* + ** Allocate a TLS slot for the PRThread structure (just using + ** native TLS, as opposed to NSPR TPD, will make PR_GetCurrentThread() + ** somewhat faster, and will leave one more TPD slot for our client) + */ + + tls_prThreadSlot = tls_allocate(); + + /* + ** Stuff our new PRThread structure into our thread specific + ** slot. + */ + + tls_set(tls_prThreadSlot, primordialThread); + + /* allocate lock for bt_book */ + bt_book.ml = PR_NewLock(); + if( NULL == bt_book.ml ) + { + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); + return; + } +} + +PRUint32 +_bt_MapNSPRToNativePriority( PRThreadPriority priority ) + { + switch( priority ) + { + case PR_PRIORITY_LOW: return( B_LOW_PRIORITY ); + case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY ); + case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY ); + case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY ); + default: return( B_NORMAL_PRIORITY ); + } +} + +PRThreadPriority +_bt_MapNativeToNSPRPriority(PRUint32 priority) + { + if (priority < B_NORMAL_PRIORITY) + return PR_PRIORITY_LOW; + if (priority < B_DISPLAY_PRIORITY) + return PR_PRIORITY_NORMAL; + if (priority < B_URGENT_DISPLAY_PRIORITY) + return PR_PRIORITY_HIGH; + return PR_PRIORITY_URGENT; +} + +PRUint32 +_bt_mapNativeToNSPRPriority( int32 priority ) +{ + switch( priority ) + { + case PR_PRIORITY_LOW: return( B_LOW_PRIORITY ); + case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY ); + case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY ); + case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY ); + default: return( B_NORMAL_PRIORITY ); + } +} + +/* This method is called by all NSPR threads as they exit */ +void _bt_CleanupThread(void *arg) +{ + PRThread *me = PR_GetCurrentThread(); + int32 i; + + /* first, clean up all thread-private data */ + for (i = 0; i < tpd_slotsUsed; i++) + { + void *oldValue = tls_get(tpd_beosTLSSlots[i]); + if ( oldValue != NULL && tpd_dtors[i] != NULL ) + (*tpd_dtors[i])(oldValue); + } + + /* if this thread is joinable, wait for someone to join it */ + if (me->state & BT_THREAD_JOINABLE) + { + /* protect access to our joinSem */ + PR_Lock(joinSemLock); + + if (me->md.is_joining) + { + /* someone is already waiting to join us (they've + allocated a joinSem for us) - let them know we're + ready */ + delete_sem(me->md.joinSem); + + PR_Unlock(joinSemLock); + + } + else + { + /* noone is currently waiting for our demise - it + is our responsibility to allocate the joinSem + and block on it */ + me->md.joinSem = create_sem(0, "join sem"); + + /* we're done accessing our joinSem */ + PR_Unlock(joinSemLock); + + /* wait for someone to join us */ + while (acquire_sem(me->md.joinSem) == B_INTERRUPTED); + } + } + + /* if this is a user thread, we must update our books */ + if ((me->state & BT_THREAD_SYSTEM) == 0) + { + /* synchronize access to bt_book */ + PR_Lock( bt_book.ml ); + + /* decrement the number of currently-alive user threads */ + bt_book.threadCount--; + + if (bt_book.threadCount == 0 && bt_book.cleanUpSem != B_ERROR) { + /* we are the last user thread, and the primordial thread is + blocked in PR_Cleanup() waiting for us to finish - notify + it */ + delete_sem(bt_book.cleanUpSem); + } + + PR_Unlock( bt_book.ml ); + } + + /* finally, delete this thread's PRThread */ + PR_DELETE(me); +} + +/** + * This is a wrapper that all threads invoke that allows us to set some + * things up prior to a thread's invocation and clean up after a thread has + * exited. + */ +static void* +_bt_root (void* arg) + { + PRThread *thred = (PRThread*)arg; + PRIntn rv; + void *privData; + status_t result; + int i; + + /* save our PRThread object into our TLS */ + tls_set(tls_prThreadSlot, thred); + + thred->startFunc(thred->arg); /* run the dang thing */ + + /* clean up */ + _bt_CleanupThread(NULL); + + return 0; +} + +PR_IMPLEMENT(PRThread*) + PR_CreateThread (PRThreadType type, void (*start)(void* arg), void* arg, + PRThreadPriority priority, PRThreadScope scope, + PRThreadState state, PRUint32 stackSize) +{ + PRUint32 bePriority; + + PRThread* thred; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + thred = PR_NEWZAP(PRThread); + if (thred == NULL) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + thred->md.joinSem = B_ERROR; + + thred->arg = arg; + thred->startFunc = start; + thred->priority = priority; + + if( state == PR_JOINABLE_THREAD ) + { + thred->state |= BT_THREAD_JOINABLE; + } + + /* keep some books */ + + PR_Lock( bt_book.ml ); + + if (type == PR_USER_THREAD) + { + bt_book.threadCount++; + } + + PR_Unlock( bt_book.ml ); + + bePriority = _bt_MapNSPRToNativePriority( priority ); + + thred->md.tid = spawn_thread((thread_func)_bt_root, "moz-thread", + bePriority, thred); + if (thred->md.tid < B_OK) { + PR_SetError(PR_UNKNOWN_ERROR, thred->md.tid); + PR_DELETE(thred); + return NULL; + } + + if (resume_thread(thred->md.tid) < B_OK) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + PR_DELETE(thred); + return NULL; + } + + return thred; + } + +PR_IMPLEMENT(PRThread*) + PR_AttachThread(PRThreadType type, PRThreadPriority priority, + PRThreadStack *stack) +{ + /* PR_GetCurrentThread() will attach a thread if necessary */ + return PR_GetCurrentThread(); +} + +PR_IMPLEMENT(void) + PR_DetachThread() +{ + /* we don't support detaching */ +} + +PR_IMPLEMENT(PRStatus) + PR_JoinThread (PRThread* thred) +{ + status_t eval, status; + + PR_ASSERT(thred != NULL); + + if ((thred->state & BT_THREAD_JOINABLE) == 0) + { + PR_SetError( PR_INVALID_ARGUMENT_ERROR, 0 ); + return( PR_FAILURE ); + } + + /* synchronize access to the thread's joinSem */ + PR_Lock(joinSemLock); + + if (thred->md.is_joining) + { + /* another thread is already waiting to join the specified + thread - we must fail */ + PR_Unlock(joinSemLock); + return PR_FAILURE; + } + + /* let others know we are waiting to join */ + thred->md.is_joining = PR_TRUE; + + if (thred->md.joinSem == B_ERROR) + { + /* the thread hasn't finished yet - it is our responsibility to + allocate a joinSem and wait on it */ + thred->md.joinSem = create_sem(0, "join sem"); + + /* we're done changing the joinSem now */ + PR_Unlock(joinSemLock); + + /* wait for the thread to finish */ + while (acquire_sem(thred->md.joinSem) == B_INTERRUPTED); + + } + else + { + /* the thread has already finished, and has allocated the + joinSem itself - let it know it can finally die */ + delete_sem(thred->md.joinSem); + + PR_Unlock(joinSemLock); + } + + /* make sure the thread is dead */ + wait_for_thread(thred->md.tid, &eval); + + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRThread*) + PR_GetCurrentThread () +{ + PRThread* thred; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + thred = (PRThread *)tls_get( tls_prThreadSlot); + if (thred == NULL) + { + /* this thread doesn't have a PRThread structure (it must be + a native thread not created by the NSPR) - assimilate it */ + thred = _bt_AttachThread(); + } + PR_ASSERT(NULL != thred); + + return thred; +} + +PR_IMPLEMENT(PRThreadScope) + PR_GetThreadScope (const PRThread* thred) +{ + PR_ASSERT(thred != NULL); + return PR_GLOBAL_THREAD; +} + +PR_IMPLEMENT(PRThreadType) + PR_GetThreadType (const PRThread* thred) +{ + PR_ASSERT(thred != NULL); + return (thred->state & BT_THREAD_SYSTEM) ? + PR_SYSTEM_THREAD : PR_USER_THREAD; +} + +PR_IMPLEMENT(PRThreadState) + PR_GetThreadState (const PRThread* thred) +{ + PR_ASSERT(thred != NULL); + return (thred->state & BT_THREAD_JOINABLE)? + PR_JOINABLE_THREAD: PR_UNJOINABLE_THREAD; +} + +PR_IMPLEMENT(PRThreadPriority) + PR_GetThreadPriority (const PRThread* thred) +{ + PR_ASSERT(thred != NULL); + return thred->priority; +} /* PR_GetThreadPriority */ + +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, + PRThreadPriority newPri) +{ + PRUint32 bePriority; + + PR_ASSERT( thred != NULL ); + + thred->priority = newPri; + bePriority = _bt_MapNSPRToNativePriority( newPri ); + set_thread_priority( thred->md.tid, bePriority ); +} + +PR_IMPLEMENT(PRStatus) + PR_NewThreadPrivateIndex (PRUintn* newIndex, + PRThreadPrivateDTOR destructor) +{ + int32 index; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* reserve the next available tpd slot */ + index = atomic_add( &tpd_slotsUsed, 1 ); + if (index >= BT_TPD_LIMIT) + { + /* no slots left - decrement value, then fail */ + atomic_add( &tpd_slotsUsed, -1 ); + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); + return( PR_FAILURE ); + } + + /* allocate a beos-native TLS slot for this index (the new slot + automatically contains NULL) */ + tpd_beosTLSSlots[index] = tls_allocate(); + + /* remember the destructor */ + tpd_dtors[index] = destructor; + + *newIndex = (PRUintn)index; + + return( PR_SUCCESS ); +} + +PR_IMPLEMENT(PRStatus) + PR_SetThreadPrivate (PRUintn index, void* priv) +{ + void *oldValue; + + /* + ** Sanity checking + */ + + if(index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT) + { + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); + return( PR_FAILURE ); + } + + /* if the old value isn't NULL, and the dtor for this slot isn't + NULL, we must destroy the data */ + oldValue = tls_get(tpd_beosTLSSlots[index]); + if (oldValue != NULL && tpd_dtors[index] != NULL) + (*tpd_dtors[index])(oldValue); + + /* save new value */ + tls_set(tpd_beosTLSSlots[index], priv); + + return( PR_SUCCESS ); + } + +PR_IMPLEMENT(void*) + PR_GetThreadPrivate (PRUintn index) +{ + /* make sure the index is valid */ + if (index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT) + { + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); + return NULL; + } + + /* return the value */ + return tls_get( tpd_beosTLSSlots[index] ); + } + + +PR_IMPLEMENT(PRStatus) + PR_Interrupt (PRThread* thred) +{ + PRIntn rv; + + PR_ASSERT(thred != NULL); + + /* + ** there seems to be a bug in beos R5 in which calling + ** resume_thread() on a blocked thread returns B_OK instead + ** of B_BAD_THREAD_STATE (beos bug #20000422-19095). as such, + ** to interrupt a thread, we will simply suspend then resume it + ** (no longer call resume_thread(), check for B_BAD_THREAD_STATE, + ** the suspend/resume to wake up a blocked thread). this wakes + ** up blocked threads properly, and doesn't hurt unblocked threads + ** (they simply get stopped then re-started immediately) + */ + + rv = suspend_thread( thred->md.tid ); + if( rv != B_NO_ERROR ) + { + /* this doesn't appear to be a valid thread_id */ + PR_SetError( PR_UNKNOWN_ERROR, rv ); + return PR_FAILURE; + } + + rv = resume_thread( thred->md.tid ); + if( rv != B_NO_ERROR ) + { + PR_SetError( PR_UNKNOWN_ERROR, rv ); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +PR_IMPLEMENT(void) + PR_ClearInterrupt () +{ +} + +PR_IMPLEMENT(PRStatus) + PR_Yield () +{ + /* we just sleep for long enough to cause a reschedule (100 + microseconds) */ + snooze(100); +} + +#define BT_MILLION 1000000UL + +PR_IMPLEMENT(PRStatus) + PR_Sleep (PRIntervalTime ticks) +{ + bigtime_t tps; + status_t status; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + tps = PR_IntervalToMicroseconds( ticks ); + + status = snooze(tps); + if (status == B_NO_ERROR) return PR_SUCCESS; + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, status); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) + PR_Cleanup () +{ + PRThread *me = PR_GetCurrentThread(); + + PR_ASSERT(me->state & BT_THREAD_PRIMORD); + if ((me->state & BT_THREAD_PRIMORD) == 0) { + return PR_FAILURE; + } + + PR_Lock( bt_book.ml ); + + if (bt_book.threadCount != 0) + { + /* we'll have to wait for some threads to finish - create a + sem to block on */ + bt_book.cleanUpSem = create_sem(0, "cleanup sem"); + } + + PR_Unlock( bt_book.ml ); + + /* note that, if all the user threads were already dead, we + wouldn't have created a sem above, so this acquire_sem() + will fail immediately */ + while (acquire_sem(bt_book.cleanUpSem) == B_INTERRUPTED); + + return PR_SUCCESS; +} + +PR_IMPLEMENT(void) + PR_ProcessExit (PRIntn status) +{ + exit(status); +} + +PRThread *_bt_AttachThread() +{ + PRThread *thread; + thread_info tInfo; + + /* make sure this thread doesn't already have a PRThread structure */ + PR_ASSERT(tls_get(tls_prThreadSlot) == NULL); + + /* allocate a PRThread structure for this thread */ + thread = PR_NEWZAP(PRThread); + if (thread == NULL) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + /* get the native thread's current state */ + get_thread_info(find_thread(NULL), &tInfo); + + /* initialize new PRThread */ + thread->md.tid = tInfo.thread; + thread->md.joinSem = B_ERROR; + thread->priority = _bt_MapNativeToNSPRPriority(tInfo.priority); + + /* attached threads are always non-joinable user threads */ + thread->state = 0; + + /* increment user thread count */ + PR_Lock(bt_book.ml); + bt_book.threadCount++; + PR_Unlock(bt_book.ml); + + /* store this thread's PRThread */ + tls_set(tls_prThreadSlot, thread); + + /* the thread must call _bt_CleanupThread() before it dies, in order + to clean up its PRThread, synchronize with the primordial thread, + etc. */ + on_exit_thread(_bt_CleanupThread, NULL); + + return thread; +} diff --git a/nsprpub/pr/src/bthreads/objs.mk b/nsprpub/pr/src/bthreads/objs.mk new file mode 100644 index 00000000000..60455a3768d --- /dev/null +++ b/nsprpub/pr/src/bthreads/objs.mk @@ -0,0 +1,43 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# This makefile appends to the variable OBJS the bthread object modules +# that will be part of the nspr20 library. + +include $(srcdir)/bthreads/bsrcs.mk + +OBJS += $(BTCSRCS:%.c=bthreads/$(OBJDIR)/%.$(OBJ_SUFFIX)) diff --git a/nsprpub/pr/src/cplus/.cvsignore b/nsprpub/pr/src/cplus/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/cplus/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/cplus/Makefile.in b/nsprpub/pr/src/cplus/Makefile.in new file mode 100644 index 00000000000..46e62e75f61 --- /dev/null +++ b/nsprpub/pr/src/cplus/Makefile.in @@ -0,0 +1,75 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +CXXSRCS = \ + rcbase.cpp \ + rccv.cpp \ + rcfileio.cpp \ + rcinrval.cpp \ + rcio.cpp \ + rclock.cpp \ + rcnetdb.cpp \ + rcnetio.cpp \ + rcthread.cpp \ + rctime.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +HEADERS = $(wildcard $(srcdir)/*.h) + +export:: $(TARGETS) + diff --git a/nsprpub/pr/src/cplus/rcascii.h b/nsprpub/pr/src/cplus/rcascii.h new file mode 100644 index 00000000000..8476fc49e9d --- /dev/null +++ b/nsprpub/pr/src/cplus/rcascii.h @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Class definitions to format ASCII data. +*/ + +#if defined(_RCASCII_H) +#else +#define _RCASCII_H + +/* +** RCFormatStuff +** This class maintains no state - that is the responsibility of +** the class' client. For each call to Sx_printf(), the StuffFunction +** will be called for each embedded "%" in the 'fmt' string and once +** for each interveaning literal. +*/ +class PR_IMPLEMENT(RCFormatStuff) +{ +public: + RCFormatStuff(); + virtual ~RCFormatStuff(); + + /* + ** Process the arbitrary argument list using as indicated by + ** the 'fmt' string. Each segment of the processing the stuff + ** function is called with the relavent translation. + */ + virtual PRInt32 Sx_printf(void *state, const char *fmt, ...); + + /* + ** The 'state' argument is not processed by the runtime. It + ** is merely passed from the Sx_printf() call. It is intended + ** to be used by the client to figure out what to do with the + ** new string. + ** + ** The new string ('stuff') is ASCII translation driven by the + ** Sx_printf()'s 'fmt' string. It is not guaranteed to be a null + ** terminated string. + ** + ** The return value is the number of bytes copied from the 'stuff' + ** string. It is accumulated for each of the calls to the stuff + ** function and returned from the original caller of Sx_printf(). + */ + virtual PRSize StuffFunction( + void *state, const char *stuff, PRSize stufflen) = 0; +}; /* RCFormatStuff */ + + +/* +** RCFormatBuffer +** The caller is supplying the buffer, the runtime is doing all +** the conversion. The object contains no state, so is reusable +** and reentrant. +*/ +class PR_IMPLEMENT(RCFormatBuffer): public RCFormatStuff +{ +public: + RCFormatBuffer(); + virtual ~RCFormatBuffer(); + + /* + ** Format the trailing arguments as indicated by the 'fmt' + ** string. Put the result in 'buffer'. Return the number + ** of bytes moved into 'buffer'. 'buffer' will always be + ** a properly terminated string even if the convresion fails. + */ + virtual PRSize Sn_printf( + char *buffer, PRSize length, const char *fmt, ...); + + virtual char *Sm_append(char *buffer, const char *fmt, ...); + +private: + /* + ** This class overrides the stuff function, does not preserve + ** its virtual-ness and no longer allows the clients to call + ** it in the clear. In other words, it is now the implementation + ** for this class. + */ + PRSize StuffFunction(void*, const char*, PRSize); + +}; /* RCFormatBuffer */ + +/* +** RCFormat +** The runtime is supplying the buffer. The object has state - the +** buffer. Each operation must run to completion before the object +** can be reused. When it is, the buffer is reset (whatever that +** means). The result of a conversion is available via the extractor. +** After extracted, the memory still belongs to the class - if the +** caller wants to retain or modify, it must first be copied. +*/ +class PR_IMPLEMENT(RCFormat): pubic RCFormatBuffer +{ +public: + RCFormat(); + virtual ~RCFormat(); + + /* + ** Translate the trailing arguments according to the 'fmt' + ** string and store the results in the object. + */ + virtual PRSize Sm_printf(const char *fmt, ...); + + /* + ** Extract the latest translation. + ** The object does not surrender the memory occupied by + ** the string. If the caller wishes to modify the data, + ** it must first be copied. + */ + const char*(); + +private: + char *buffer; + + RCFormat(const RCFormat&); + RCFormat& operator=(const RCFormat&); +}; /* RCFormat */ + +/* +** RCPrint +** The output is formatted and then written to an associated file +** descriptor. The client can provide a suitable file descriptor +** or can indicate that the output should be directed to one of +** the well-known "console" devices. +*/ +class PR_IMPLEMENT(RCPrint): public RCFormat +{ + virtual ~RCPrint(); + RCPrint(RCIO* output); + RCPrint(RCFileIO::SpecialFile output); + + virtual PRSize Printf(const char *fmt, ...); +private: + RCPrint(); +}; /* RCPrint */ + +#endif /* defined(_RCASCII_H) */ + +/* RCAscii.h */ diff --git a/nsprpub/pr/src/cplus/rcbase.cpp b/nsprpub/pr/src/cplus/rcbase.cpp new file mode 100644 index 00000000000..84662d9ae4e --- /dev/null +++ b/nsprpub/pr/src/cplus/rcbase.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** RCBase.cpp - Mixin class for NSPR C++ wrappers +*/ + +#include "rcbase.h" + +RCBase::~RCBase() { } + +PRSize RCBase::GetErrorTextLength() { return PR_GetErrorTextLength(); } +PRSize RCBase::CopyErrorText(char *text) { return PR_GetErrorText(text); } + +void RCBase::SetError(PRErrorCode error, PRInt32 oserror) + { PR_SetError(error, oserror); } + +void RCBase::SetErrorText(PRSize text_length, const char *text) + { PR_SetErrorText(text_length, text); } + +/* rcbase.cpp */ diff --git a/nsprpub/pr/src/cplus/rcbase.h b/nsprpub/pr/src/cplus/rcbase.h new file mode 100644 index 00000000000..0910a15828b --- /dev/null +++ b/nsprpub/pr/src/cplus/rcbase.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** RCBase.h - Mixin class for NSPR C++ wrappers +*/ + +#if defined(_RCRUNTIME_H) +#else +#define _RCRUNTIME_H + +#include + +/* +** Class: RCBase (mixin) +** +** Generally mixed into every base class. The functions in this class are all +** static. Therefore this entire class is just syntatic sugar. It gives the +** illusion that errors (in particular) are retrieved via the same object +** that just reported a failure. It also (unfortunately) might lead one to +** believe that the errors are persistent in that object. They're not. +*/ + +class PR_IMPLEMENT(RCBase) +{ +public: + virtual ~RCBase(); + + static void AbortSelf(); + + static PRErrorCode GetError(); + static PRInt32 GetOSError(); + + static PRSize GetErrorTextLength(); + static PRSize CopyErrorText(char *text); + + static void SetError(PRErrorCode error, PRInt32 oserror); + static void SetErrorText(PRSize textLength, const char *text); + +protected: + RCBase() { } +}; /* RCObject */ + +inline PRErrorCode RCBase::GetError() { return PR_GetError(); } +inline PRInt32 RCBase::GetOSError() { return PR_GetOSError(); } + +#endif /* defined(_RCRUNTIME_H) */ + +/* rcbase.h */ diff --git a/nsprpub/pr/src/cplus/rccv.cpp b/nsprpub/pr/src/cplus/rccv.cpp new file mode 100644 index 00000000000..5e03ae75d10 --- /dev/null +++ b/nsprpub/pr/src/cplus/rccv.cpp @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** RCCondition - C++ wrapper around NSPR's PRCondVar +*/ + +#include "rccv.h" + +#include +#include +#include + +RCCondition::RCCondition(class RCLock *lock): RCBase() +{ + cv = PR_NewCondVar(lock->lock); + PR_ASSERT(NULL != cv); + timeout = PR_INTERVAL_NO_TIMEOUT; +} /* RCCondition::RCCondition */ + +RCCondition::~RCCondition() +{ + if (NULL != cv) PR_DestroyCondVar(cv); +} /* RCCondition::~RCCondition */ + +PRStatus RCCondition::Wait() +{ + PRStatus rv; + PR_ASSERT(NULL != cv); + if (NULL == cv) + { + SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + else + rv = PR_WaitCondVar(cv, timeout.interval); + return rv; +} /* RCCondition::Wait */ + +PRStatus RCCondition::Notify() +{ + return PR_NotifyCondVar(cv); +} /* RCCondition::Notify */ + +PRStatus RCCondition::Broadcast() +{ + return PR_NotifyAllCondVar(cv); +} /* RCCondition::Broadcast */ + +PRStatus RCCondition::SetTimeout(const RCInterval& tmo) +{ + if (NULL == cv) + { + SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + timeout = tmo; + return PR_SUCCESS; +} /* RCCondition::SetTimeout */ + +RCInterval RCCondition::GetTimeout() const { return timeout; } + +/* rccv.cpp */ diff --git a/nsprpub/pr/src/cplus/rccv.h b/nsprpub/pr/src/cplus/rccv.h new file mode 100644 index 00000000000..56923af1d42 --- /dev/null +++ b/nsprpub/pr/src/cplus/rccv.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** RCCondition - C++ wrapper around NSPR's PRCondVar +** +** Conditions have a notion of timeouts. A thread that waits on a condition +** will resume execution when the condition is notified OR when a specified +** interval of time has expired. +** +** Most applications don't adjust the timeouts on conditions. The literature +** would argue that all threads waiting on a single condition must have the +** same semantics. But if an application wishes to modify the timeout with +** (perhaps) each wait call, that modification should be done consistantly +** and under protection of the condition's associated lock. +** +** The default timeout is infinity. +*/ + +#if defined(_RCCOND_H) +#else +#define _RCCOND_H + +#include "rclock.h" +#include "rcbase.h" +#include "rcinrval.h" + +struct PRCondVar; + +class PR_IMPLEMENT(RCCondition): public RCBase +{ +public: + RCCondition(RCLock*); /* associates CV with a lock and infinite tmo */ + virtual ~RCCondition(); + + virtual PRStatus Wait(); /* applies object's current timeout */ + + virtual PRStatus Notify(); /* perhaps ready one thread */ + virtual PRStatus Broadcast(); /* perhaps ready many threads */ + + virtual PRStatus SetTimeout(const RCInterval&); + /* set object's current timeout value */ + +private: + PRCondVar *cv; + RCInterval timeout; + + RCCondition(); + RCCondition(const RCCondition&); + void operator=(const RCCondition&); + +public: + RCInterval GetTimeout() const; +}; /* RCCondition */ + +inline RCCondition::RCCondition(): RCBase() { } +inline RCCondition::RCCondition(const RCCondition&): RCBase() { } +inline void RCCondition::operator=(const RCCondition&) { } + +#endif /* defined(_RCCOND_H) */ + +/* RCCond.h */ diff --git a/nsprpub/pr/src/cplus/rcfileio.cpp b/nsprpub/pr/src/cplus/rcfileio.cpp new file mode 100644 index 00000000000..7646c89401d --- /dev/null +++ b/nsprpub/pr/src/cplus/rcfileio.cpp @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Class implementation for normal and special file I/O (ref: prio.h) +*/ + +#include "rcfileio.h" + +#include + +RCFileIO::RCFileIO(): RCIO(RCIO::file) { } + +RCFileIO::~RCFileIO() { if (NULL != fd) (void)Close(); } + +PRInt64 RCFileIO::Available() + { return fd->methods->available(fd); } + +PRStatus RCFileIO::Close() + { PRStatus rv = fd->methods->close(fd); fd = NULL; return rv; } + +PRStatus RCFileIO::Delete(const char* filename) { return PR_Delete(filename); } + +PRStatus RCFileIO::FileInfo(RCFileInfo* info) const + { return fd->methods->fileInfo64(fd, &info->info); } + +PRStatus RCFileIO::FileInfo(const char *name, RCFileInfo* info) + { return PR_GetFileInfo64(name, &info->info); } + +PRStatus RCFileIO::Fsync() + { return fd->methods->fsync(fd); } + +PRStatus RCFileIO::Open(const char *filename, PRIntn flags, PRIntn mode) +{ + fd = PR_Open(filename, flags, mode); + return (NULL == fd) ? PR_FAILURE : PR_SUCCESS; +} /* RCFileIO::Open */ + +PRInt32 RCFileIO::Read(void *buf, PRSize amount) + { return fd->methods->read(fd, buf, amount); } + +PRInt64 RCFileIO::Seek(PRInt64 offset, RCIO::Whence how) +{ + PRSeekWhence whence; + switch (how) + { + case RCFileIO::set: whence = PR_SEEK_SET; break; + case RCFileIO::current: whence = PR_SEEK_CUR; break; + case RCFileIO::end: whence = PR_SEEK_END; break; + default: whence = (PRSeekWhence)-1; + } + return fd->methods->seek64(fd, offset, whence); +} /* RCFileIO::Seek */ + +PRInt32 RCFileIO::Write(const void *buf, PRSize amount) + { return fd->methods->write(fd, buf, amount); } + +PRInt32 RCFileIO::Writev( + const PRIOVec *iov, PRSize size, const RCInterval& timeout) + { return fd->methods->writev(fd, iov, size, timeout); } + +RCIO *RCFileIO::GetSpecialFile(RCFileIO::SpecialFile special) +{ + PRFileDesc* fd; + PRSpecialFD which; + RCFileIO* spec = NULL; + + switch (special) + { + case RCFileIO::input: which = PR_StandardInput; break; + case RCFileIO::output: which = PR_StandardOutput; break; + case RCFileIO::error: which = PR_StandardError; break; + default: which = (PRSpecialFD)-1; + } + fd = PR_GetSpecialFD(which); + if (NULL != fd) + { + spec = new RCFileIO(); + if (NULL != spec) spec->fd = fd; + } + return spec; +} /* RCFileIO::GetSpecialFile */ + + +/* +** The following methods have been made non-virtual and private. These +** default implementations are intended to NEVER be called. They +** are not valid for this type of I/O class (normal and special file). +*/ +PRStatus RCFileIO::Connect(const RCNetAddr&, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::GetLocalName(RCNetAddr*) const +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::GetPeerName(RCNetAddr*) const +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::GetSocketOption(PRSocketOptionData*) const +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::Listen(PRIntn) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRInt16 RCFileIO::Poll(PRInt16, PRInt16*) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return 0; } + +PRInt32 RCFileIO::Recv(void*, PRSize, PRIntn, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +PRInt32 RCFileIO::Recvfrom(void*, PRSize, PRIntn, RCNetAddr*, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +PRInt32 RCFileIO::Send( + const void*, PRSize, PRIntn, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +PRInt32 RCFileIO::Sendto( + const void*, PRSize, PRIntn, const RCNetAddr&, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +RCIO* RCFileIO::Accept(RCNetAddr*, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return NULL; } + +PRStatus RCFileIO::Bind(const RCNetAddr&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRInt32 RCFileIO::AcceptRead( + RCIO**, RCNetAddr**, void*, PRSize, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +PRStatus RCFileIO::SetSocketOption(const PRSocketOptionData*) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::Shutdown(RCIO::ShutdownHow) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRInt32 RCFileIO::TransmitFile( + RCIO*, const void*, PRSize, RCIO::FileDisposition, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +/* +** Class implementation for file information object (ref: prio.h) +*/ + +RCFileInfo::~RCFileInfo() { } + +RCFileInfo::RCFileInfo(const RCFileInfo& her): RCBase() + { info = her.info; } /* RCFileInfo::RCFileInfo */ + +RCTime RCFileInfo::CreationTime() const { return RCTime(info.creationTime); } + +RCTime RCFileInfo::ModifyTime() const { return RCTime(info.modifyTime); } + +RCFileInfo::FileType RCFileInfo::Type() const +{ + RCFileInfo::FileType type; + switch (info.type) + { + case PR_FILE_FILE: type = RCFileInfo::file; break; + case PR_FILE_DIRECTORY: type = RCFileInfo::directory; break; + default: type = RCFileInfo::other; + } + return type; +} /* RCFileInfo::Type */ diff --git a/nsprpub/pr/src/cplus/rcfileio.h b/nsprpub/pr/src/cplus/rcfileio.h new file mode 100644 index 00000000000..576b37dffea --- /dev/null +++ b/nsprpub/pr/src/cplus/rcfileio.h @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Class definitions for normal and special file I/O (ref: prio.h) +*/ + +#if defined(_RCFILEIO_H) +#else +#define _RCFILEIO_H + +#include "rcio.h" +#include "rctime.h" + +/* +** One would normally create a concrete class, such as RCFileIO, but then +** pass around more generic references, ie., RCIO. +** +** This subclass of RCIO hides (makes private) the methods that are not +** applicable to normal files. +*/ + +class RCFileInfo; + +class PR_IMPLEMENT(RCFileIO): public RCIO +{ +public: + RCFileIO(); + virtual ~RCFileIO(); + + virtual PRInt64 Available(); + virtual PRStatus Close(); + static PRStatus Delete(const char *name); + virtual PRStatus FileInfo(RCFileInfo* info) const; + static PRStatus FileInfo(const char *name, RCFileInfo* info); + virtual PRStatus Fsync(); + virtual PRStatus Open(const char *name, PRIntn flags, PRIntn mode); + virtual PRInt32 Read(void *buf, PRSize amount); + virtual PRInt64 Seek(PRInt64 offset, RCIO::Whence how); + virtual PRInt32 Write(const void *buf, PRSize amount); + virtual PRInt32 Writev( + const PRIOVec *iov, PRSize size, + const RCInterval& timeout); + +private: + + /* These methods made private are unavailable for this object */ + RCFileIO(const RCFileIO&); + void operator=(const RCFileIO&); + + RCIO* Accept(RCNetAddr* addr, const RCInterval& timeout); + PRInt32 AcceptRead( + RCIO **newfd, RCNetAddr **address, void *buffer, + PRSize amount, const RCInterval& timeout); + PRStatus Bind(const RCNetAddr& addr); + PRStatus Connect(const RCNetAddr& addr, const RCInterval& timeout); + PRStatus GetLocalName(RCNetAddr *addr) const; + PRStatus GetPeerName(RCNetAddr *addr) const; + PRStatus GetSocketOption(PRSocketOptionData *data) const; + PRStatus Listen(PRIntn backlog); + PRInt16 Poll(PRInt16 in_flags, PRInt16 *out_flags); + PRInt32 Recv( + void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout); + PRInt32 Recvfrom( + void *buf, PRSize amount, PRIntn flags, + RCNetAddr* addr, const RCInterval& timeout); + PRInt32 Send( + const void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout); + PRInt32 Sendto( + const void *buf, PRSize amount, PRIntn flags, + const RCNetAddr& addr, + const RCInterval& timeout); + PRStatus SetSocketOption(const PRSocketOptionData *data); + PRStatus Shutdown(RCIO::ShutdownHow how); + PRInt32 TransmitFile( + RCIO *source, const void *headers, + PRSize hlen, RCIO::FileDisposition flags, + const RCInterval& timeout); +public: + + /* + ** The following function return a valid normal file object, + ** Such objects can be used for scanned input and console output. + */ + typedef enum { + input = PR_StandardInput, + output = PR_StandardOutput, + error = PR_StandardError + } SpecialFile; + + static RCIO *GetSpecialFile(RCFileIO::SpecialFile special); + +}; /* RCFileIO */ + +class PR_IMPLEMENT(RCFileInfo): public RCBase +{ +public: + typedef enum { + file = PR_FILE_FILE, + directory = PR_FILE_DIRECTORY, + other = PR_FILE_OTHER + } FileType; + +public: + RCFileInfo(); + RCFileInfo(const RCFileInfo&); + + virtual ~RCFileInfo(); + + PRInt64 Size() const; + RCTime CreationTime() const; + RCTime ModifyTime() const; + RCFileInfo::FileType Type() const; + +friend PRStatus RCFileIO::FileInfo(RCFileInfo*) const; +friend PRStatus RCFileIO::FileInfo(const char *name, RCFileInfo*); + +private: + PRFileInfo64 info; +}; /* RCFileInfo */ + +inline RCFileInfo::RCFileInfo(): RCBase() { } +inline PRInt64 RCFileInfo::Size() const { return info.size; } + +#endif /* defined(_RCFILEIO_H) */ diff --git a/nsprpub/pr/src/cplus/rcinrval.cpp b/nsprpub/pr/src/cplus/rcinrval.cpp new file mode 100644 index 00000000000..ff075a3a9d5 --- /dev/null +++ b/nsprpub/pr/src/cplus/rcinrval.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** C++ interval times (ref: prinrval.h) +** +** An interval is a period of time. The start of the interval (epoch) +** must be defined by the application. The unit of time of an interval +** is platform dependent, therefore so is the maximum interval that is +** representable. However, that interval is never less that ~12 hours. +*/ + +#include "rcinrval.h" + +RCInterval::~RCInterval() { } + +RCInterval::RCInterval(RCInterval::RCReservedInterval special): RCBase() +{ + switch (special) + { + case RCInterval::now: + interval = PR_IntervalNow(); + break; + case RCInterval::no_timeout: + interval = PR_INTERVAL_NO_TIMEOUT; + break; + case RCInterval::no_wait: + interval = PR_INTERVAL_NO_WAIT; + break; + default: + break; + } +} /* RCInterval::RCInterval */ + +/* rcinrval.cpp */ diff --git a/nsprpub/pr/src/cplus/rcinrval.h b/nsprpub/pr/src/cplus/rcinrval.h new file mode 100644 index 00000000000..2dc24987d2f --- /dev/null +++ b/nsprpub/pr/src/cplus/rcinrval.h @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** C++ interval times (ref: prinrval.h) +** +** An interval is a period of time. The start of the interval (epoch) +** must be defined by the application. The unit of time of an interval +** is platform dependent, therefore so is the maximum interval that is +** representable. However, that interval is never less than ~6 hours. +*/ +#if defined(_RCINTERVAL_H) +#else +#define _RCINTERVAL_H + +#include "rcbase.h" +#include + +class PR_IMPLEMENT(RCInterval): public RCBase +{ +public: + typedef enum {now, no_timeout, no_wait} RCReservedInterval; + + virtual ~RCInterval(); + + RCInterval(); + + RCInterval(PRIntervalTime interval); + RCInterval(const RCInterval& copy); + RCInterval(RCReservedInterval special); + + void SetToNow(); + + void operator=(const RCInterval&); + void operator=(PRIntervalTime interval); + + PRBool operator<(const RCInterval&); + PRBool operator>(const RCInterval&); + PRBool operator==(const RCInterval&); + PRBool operator>=(const RCInterval&); + PRBool operator<=(const RCInterval&); + + RCInterval operator+(const RCInterval&); + RCInterval operator-(const RCInterval&); + RCInterval& operator+=(const RCInterval&); + RCInterval& operator-=(const RCInterval&); + + RCInterval operator/(PRUint32); + RCInterval operator*(PRUint32); + RCInterval& operator/=(PRUint32); + RCInterval& operator*=(PRUint32); + + + PRUint32 ToSeconds() const; + PRUint32 ToMilliseconds() const; + PRUint32 ToMicroseconds() const; + operator PRIntervalTime() const; + + static PRIntervalTime FromSeconds(PRUint32 seconds); + static PRIntervalTime FromMilliseconds(PRUint32 milli); + static PRIntervalTime FromMicroseconds(PRUint32 micro); + + friend class RCCondition; + +private: + PRIntervalTime interval; + +}; /* RCInterval */ + + +inline RCInterval::RCInterval(): RCBase() { } + +inline RCInterval::RCInterval(const RCInterval& his): RCBase() + { interval = his.interval; } + +inline RCInterval::RCInterval(PRIntervalTime ticks): RCBase() + { interval = ticks; } + +inline void RCInterval::SetToNow() { interval = PR_IntervalNow(); } + +inline void RCInterval::operator=(const RCInterval& his) + { interval = his.interval; } + +inline void RCInterval::operator=(PRIntervalTime his) + { interval = his; } + +inline PRBool RCInterval::operator==(const RCInterval& his) + { return (interval == his.interval) ? PR_TRUE : PR_FALSE; } +inline PRBool RCInterval::operator<(const RCInterval& his) + { return (interval < his.interval)? PR_TRUE : PR_FALSE; } +inline PRBool RCInterval::operator>(const RCInterval& his) + { return (interval > his.interval) ? PR_TRUE : PR_FALSE; } +inline PRBool RCInterval::operator<=(const RCInterval& his) + { return (interval <= his.interval) ? PR_TRUE : PR_FALSE; } +inline PRBool RCInterval::operator>=(const RCInterval& his) + { return (interval <= his.interval) ? PR_TRUE : PR_FALSE; } + +inline RCInterval RCInterval::operator+(const RCInterval& his) + { return RCInterval((PRIntervalTime)(interval + his.interval)); } +inline RCInterval RCInterval::operator-(const RCInterval& his) + { return RCInterval((PRIntervalTime)(interval - his.interval)); } +inline RCInterval& RCInterval::operator+=(const RCInterval& his) + { interval += his.interval; return *this; } +inline RCInterval& RCInterval::operator-=(const RCInterval& his) + { interval -= his.interval; return *this; } + +inline RCInterval RCInterval::operator/(PRUint32 him) + { return RCInterval((PRIntervalTime)(interval / him)); } +inline RCInterval RCInterval::operator*(PRUint32 him) + { return RCInterval((PRIntervalTime)(interval * him)); } + +inline RCInterval& RCInterval::operator/=(PRUint32 him) + { interval /= him; return *this; } + +inline RCInterval& RCInterval::operator*=(PRUint32 him) + { interval *= him; return *this; } + +inline PRUint32 RCInterval::ToSeconds() const + { return PR_IntervalToSeconds(interval); } +inline PRUint32 RCInterval::ToMilliseconds() const + { return PR_IntervalToMilliseconds(interval); } +inline PRUint32 RCInterval::ToMicroseconds() const + { return PR_IntervalToMicroseconds(interval); } +inline RCInterval::operator PRIntervalTime() const { return interval; } + +inline PRIntervalTime RCInterval::FromSeconds(PRUint32 seconds) + { return PR_SecondsToInterval(seconds); } +inline PRIntervalTime RCInterval::FromMilliseconds(PRUint32 milli) + { return PR_MillisecondsToInterval(milli); } +inline PRIntervalTime RCInterval::FromMicroseconds(PRUint32 micro) + { return PR_MicrosecondsToInterval(micro); } + +#endif /* defined(_RCINTERVAL_H) */ + +/* RCInterval.h */ diff --git a/nsprpub/pr/src/cplus/rcio.cpp b/nsprpub/pr/src/cplus/rcio.cpp new file mode 100644 index 00000000000..27f9e788ac2 --- /dev/null +++ b/nsprpub/pr/src/cplus/rcio.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Base class implmenation for I/O (ref: prio.h) +*/ + +#include "rcio.h" + +RCIO::~RCIO() { } + +RCIO::RCIO(RCIO::RCIOType): RCBase() { } diff --git a/nsprpub/pr/src/cplus/rcio.h b/nsprpub/pr/src/cplus/rcio.h new file mode 100644 index 00000000000..5550a881ba5 --- /dev/null +++ b/nsprpub/pr/src/cplus/rcio.h @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Base class definitions for I/O (ref: prio.h) +** +** This class is a virtual base class. Construction must be done by a +** subclass, but the I/O operations can be done on a RCIO object reference. +*/ + +#if defined(_RCIO_H) +#else +#define _RCIO_H + +#include "rcbase.h" +#include "rcnetdb.h" +#include "rcinrval.h" + +#include "prio.h" + +class RCFileInfo; + +class PR_IMPLEMENT(RCIO): public RCBase +{ +public: + typedef enum { + open = PR_TRANSMITFILE_KEEP_OPEN, /* socket is left open after file + * is transmitted. */ + close = PR_TRANSMITFILE_CLOSE_SOCKET/* socket is closed after file + * is transmitted. */ + } FileDisposition; + + typedef enum { + set = PR_SEEK_SET, /* Set to value specified */ + current = PR_SEEK_CUR, /* Seek relative to current position */ + end = PR_SEEK_END /* seek past end of current eof */ + } Whence; + + typedef enum { + recv = PR_SHUTDOWN_RCV, /* receives will be disallowed */ + send = PR_SHUTDOWN_SEND, /* sends will be disallowed */ + both = PR_SHUTDOWN_BOTH /* sends & receives will be disallowed */ + } ShutdownHow; + +public: + virtual ~RCIO(); + + virtual RCIO* Accept(RCNetAddr* addr, const RCInterval& timeout) = 0; + virtual PRInt32 AcceptRead( + RCIO **nd, RCNetAddr **raddr, void *buf, + PRSize amount, const RCInterval& timeout) = 0; + virtual PRInt64 Available() = 0; + virtual PRStatus Bind(const RCNetAddr& addr) = 0; + virtual PRStatus Close() = 0; + virtual PRStatus Connect( + const RCNetAddr& addr, + const RCInterval& timeout) = 0; + virtual PRStatus FileInfo(RCFileInfo *info) const = 0; + virtual PRStatus Fsync() = 0; + virtual PRStatus GetLocalName(RCNetAddr *addr) const = 0; + virtual PRStatus GetPeerName(RCNetAddr *addr) const = 0; + virtual PRStatus GetSocketOption(PRSocketOptionData *data) const = 0; + virtual PRStatus Listen(PRIntn backlog) = 0; + virtual PRStatus Open(const char *name, PRIntn flags, PRIntn mode) = 0; + virtual PRInt16 Poll(PRInt16 in_flags, PRInt16 *out_flags) = 0; + virtual PRInt32 Read(void *buf, PRSize amount) = 0; + virtual PRInt32 Recv( + void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout) = 0; + virtual PRInt32 Recvfrom( + void *buf, PRSize amount, PRIntn flags, + RCNetAddr* addr, const RCInterval& timeout) = 0; + virtual PRInt64 Seek(PRInt64 offset, Whence how) = 0; + virtual PRInt32 Send( + const void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout) = 0; + virtual PRInt32 Sendto( + const void *buf, PRSize amount, PRIntn flags, + const RCNetAddr& addr, + const RCInterval& timeout) = 0; + virtual PRStatus SetSocketOption(const PRSocketOptionData *data) = 0; + virtual PRStatus Shutdown(ShutdownHow how) = 0; + virtual PRInt32 TransmitFile( + RCIO *source, const void *headers, + PRSize hlen, RCIO::FileDisposition flags, + const RCInterval& timeout) = 0; + virtual PRInt32 Write(const void *buf, PRSize amount) = 0; + virtual PRInt32 Writev( + const PRIOVec *iov, PRSize size, + const RCInterval& timeout) = 0; + +protected: + typedef enum { + file = PR_DESC_FILE, + tcp = PR_DESC_SOCKET_TCP, + udp = PR_DESC_SOCKET_UDP, + layered = PR_DESC_LAYERED} RCIOType; + + RCIO(RCIOType); + + PRFileDesc *fd; /* where the real code hides */ + +private: + /* no default construction and no copies allowed */ + RCIO(); + RCIO(const RCIO&); + +}; /* RCIO */ + +#endif /* defined(_RCIO_H) */ + +/* RCIO.h */ + + diff --git a/nsprpub/pr/src/cplus/rclock.cpp b/nsprpub/pr/src/cplus/rclock.cpp new file mode 100644 index 00000000000..87b326bca74 --- /dev/null +++ b/nsprpub/pr/src/cplus/rclock.cpp @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* +** C++ access to NSPR locks (PRLock) +*/ + +#include "rclock.h" +#include + +RCLock::RCLock() +{ + lock = PR_NewLock(); /* it might be NULL */ + PR_ASSERT(NULL != lock); +} /* RCLock::RCLock */ + +RCLock::~RCLock() +{ + if (NULL != lock) PR_DestroyLock(lock); + lock = NULL; +} /* RCLock::~RCLock */ + +void RCLock::Acquire() +{ + PR_ASSERT(NULL != lock); + PR_Lock(lock); +} /* RCLock::Acquire */ + +void RCLock::Release() +{ + PRStatus rv; + PR_ASSERT(NULL != lock); + rv = PR_Unlock(lock); + PR_ASSERT(PR_SUCCESS == rv); +} /* RCLock::Release */ + +/* RCLock.cpp */ + diff --git a/nsprpub/pr/src/cplus/rclock.h b/nsprpub/pr/src/cplus/rclock.h new file mode 100644 index 00000000000..9e20ef04c7f --- /dev/null +++ b/nsprpub/pr/src/cplus/rclock.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** C++ access to NSPR locks (PRLock) +*/ + +#if defined(_RCLOCK_H) +#else +#define _RCLOCK_H + +#include "rcbase.h" + +#include + +class PR_IMPLEMENT(RCLock): public RCBase +{ +public: + RCLock(); + virtual ~RCLock(); + + void Acquire(); /* non-reentrant */ + void Release(); /* should be by owning thread */ + + friend class RCCondition; + +private: + RCLock(const RCLock&); /* can't do that */ + void operator=(const RCLock&); /* nor that */ + + PRLock *lock; +}; /* RCLock */ + +/* +** Class: RCEnter +** +** In scope locks. You can only allocate them on the stack. The language +** will insure that they get released (by calling the destructor) when +** the thread leaves scope, even if via an exception. +*/ +class PR_IMPLEMENT(RCEnter) +{ +public: + ~RCEnter(); /* releases the lock */ + RCEnter(RCLock*); /* acquires the lock */ + +private: + RCLock *lock; + + RCEnter(); + RCEnter(const RCEnter&); + void operator=(const RCEnter&); + + void *operator new(PRSize) { return NULL; } + void operator delete(void*) { } +}; /* RCEnter */ + + +inline RCEnter::RCEnter(RCLock* ml) { lock = ml; lock->Acquire(); } +inline RCEnter::~RCEnter() { lock->Release(); lock = NULL; } + +#endif /* defined(_RCLOCK_H) */ + +/* RCLock.h */ diff --git a/nsprpub/pr/src/cplus/rcmon.h b/nsprpub/pr/src/cplus/rcmon.h new file mode 100644 index 00000000000..75b8ca3e393 --- /dev/null +++ b/nsprpub/pr/src/cplus/rcmon.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Class: RCMonitor (ref prmonitor.h) +** +** RCMonitor.h - C++ wrapper around NSPR's monitors +*/ +#if defined(_RCMONITOR_H) +#else +#define _RCMONITOR_H + +#include "rcbase.h" +#include "rcinrval.h" + +struct PRMonitor; + +class PR_IMPLEMENT(RCMonitor): public RCBase +{ +public: + RCMonitor(); /* timeout is infinity */ + virtual ~RCMonitor(); + + virtual void Enter(); /* reentrant entry */ + virtual void Exit(); + + virtual void Notify(); /* possibly enable one thread */ + virtual void NotifyAll(); /* enable all waiters */ + + virtual void Wait(); /* applies object's timeout */ + + virtual void SetTimeout(const RCInterval& timeout); + +private: + PRMonitor *monitor; + RCInterval timeout; + +public: + RCInterval GetTimeout() const; /* get the current value */ + +}; /* RCMonitor */ + +#endif /* defined(_RCMONITOR_H) */ + +/* RCMonitor.h */ diff --git a/nsprpub/pr/src/cplus/rcnetdb.cpp b/nsprpub/pr/src/cplus/rcnetdb.cpp new file mode 100644 index 00000000000..9890c9aea84 --- /dev/null +++ b/nsprpub/pr/src/cplus/rcnetdb.cpp @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Base class implementation for network access functions (ref: prnetdb.h) +*/ + +#include "rclock.h" +#include "rcnetdb.h" + +#include +#include +#include + +RCNetAddr::RCNetAddr(const RCNetAddr& his): RCBase() + { address = his.address; } + +RCNetAddr::RCNetAddr(const RCNetAddr& his, PRUint16 port): RCBase() +{ + address = his.address; + switch (address.raw.family) + { + case PR_AF_INET: address.inet.port = port; break; + case PR_AF_INET6: address.ipv6.port = port; break; + default: break; + } +} /* RCNetAddr::RCNetAddr */ + +RCNetAddr::RCNetAddr(RCNetAddr::HostValue host, PRUint16 port): RCBase() +{ + PRNetAddrValue how; + switch (host) + { + case RCNetAddr::any: how = PR_IpAddrAny; break; + case RCNetAddr::loopback: how = PR_IpAddrLoopback; break; + default: PR_ASSERT(!"This can't happen -- and did!"); + } + (void)PR_InitializeNetAddr(how, port, &address); +} /* RCNetAddr::RCNetAddr */ + +RCNetAddr::~RCNetAddr() { } + +void RCNetAddr::operator=(const RCNetAddr& his) { address = his.address; } + +PRStatus RCNetAddr::FromString(const char* string) + { return PR_StringToNetAddr(string, &address); } + +void RCNetAddr::operator=(const PRNetAddr* addr) { address = *addr; } + +PRBool RCNetAddr::operator==(const RCNetAddr& his) const +{ + PRBool rv = EqualHost(his); + if (rv) + { + switch (address.raw.family) + { + case PR_AF_INET: + rv = (address.inet.port == his.address.inet.port); break; + case PR_AF_INET6: + rv = (address.ipv6.port == his.address.ipv6.port); break; + case PR_AF_LOCAL: + default: break; + } + } + return rv; +} /* RCNetAddr::operator== */ + +PRBool RCNetAddr::EqualHost(const RCNetAddr& his) const +{ + PRBool rv; + switch (address.raw.family) + { + case PR_AF_INET: + rv = (address.inet.ip == his.address.inet.ip); break; + case PR_AF_INET6: + rv = (0 == memcmp( + &address.ipv6.ip, &his.address.ipv6.ip, + sizeof(address.ipv6.ip))); + break; +#if defined(XP_UNIX) + case PR_AF_LOCAL: + rv = (0 == strncmp( + address.local.path, his.address.local.path, + sizeof(address.local.path))); + break; +#endif + default: break; + } + return rv; +} /* RCNetAddr::operator== */ + +PRStatus RCNetAddr::ToString(char *string, PRSize size) const + { return PR_NetAddrToString(&address, string, size); } + +/* +** RCHostLookup +*/ + +RCHostLookup::~RCHostLookup() +{ + if (NULL != address) delete [] address; +} /* RCHostLookup::~RCHostLookup */ + +RCHostLookup::RCHostLookup(): RCBase() +{ + address = NULL; + max_index = 0; +} /* RCHostLookup::RCHostLookup */ + +PRStatus RCHostLookup::ByName(const char* name) +{ + PRStatus rv; + PRNetAddr addr; + PRHostEnt hostentry; + PRIntn index = 0, max; + RCNetAddr* vector = NULL; + RCNetAddr* old_vector = NULL; + void* buffer = PR_Malloc(PR_NETDB_BUF_SIZE); + if (NULL == buffer) return PR_FAILURE; + rv = PR_GetHostByName(name, (char*)buffer, PR_NETDB_BUF_SIZE, &hostentry); + if (PR_SUCCESS == rv) + { + for (max = 0, index = 0;; ++max) + { + index = PR_EnumerateHostEnt(index, &hostentry, 0, &addr); + if (0 == index) break; + } + if (max > 0) + { + vector = new RCNetAddr[max]; + while (--max > 0) + { + index = PR_EnumerateHostEnt(index, &hostentry, 0, &addr); + if (0 == index) break; + vector[index] = &addr; + } + { + RCEnter entry(&ml); + old_vector = address; + address = vector; + max_index = max; + } + if (NULL != old_vector) delete [] old_vector; + } + } + if (NULL != buffer) PR_DELETE(buffer); + return PR_SUCCESS; +} /* RCHostLookup::ByName */ + +PRStatus RCHostLookup::ByAddress(const RCNetAddr& host_addr) +{ + PRStatus rv; + PRNetAddr addr; + PRHostEnt hostentry; + PRIntn index = 0, max; + RCNetAddr* vector = NULL; + RCNetAddr* old_vector = NULL; + char *buffer = (char*)PR_Malloc(PR_NETDB_BUF_SIZE); + if (NULL == buffer) return PR_FAILURE; + rv = PR_GetHostByAddr(host_addr, buffer, PR_NETDB_BUF_SIZE, &hostentry); + if (PR_SUCCESS == rv) + { + for (max = 0, index = 0;; ++max) + { + index = PR_EnumerateHostEnt(index, &hostentry, 0, &addr); + if (0 == index) break; + } + if (max > 0) + { + vector = new RCNetAddr[max]; + while (--max > 0) + { + index = PR_EnumerateHostEnt(index, &hostentry, 0, &addr); + if (0 == index) break; + vector[index] = &addr; + } + { + RCEnter entry(&ml); + old_vector = address; + address = vector; + max_index = max; + } + if (NULL != old_vector) delete [] old_vector; + } + } + if (NULL != buffer) PR_DELETE(buffer); + return PR_SUCCESS; +} /* RCHostLookup::ByAddress */ + +const RCNetAddr* RCHostLookup::operator[](PRUintn which) +{ + RCNetAddr* addr = NULL; + if (which < max_index) + addr = &address[which]; + return addr; +} /* RCHostLookup::operator[] */ + +/* RCNetdb.cpp */ diff --git a/nsprpub/pr/src/cplus/rcnetdb.h b/nsprpub/pr/src/cplus/rcnetdb.h new file mode 100644 index 00000000000..03f5b4f0adf --- /dev/null +++ b/nsprpub/pr/src/cplus/rcnetdb.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Base class definitions for network access functions (ref: prnetdb.h) +*/ + +#if defined(_RCNETDB_H) +#else +#define _RCNETDB_H + +#include "rclock.h" +#include "rcbase.h" + +#include + +class PR_IMPLEMENT(RCNetAddr): public RCBase +{ +public: + typedef enum { + any = PR_IpAddrAny, /* assign logical INADDR_ANY */ + loopback = PR_IpAddrLoopback /* assign logical INADDR_LOOPBACK */ + } HostValue; + + RCNetAddr(); /* default constructor is unit'd object */ + RCNetAddr(const RCNetAddr&); /* copy constructor */ + RCNetAddr(HostValue, PRUint16 port);/* init'd w/ 'special' assignments */ + RCNetAddr(const RCNetAddr&, PRUint16 port); + /* copy w/ port reassigment */ + + virtual ~RCNetAddr(); + + void operator=(const RCNetAddr&); + + virtual PRBool operator==(const RCNetAddr&) const; + /* compare of all relavent fields */ + virtual PRBool EqualHost(const RCNetAddr&) const; + /* compare of just host field */ + + +public: + + void operator=(const PRNetAddr*); /* construction from more primitive data */ + operator const PRNetAddr*() const; /* extraction of underlying representation */ + virtual PRStatus FromString(const char* string); + /* initialization from an ASCII string */ + virtual PRStatus ToString(char *string, PRSize size) const; + /* convert internal fromat to a string */ + +private: + + PRNetAddr address; + +}; /* RCNetAddr */ + +/* +** Class: RCHostLookup +** +** Abstractions to look up host names and addresses. +** +** This is a stateful class. One looks up the host by name or by +** address, then enumerates over a possibly empty array of network +** addresses. The storage for the addresses is owned by the class. +*/ + +class RCHostLookup: public RCBase +{ +public: + virtual ~RCHostLookup(); + + RCHostLookup(); + + virtual PRStatus ByName(const char* name); + virtual PRStatus ByAddress(const RCNetAddr&); + + virtual const RCNetAddr* operator[](PRUintn); + +private: + RCLock ml; + PRIntn max_index; + RCNetAddr* address; + + RCHostLookup(const RCHostLookup&); + RCHostLookup& operator=(const RCHostLookup&); +}; + +inline RCNetAddr::RCNetAddr(): RCBase() { } +inline RCNetAddr::operator const PRNetAddr*() const { return &address; } + + +#endif /* defined(_RCNETDB_H) */ + +/* RCNetdb.h */ + + diff --git a/nsprpub/pr/src/cplus/rcnetio.cpp b/nsprpub/pr/src/cplus/rcnetio.cpp new file mode 100644 index 00000000000..bdc94309c84 --- /dev/null +++ b/nsprpub/pr/src/cplus/rcnetio.cpp @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Subclass implementation for streamed network I/O (ref: prio.h) +*/ + +#include "rcnetio.h" + +#include + +RCNetStreamIO::~RCNetStreamIO() + { PRStatus rv = (fd->methods->close)(fd); fd = NULL; } + +RCNetStreamIO::RCNetStreamIO(): RCIO(RCIO::tcp) + { fd = PR_NewTCPSocket(); } + +RCNetStreamIO::RCNetStreamIO(PRIntn protocol): RCIO(RCIO::tcp) + { fd = PR_Socket(PR_AF_INET, PR_SOCK_STREAM, protocol); } + +RCIO* RCNetStreamIO::Accept(RCNetAddr* addr, const RCInterval& timeout) +{ + PRNetAddr peer; + RCNetStreamIO* rcio = NULL; + PRFileDesc* newfd = fd->methods->accept(fd, &peer, timeout); + if (NULL != newfd) + { + rcio = new RCNetStreamIO(); + if (NULL != rcio) + { + *addr = &peer; + rcio->fd = newfd; + } + else + (void)(newfd->methods->close)(newfd); + } + return rcio; +} /* RCNetStreamIO::Accept */ + +PRInt32 RCNetStreamIO::AcceptRead( + RCIO **nd, RCNetAddr **raddr, void *buf, + PRSize amount, const RCInterval& timeout) +{ + PRNetAddr *from; + PRFileDesc *accepted; + PRInt32 rv = (fd->methods->acceptread)( + fd, &accepted, &from, buf, amount, timeout); + if (rv >= 0) + { + RCNetStreamIO *ns = new RCNetStreamIO(); + if (NULL != *nd) ns->fd = accepted; + else {PR_Close(accepted); rv = -1; } + *nd = ns; + } + return rv; +} /* RCNetStreamIO::AcceptRead */ + +PRInt64 RCNetStreamIO::Available() + { return (fd->methods->available64)(fd); } + +PRStatus RCNetStreamIO::Bind(const RCNetAddr& addr) + { return (fd->methods->bind)(fd, addr); } + +PRStatus RCNetStreamIO::Connect(const RCNetAddr& addr, const RCInterval& timeout) + { return (fd->methods->connect)(fd, addr, timeout); } + +PRStatus RCNetStreamIO::GetLocalName(RCNetAddr *addr) const +{ + PRNetAddr local; + PRStatus rv = (fd->methods->getsockname)(fd, &local); + if (PR_SUCCESS == rv) *addr = &local; + return rv; +} /* RCNetStreamIO::GetLocalName */ + +PRStatus RCNetStreamIO::GetPeerName(RCNetAddr *addr) const +{ + PRNetAddr peer; + PRStatus rv = (fd->methods->getpeername)(fd, &peer); + if (PR_SUCCESS == rv) *addr = &peer; + return rv; +} /* RCNetStreamIO::GetPeerName */ + +PRStatus RCNetStreamIO::GetSocketOption(PRSocketOptionData *data) const + { return (fd->methods->getsocketoption)(fd, data); } + +PRStatus RCNetStreamIO::Listen(PRIntn backlog) + { return (fd->methods->listen)(fd, backlog); } + +PRInt16 RCNetStreamIO::Poll(PRInt16 in_flags, PRInt16 *out_flags) + { return (fd->methods->poll)(fd, in_flags, out_flags); } + +PRInt32 RCNetStreamIO::Read(void *buf, PRSize amount) + { return (fd->methods->read)(fd, buf, amount); } + +PRInt32 RCNetStreamIO::Recv( + void *buf, PRSize amount, PRIntn flags, const RCInterval& timeout) + { return (fd->methods->recv)(fd, buf, amount, flags, timeout); } + +PRInt32 RCNetStreamIO::Recvfrom( + void *buf, PRSize amount, PRIntn flags, + RCNetAddr* addr, const RCInterval& timeout) +{ + PRNetAddr peer; + PRInt32 rv = (fd->methods->recvfrom)( + fd, buf, amount, flags, &peer, timeout); + if (-1 != rv) *addr = &peer; + return rv; +} /* RCNetStreamIO::Recvfrom */ + +PRInt32 RCNetStreamIO::Send( + const void *buf, PRSize amount, PRIntn flags, const RCInterval& timeout) + { return (fd->methods->send)(fd, buf, amount, flags, timeout); } + +PRInt32 RCNetStreamIO::Sendto( + const void *buf, PRSize amount, PRIntn flags, + const RCNetAddr& addr, const RCInterval& timeout) + { return (fd->methods->sendto)(fd, buf, amount, flags, addr, timeout); } + +PRStatus RCNetStreamIO::SetSocketOption(const PRSocketOptionData *data) + { return (fd->methods->setsocketoption)(fd, data); } + +PRStatus RCNetStreamIO::Shutdown(RCIO::ShutdownHow how) + { return (fd->methods->shutdown)(fd, (PRIntn)how); } + +PRInt32 RCNetStreamIO::TransmitFile( + RCIO *source, const void *headers, PRSize hlen, + RCIO::FileDisposition flags, const RCInterval& timeout) +{ + RCNetStreamIO *src = (RCNetStreamIO*)source; + return (fd->methods->transmitfile)( + fd, src->fd, headers, hlen, (PRTransmitFileFlags)flags, timeout); } + +PRInt32 RCNetStreamIO::Write(const void *buf, PRSize amount) + { return (fd->methods->write)(fd, buf, amount); } + +PRInt32 RCNetStreamIO::Writev( + const PRIOVec *iov, PRSize size, const RCInterval& timeout) + { return (fd->methods->writev)(fd, iov, size, timeout); } + +/* +** Invalid functions +*/ + +PRStatus RCNetStreamIO::Close() + { PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCNetStreamIO::FileInfo(RCFileInfo*) const + { PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCNetStreamIO::Fsync() + { return (fd->methods->fsync)(fd); } + +PRStatus RCNetStreamIO::Open(const char*, PRIntn, PRIntn) + { PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRInt64 RCNetStreamIO::Seek(PRInt64, RCIO::Whence) + { PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +/* RCNetStreamIO.cpp */ + + diff --git a/nsprpub/pr/src/cplus/rcnetio.h b/nsprpub/pr/src/cplus/rcnetio.h new file mode 100644 index 00000000000..54ce695fc73 --- /dev/null +++ b/nsprpub/pr/src/cplus/rcnetio.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Subclass definitions for network I/O (ref: prio.h) +*/ + +#if defined(_RCNETIO_H) +#else +#define _RCNETIO_H + +#include "rcbase.h" +#include "rcinrval.h" +#include "rcio.h" +#include "rcnetdb.h" + +#include "prio.h" + +class RCFileInfo; + +/* +** Class: RCNetStreamIO (ref prio.h) +** +** Streamed (reliable) network I/O (e.g., TCP). +** This class hides (makes private) the functions that are not applicable +** to network I/O (i.e., those for file I/O). +*/ + +class PR_IMPLEMENT(RCNetStreamIO): public RCIO +{ + +public: + RCNetStreamIO(); + virtual ~RCNetStreamIO(); + + virtual RCIO* Accept(RCNetAddr* addr, const RCInterval& timeout); + virtual PRInt32 AcceptRead( + RCIO **nd, RCNetAddr **raddr, void *buf, + PRSize amount, const RCInterval& timeout); + virtual PRInt64 Available(); + virtual PRStatus Bind(const RCNetAddr& addr); + virtual PRStatus Connect( + const RCNetAddr& addr, const RCInterval& timeout); + virtual PRStatus GetLocalName(RCNetAddr *addr) const; + virtual PRStatus GetPeerName(RCNetAddr *addr) const; + virtual PRStatus GetSocketOption(PRSocketOptionData *data) const; + virtual PRStatus Listen(PRIntn backlog); + virtual PRInt16 Poll(PRInt16 in_flags, PRInt16 *out_flags); + virtual PRInt32 Read(void *buf, PRSize amount); + virtual PRInt32 Recv( + void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout); + virtual PRInt32 Recvfrom( + void *buf, PRSize amount, PRIntn flags, + RCNetAddr* addr, const RCInterval& timeout); + virtual PRInt32 Send( + const void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout); + virtual PRInt32 Sendto( + const void *buf, PRSize amount, PRIntn flags, + const RCNetAddr& addr, + const RCInterval& timeout); + virtual PRStatus SetSocketOption(const PRSocketOptionData *data); + virtual PRStatus Shutdown(ShutdownHow how); + virtual PRInt32 TransmitFile( + RCIO *source, const void *headers, + PRSize hlen, RCIO::FileDisposition flags, + const RCInterval& timeout); + virtual PRInt32 Write(const void *buf, PRSize amount); + virtual PRInt32 Writev( + const PRIOVec *iov, PRSize size, + const RCInterval& timeout); + +private: + /* functions unavailable to this clients of this class */ + RCNetStreamIO(const RCNetStreamIO&); + + PRStatus Close(); + PRStatus Open(const char *name, PRIntn flags, PRIntn mode); + PRStatus FileInfo(RCFileInfo *info) const; + PRStatus Fsync(); + PRInt64 Seek(PRInt64 offset, RCIO::Whence how); + +public: + RCNetStreamIO(PRIntn protocol); +}; /* RCNetIO */ + +#endif /* defined(_RCNETIO_H) */ + +/* RCNetStreamIO.h */ + + diff --git a/nsprpub/pr/src/cplus/rcthread.cpp b/nsprpub/pr/src/cplus/rcthread.cpp new file mode 100755 index 00000000000..25a9810fecf --- /dev/null +++ b/nsprpub/pr/src/cplus/rcthread.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* RCThread.cpp - C++ wrapper on NSPR */ + +#include "rcthread.h" +#include "rcinrval.h" + +#include +#include +#include +#include + +static RCPrimordialThread *primordial = NULL; + +void nas_Root(void *arg) +{ + RCThread *him = (RCThread*)arg; + while (RCThread::ex_unstarted == him->execution) + (void)PR_Sleep(PR_INTERVAL_NO_TIMEOUT); /* wait for Start() */ + him->RootFunction(); /* he gets a self reference */ + if (PR_UNJOINABLE_THREAD == PR_GetThreadState(him->identity)) + delete him; +} /* nas_Root */ + +RCThread::~RCThread() { } + +RCThread::RCThread(): RCBase() { } + +RCThread::RCThread(const RCThread&): RCBase() +{ + PR_NOT_REACHED("Cannot call thread copy constructor"); +} /* RCThread::RCThread */ + +RCThread::RCThread( + RCThread::Scope scope, RCThread::State join, PRUint32 stackSize): + RCBase() +{ + execution = ex_unstarted; + identity = PR_CreateThread( + PR_USER_THREAD, nas_Root, this, + PR_GetThreadPriority(PR_GetCurrentThread()), + (PRThreadScope)scope, (PRThreadState)join, stackSize); +} /* RCThread::RCThread */ + +void RCThread::operator=(const RCThread&) +{ + PR_NOT_REACHED("Cannot call thread assignment operator"); +} /* RCThread::operator= */ + + +PRStatus RCThread::Start() +{ + PRStatus rv; + /* This is an unsafe check, but not too critical */ + if (RCThread::ex_unstarted == execution) + { + execution = RCThread::ex_started; + rv = PR_Interrupt(identity); + PR_ASSERT(PR_SUCCESS == rv); + } + else + { + rv = PR_FAILURE; + PR_SetError(PR_INVALID_STATE_ERROR, 0); + } + return rv; +} /* RCThread::Start */ + +PRStatus RCThread::Join() +{ + PRStatus rv; + if (RCThread::ex_unstarted == execution) + { + rv = PR_FAILURE; + PR_SetError(PR_INVALID_STATE_ERROR, 0); + } + else rv = PR_JoinThread(identity); + if (PR_SUCCESS == rv) delete this; + return rv; +} /* RCThread::Join */ + +PRStatus RCThread::Interrupt() +{ + PRStatus rv; + if (RCThread::ex_unstarted == execution) + { + rv = PR_FAILURE; + PR_SetError(PR_INVALID_STATE_ERROR, 0); + } + else rv = PR_Interrupt(identity); + return rv; +} /* RCThread::Interrupt */ + +void RCThread::ClearInterrupt() { PR_ClearInterrupt(); } + +void RCThread::SetPriority(RCThread::Priority new_priority) + { PR_SetThreadPriority(identity, (PRThreadPriority)new_priority); } + +PRThread *RCThread::Self() + { return PR_GetCurrentThread(); } + +RCThread::Scope RCThread::GetScope() const + { return (RCThread::Scope)PR_GetThreadScope(identity); } + +RCThread::State RCThread::GetState() const + { return (RCThread::State)PR_GetThreadState(identity); } + +RCThread::Priority RCThread::GetPriority() const + { return (RCThread::Priority)PR_GetThreadPriority(identity); } + +static void _rc_PDDestructor(RCThreadPrivateData* privateData) +{ + PR_ASSERT(NULL != privateData); + privateData->Release(); +} + +static PRThreadPrivateDTOR _tpd_dtor = (PRThreadPrivateDTOR)_rc_PDDestructor; + +PRStatus RCThread::NewPrivateIndex(PRUintn* index) + { return PR_NewThreadPrivateIndex(index, _tpd_dtor); } + +PRStatus RCThread::SetPrivateData(PRUintn index) + { return PR_SetThreadPrivate(index, NULL); } + +PRStatus RCThread::SetPrivateData(PRUintn index, RCThreadPrivateData* data) +{ + return PR_SetThreadPrivate(index, data); +} + +RCThreadPrivateData* RCThread::GetPrivateData(PRUintn index) + { return (RCThreadPrivateData*)PR_GetThreadPrivate(index); } + +PRStatus RCThread::Sleep(const RCInterval& ticks) + { PRIntervalTime tmo = ticks; return PR_Sleep(tmo); } + +RCPrimordialThread *RCThread::WrapPrimordialThread() +{ + /* + ** This needs to take more care in insuring that the thread + ** being wrapped is really the primordial thread. This code + ** is assuming that the caller is the primordial thread, and + ** there's nothing to insure that. + */ + if (NULL == primordial) + { + /* it doesn't have to be perfect */ + RCPrimordialThread *me = new RCPrimordialThread(); + PR_ASSERT(NULL != me); + if (NULL == primordial) + { + primordial = me; + me->execution = RCThread::ex_started; + me->identity = PR_GetCurrentThread(); + } + else delete me; /* somebody beat us to it */ + } + return primordial; +} /* RCThread::WrapPrimordialThread */ + +RCPrimordialThread::RCPrimordialThread(): RCThread() { } + +RCPrimordialThread::~RCPrimordialThread() { } + +void RCPrimordialThread::RootFunction() +{ + PR_NOT_REACHED("Primordial thread calling root function"); +} /* RCPrimordialThread::RootFunction */ + +PRStatus RCPrimordialThread::Cleanup() { return PR_Cleanup(); } + +PRStatus RCPrimordialThread::SetVirtualProcessors(PRIntn count) +{ + PR_SetConcurrency(count); + return PR_SUCCESS; +} /* SetVirutalProcessors */ + +RCThreadPrivateData::RCThreadPrivateData() { } + +RCThreadPrivateData::RCThreadPrivateData( + const RCThreadPrivateData& him) { } + +RCThreadPrivateData::~RCThreadPrivateData() { } + +/* RCThread.c */ + diff --git a/nsprpub/pr/src/cplus/rcthread.h b/nsprpub/pr/src/cplus/rcthread.h new file mode 100644 index 00000000000..2b000564a86 --- /dev/null +++ b/nsprpub/pr/src/cplus/rcthread.h @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* RCThread.h */ + +#if defined(_RCTHREAD_H) +#else +#define _RCTHREAD_H + +#include "rcbase.h" + +#include + +class RCInterval; + +class PR_IMPLEMENT(RCThreadPrivateData) +{ +public: + RCThreadPrivateData(); + RCThreadPrivateData(const RCThreadPrivateData&); + + virtual ~RCThreadPrivateData(); + + virtual void Release() = 0; + +}; /* RCThreadPrivateData */ + +class PR_IMPLEMENT(RCThread): public RCBase +{ +public: + + typedef enum + { + local = PR_LOCAL_THREAD, global = PR_GLOBAL_THREAD + } Scope; + + typedef enum + { + joinable = PR_JOINABLE_THREAD, unjoinable = PR_UNJOINABLE_THREAD + } State; + + typedef enum + { + first = PR_PRIORITY_FIRST, + low = PR_PRIORITY_LOW, + normal = PR_PRIORITY_NORMAL, + high = PR_PRIORITY_HIGH, + urgent = PR_PRIORITY_URGENT, + last = PR_PRIORITY_LAST + } Priority; + + /* + * Create a new thread, providing scope and joinability state. + */ + RCThread(Scope scope, State state, PRUint32 stackSize=0); + + /* + * New threads are created in a suspended state. It must be 'started" + * before it begins execution in the class' defined 'RootFunction()'. + */ + virtual PRStatus Start(); + + /* + * If a thread is created joinable, then the thread's object exists + * until join is called. The thread that calls join will block until + * the target thread returns from it's root function. + */ + virtual PRStatus Join(); + + /* + * The priority of a newly created thread is the same as the creator. + * The priority may be changed either by the new thread itself, by + * the creator or any other arbitrary thread. + */ + virtual void SetPriority(Priority newPriority); + + + /* + * Interrupt another thread, causing it to stop what it + * is doing and return with a well known error code. + */ + virtual PRStatus Interrupt(); + + /* + * And in case a thread was interrupted and didn't get a chance + * to have the notification delivered, a way to cancel the pending + * status. + */ + static void ClearInterrupt(); + + /* + * Methods to discover the attributes of an existing thread. + */ + static PRThread *Self(); + Scope GetScope() const; + State GetState() const; + Priority GetPriority() const; + + /* + * Thread private data + */ + static PRStatus NewPrivateIndex(PRUintn* index); + + /* + * Getting it - if you want to modify, make a copy + */ + static RCThreadPrivateData* GetPrivateData(PRUintn index); + + /* + * Setting it to - deletes existing data + */ + static PRStatus SetPrivateData(PRUintn index); + + /* + * Setting it - runtime will make a copy, freeing old iff necessary + */ + static PRStatus SetPrivateData(PRUintn index, RCThreadPrivateData* data); + + /* + * Scheduling control + */ + static PRStatus Sleep(const RCInterval& ticks); + + friend void nas_Root(void*); + friend class RCPrimordialThread; +protected: + + /* + * The instantiator of a class must not call the destructor. The base + * implementation of Join will, and if the thread is created unjoinable, + * then the code that called the RootFunction will call the desctructor. + */ + virtual ~RCThread(); + +private: + + /* + * This is where a newly created thread begins execution. Returning + * from this function is equivalent to terminating the thread. + */ + virtual void RootFunction() = 0; + + PRThread *identity; + + /* Threads are unstarted until started - pretty startling */ + enum {ex_unstarted, ex_started} execution; + + /* There is no public default constructor or copy constructor */ + RCThread(); + RCThread(const RCThread&); + + /* And there is no assignment operator */ + void operator=(const RCThread&); + +public: + static RCPrimordialThread *WrapPrimordialThread(); + + }; + +/* +** class RCPrimordialThread +*/ +class PR_IMPLEMENT(RCPrimordialThread): public RCThread +{ +public: + /* + ** The primordial thread can (optionally) wait for all created + ** threads to terminate before allowing the process to exit. + ** Not calling Cleanup() before returning from main() will cause + ** the immediate termination of the entire process, including + ** any running threads. + */ + static PRStatus Cleanup(); + + /* + ** Only the primordial thread is allowed to adjust the number of + ** virtual processors of the runtime. It's a lame security thing. + */ + static PRStatus SetVirtualProcessors(PRIntn count=10); + +friend class RCThread; +private: + /* + ** None other than the runtime can create of destruct + ** a primordial thread. It is fabricated by the runtime + ** to wrap the thread that initiated the application. + */ + RCPrimordialThread(); + ~RCPrimordialThread(); + void RootFunction(); +}; /* RCPrimordialThread */ + + #endif /* defined(_RCTHREAD_H) */ diff --git a/nsprpub/pr/src/cplus/rctime.cpp b/nsprpub/pr/src/cplus/rctime.cpp new file mode 100644 index 00000000000..03c6ff325a7 --- /dev/null +++ b/nsprpub/pr/src/cplus/rctime.cpp @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Class implementation for calendar time routines (ref: prtime.h) +*/ + +#include "rctime.h" + +RCTime::~RCTime() { } + +RCTime::RCTime(PRTime time): RCBase() { gmt = time; } +RCTime::RCTime(const RCTime& his): RCBase() { gmt = his.gmt; } +RCTime::RCTime(RCTime::Current): RCBase() { gmt = PR_Now(); } +RCTime::RCTime(const PRExplodedTime& time): RCBase() +{ gmt = PR_ImplodeTime(&time); } + +void RCTime::operator=(const PRExplodedTime& time) +{ gmt = PR_ImplodeTime(&time); } + +RCTime RCTime::operator+(const RCTime& his) +{ RCTime sum(gmt + his.gmt); return sum; } + +RCTime RCTime::operator-(const RCTime& his) +{ RCTime difference(gmt - his.gmt); return difference; } + +RCTime RCTime::operator/(PRUint64 his) +{ RCTime quotient(gmt / gmt); return quotient; } + +RCTime RCTime::operator*(PRUint64 his) +{ RCTime product(gmt * his); return product; } + diff --git a/nsprpub/pr/src/cplus/rctime.h b/nsprpub/pr/src/cplus/rctime.h new file mode 100644 index 00000000000..f0b900a26ba --- /dev/null +++ b/nsprpub/pr/src/cplus/rctime.h @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Class definitions for calendar time routines (ref: prtime.h) +*/ + +#if defined(_RCTIME_H) +#else +#define _RCTIME_H + +#include "rcbase.h" + +#include + +/* +** Class: RCTime (ref: prtime.h) +** +** RCTimes are objects that are intended to be used to represent calendar +** times. They maintain units internally as microseconds since the defined +** epoch (midnight, January 1, 1970, GMT). Conversions to and from external +** formats (PRExplodedTime) are available. +** +** In general, NCTimes possess normal algebretic capabilities. +*/ + +class PR_IMPLEMENT(RCTime): public RCBase +{ +public: + typedef enum {now} Current; + + RCTime(); /* leaves the object unitialized */ + RCTime(Current); /* initializes to current system time */ + RCTime(const RCTime&); /* copy constructor */ + RCTime(const PRExplodedTime&); /* construction from exploded representation */ + + virtual ~RCTime(); + + /* assignment operators */ + void operator=(const RCTime&); + void operator=(const PRExplodedTime&); + + /* comparitive operators */ + PRBool operator<(const RCTime&); + PRBool operator>(const RCTime&); + PRBool operator<=(const RCTime&); + PRBool operator>=(const RCTime&); + PRBool operator==(const RCTime&); + + /* associative operators */ + RCTime operator+(const RCTime&); + RCTime operator-(const RCTime&); + RCTime& operator+=(const RCTime&); + RCTime& operator-=(const RCTime&); + + /* multiply and divide operators */ + RCTime operator/(PRUint64); + RCTime operator*(PRUint64); + RCTime& operator/=(PRUint64); + RCTime& operator*=(PRUint64); + + void Now(); /* assign current time to object */ + +private: + PRTime gmt; + +public: + + RCTime(PRTime); /* construct from raw PRTime */ + void operator=(PRTime); /* assign from raw PRTime */ + operator PRTime() const; /* extract internal representation */ +}; /* RCTime */ + +inline RCTime::RCTime(): RCBase() { } + +inline void RCTime::Now() { gmt = PR_Now(); } +inline RCTime::operator PRTime() const { return gmt; } + +inline void RCTime::operator=(PRTime his) { gmt = his; } +inline void RCTime::operator=(const RCTime& his) { gmt = his.gmt; } + +inline PRBool RCTime::operator<(const RCTime& his) + { return (gmt < his.gmt) ? PR_TRUE : PR_FALSE; } +inline PRBool RCTime::operator>(const RCTime& his) + { return (gmt > his.gmt) ? PR_TRUE : PR_FALSE; } +inline PRBool RCTime::operator<=(const RCTime& his) + { return (gmt <= his.gmt) ? PR_TRUE : PR_FALSE; } +inline PRBool RCTime::operator>=(const RCTime& his) + { return (gmt >= his.gmt) ? PR_TRUE : PR_FALSE; } +inline PRBool RCTime::operator==(const RCTime& his) + { return (gmt == his.gmt) ? PR_TRUE : PR_FALSE; } + +inline RCTime& RCTime::operator+=(const RCTime& his) + { gmt += his.gmt; return *this; } +inline RCTime& RCTime::operator-=(const RCTime& his) + { gmt -= his.gmt; return *this; } +inline RCTime& RCTime::operator/=(PRUint64 his) + { gmt /= his; return *this; } +inline RCTime& RCTime::operator*=(PRUint64 his) + { gmt *= his; return *this; } + +#endif /* defined(_RCTIME_H) */ + +/* RCTime.h */ diff --git a/nsprpub/pr/src/cplus/tests/.cvsignore b/nsprpub/pr/src/cplus/tests/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/cplus/tests/Makefile.in b/nsprpub/pr/src/cplus/tests/Makefile.in new file mode 100644 index 00000000000..1ef206971f4 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/Makefile.in @@ -0,0 +1,288 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CXXSRCS = \ + ranfile.cpp \ + thread.cpp \ + interval.cpp \ + time.cpp \ + fileio.cpp \ + switch.cpp \ + tpd.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CXXSRCS:.cpp=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I.. -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(MOD_MAJOR_VERSION) +LIBPL = -lplc$(MOD_MAJOR_VERSION) + +ifeq ($(OS_ARCH), IRIX) + LDOPTS += -rpath $(PWD)/$(dist_libdir) -rdata_shared + # For 6.x machines, include this flag + 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 + +# Solaris +ifeq ($(OS_ARCH), SunOS) + ifneq ($(OS_RELEASE), 4.1.3_U1) + ifdef NS_USE_GCC + LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) + else + LDOPTS += -R $(PWD)/$(dist_libdir) + 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 +endif # SunOS + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPL = $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -INCREMENTAL:NO + LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPL = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) +endif +endif + +ifeq ($(OS_ARCH),OS2) + ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPLC = $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib + else + LDOPTS += -Zomf -Zlinker /PM:VIO -lstdcpp + endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), HP-UX) + LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) + LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib + ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) + LIBPR = -lnspr$(MOD_MAJOR_VERSION)_shr + LIBPLC = -lplc$(MOD_MAJOR_VERSION)_shr + else + LDOPTS += -brtl + EXTRA_LIBS = -ldl + endif +endif + +ifeq ($(OS_ARCH), Linux) + ifeq ($(OS_RELEASE), 1.2) + EXTRA_LIBS = -ldl + else + LDOPTS += -Xlinker -rpath $(PWD)/$(dist_libdir) + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif + endif +endif + +ifeq ($(OS_ARCH), NCR) +# XXX: We see some strange problems when we link with libnspr.so. +# So for now we use static libraries on NCR. The shared library +# stuff below is commented out. +LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a +LIBPL = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).a +EXTRA_LIBS = -lsocket -lnsl -ldl + +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +#EXTRA_LIBS = -lsocket -lnsl +# 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_libdir) +endif + +ifeq ($(OS_ARCH), SCO_SV) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# 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_libdir) +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPL), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPR) $(LIBPL) wsock32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) $(OS_LIBS) $(EXTRA_LIBS) -o $@ +else + $(CCC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPL) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + diff --git a/nsprpub/pr/src/cplus/tests/fileio.cpp b/nsprpub/pr/src/cplus/tests/fileio.cpp new file mode 100644 index 00000000000..a01ea5eb0e6 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/fileio.cpp @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* fileio.cpp - a test program */ + +#include "rcfileio.h" + +#include +#include + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + RCFileIO fd; + RCFileInfo info; + rv = fd.Open("filio.dat", PR_CREATE_FILE, 0666); + PR_ASSERT(PR_SUCCESS == rv); + rv = fd.FileInfo(&info); + PR_ASSERT(PR_SUCCESS == rv); + rv = fd.Delete("filio.dat"); + PR_ASSERT(PR_SUCCESS == rv); + fd.Close(); + PR_ASSERT(PR_SUCCESS == rv); + + return 0; +} /* main */ + +/* interval.cpp */ + diff --git a/nsprpub/pr/src/cplus/tests/interval.cpp b/nsprpub/pr/src/cplus/tests/interval.cpp new file mode 100644 index 00000000000..1223d67a72e --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/interval.cpp @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* interval.cpp - a test program */ + +#include "rclock.h" +#include "rcthread.h" +#include "rcinrval.h" +#include "rccv.h" + +#include +#include +#include + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + RCLock ml; + PRStatus rv; + RCCondition cv(&ml); + + RCInterval now, timeout, epoch, elapsed; + PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); + PRIntn msecs, seconds, loops, iterations = DEFAULT_ITERATIONS; + + /* slow, agonizing waits */ + for (seconds = 0; seconds < 10; ++seconds) + { + timeout = RCInterval::FromSeconds(seconds); + cv.SetTimeout(timeout); + { + RCEnter lock(&ml); + + epoch.SetToNow(); + + rv = cv.Wait(); + PR_ASSERT(PR_SUCCESS == rv); + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + + PR_fprintf( + output, "Waiting %u seconds took %s%u milliseconds\n", + seconds, ((elapsed < timeout)? "**" : ""), + elapsed.ToMilliseconds()); + } + + /* more slow, agonizing sleeps */ + for (seconds = 0; seconds < 10; ++seconds) + { + timeout = RCInterval::FromSeconds(seconds); + { + epoch.SetToNow(); + + rv = RCThread::Sleep(timeout); + PR_ASSERT(PR_SUCCESS == rv); + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + + PR_fprintf( + output, "Sleeping %u seconds took %s%u milliseconds\n", + seconds, ((elapsed < timeout)? "**" : ""), + elapsed.ToMilliseconds()); + } + + /* fast, spritely little devils */ + for (msecs = 10; msecs < 100; msecs += 10) + { + timeout = RCInterval::FromMilliseconds(msecs); + cv.SetTimeout(timeout); + { + RCEnter lock(&ml); + + epoch.SetToNow(); + + for (loops = 0; loops < iterations; ++loops) + { + rv = cv.Wait(); + PR_ASSERT(PR_SUCCESS == rv); + } + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + elapsed /= iterations; + + PR_fprintf( + output, "Waiting %u msecs took %s%u milliseconds average\n", + msecs, ((elapsed < timeout)? "**" : ""), elapsed.ToMilliseconds()); + } + return 0; +} /* main */ + +/* interval.cpp */ + diff --git a/nsprpub/pr/src/cplus/tests/ranfile.cpp b/nsprpub/pr/src/cplus/tests/ranfile.cpp new file mode 100644 index 00000000000..b745b15c535 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/ranfile.cpp @@ -0,0 +1,432 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Contact: AOF +** +** Name: ranfile.c +** +** Description: Test to hammer on various components of NSPR +** Modification History: +** 20-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include +#include +#include + +#include "rccv.h" +#include "rcthread.h" +#include "rcfileio.h" +#include "rclock.h" + +#include +#include +#include + +static PRFileDesc *output; +static PRIntn debug_mode = 0; +static PRIntn failed_already = 0; + +class HammerData +{ +public: + typedef enum { + sg_go, sg_stop, sg_done} Action; + typedef enum { + sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem; + + virtual ~HammerData(); + HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip); + virtual PRUint32 Random(); + + Action action; + Problem problem; + PRUint32 writes; + RCInterval timein; +friend class Hammer; +private: + RCLock *ml; + RCCondition *cv; + PRUint32 limit; + + PRFloat64 seed; +}; /* HammerData */ + +class Hammer: public HammerData, public RCThread +{ +public: + virtual ~Hammer(); + Hammer(RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip); + +private: + void RootFunction(); + +}; + +static PRInt32 pageSize = 1024; +static const char* baseName = "./"; +static const char *programName = "Random File"; + +/*********************************************************************** +** PRIVATE FUNCTION: Random +** DESCRIPTION: +** Generate a pseudo-random number +** INPUTS: None +** OUTPUTS: None +** RETURN: A pseudo-random unsigned number, 32-bits wide +** SIDE EFFECTS: +** Updates random seed (a static) +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: +** Uses the current interval timer value, promoted to a 64 bit +** float as a multiplier for a static residue (which begins +** as an uninitialized variable). The result is bits [16..48) +** of the product. Seed is then updated with the return value +** promoted to a float-64. +***********************************************************************/ +PRUint32 HammerData::Random() +{ + PRUint32 rv; + PRUint64 shift; + RCInterval now = RCInterval(RCInterval::now); + PRFloat64 random = seed * (PRFloat64)((PRIntervalTime)now); + LL_USHR(shift, *((PRUint64*)&random), 16); + LL_L2UI(rv, shift); + seed = (PRFloat64)rv; + return rv; +} /* HammerData::Random */ + +Hammer::~Hammer() { } + +Hammer::Hammer( + RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip): + HammerData(lock, cond, clip), RCThread(scope, RCThread::joinable, 0) { } + +HammerData::~HammerData() { } + +HammerData::HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip) +{ + ml = lock; + cv = cond; + writes = 0; + limit = clip; + seed = 0x58a9382; + action = HammerData::sg_go; + problem = HammerData::sg_okay; + timein = RCInterval(RCInterval::now); +} /* HammerData::HammerData */ + + +/*********************************************************************** +** PRIVATE FUNCTION: Hammer::RootFunction +** DESCRIPTION: +** Hammer on the file I/O system +** INPUTS: A pointer to the thread's private data +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** Creates, accesses and deletes a file +** RESTRICTIONS: +** (Currently) must have file create permission in "/usr/tmp". +** MEMORY: NA +** ALGORITHM: +** This function is a root of a thread +** 1) Creates a (hopefully) unique file in /usr/tmp/ +** 2) Writes a zero to a random number of sequential pages +** 3) Closes the file +** 4) Reopens the file +** 5) Seeks to a random page within the file +** 6) Writes a one byte on that page +** 7) Repeat steps [5..6] for each page in the file +** 8) Close and delete the file +** 9) Repeat steps [1..8] until told to stop +** 10) Notify complete and return +***********************************************************************/ +void Hammer::RootFunction() +{ + PRUint32 index; + RCFileIO file; + char filename[30]; + const char zero = 0; + PRStatus rv = PR_SUCCESS; + + limit = (Random() % limit) + 1; + + (void)sprintf(filename, "%ssg%04p.dat", baseName, this); + + if (debug_mode) PR_fprintf(output, "Starting work on %s\n", filename); + + while (PR_TRUE) + { + PRUint64 bytes; + PRUint32 minor = (Random() % limit) + 1; + PRUint32 random = (Random() % limit) + 1; + PRUint32 pages = (Random() % limit) + 10; + while (minor-- > 0) + { + problem = sg_okay; + if (action != sg_go) goto finished; + problem = sg_open; + rv = file.Open(filename, PR_RDWR|PR_CREATE_FILE, 0666); + if (PR_FAILURE == rv) goto finished; + for (index = 0; index < pages; index++) + { + problem = sg_okay; + if (action != sg_go) goto close; + problem = sg_seek; + bytes = file.Seek(pageSize * index, RCFileIO::set); + if (bytes != pageSize * index) goto close; + problem = sg_write; + bytes = file.Write(&zero, sizeof(zero)); + if (bytes <= 0) goto close; + writes += 1; + } + problem = sg_close; + rv = file.Close(); + if (rv != PR_SUCCESS) goto purge; + + problem = sg_okay; + if (action != sg_go) goto purge; + + problem = sg_open; + rv = file.Open(filename, PR_RDWR, 0666); + if (PR_FAILURE == rv) goto finished; + for (index = 0; index < pages; index++) + { + problem = sg_okay; + if (action != sg_go) goto close; + problem = sg_seek; + bytes = file.Seek(pageSize * index, RCFileIO::set); + if (bytes != pageSize * index) goto close; + problem = sg_write; + bytes = file.Write(&zero, sizeof(zero)); + if (bytes <= 0) goto close; + writes += 1; + random = (random + 511) % pages; + } + problem = sg_close; + rv = file.Close(); + if (rv != PR_SUCCESS) goto purge; + problem = sg_delete; + rv = file.Delete(filename); + if (rv != PR_SUCCESS) goto finished; + } + } + +close: + (void)file.Close(); +purge: + (void)file.Delete(filename); +finished: + RCEnter scope(ml); + action = HammerData::sg_done; + cv->Notify(); + + if (debug_mode) PR_fprintf(output, "Ending work on %s\n", filename); + + return; +} /* Hammer::RootFunction */ + +static Hammer* hammer[100]; +/*********************************************************************** +** PRIVATE FUNCTION: main +** DESCRIPTION: +** Hammer on the file I/O system +** INPUTS: The usual argc and argv +** argv[0] - program name (not used) +** argv[1] - the number of virtual_procs to execute the major loop +** argv[2] - the number of threads to toss into the batch +** argv[3] - the clipping number applied to randoms +** default values: max_virtual_procs = 2, threads = 10, limit = 57 +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** Creates, accesses and deletes lots of files +** RESTRICTIONS: +** (Currently) must have file create permission in "/usr/tmp". +** MEMORY: NA +** ALGORITHM: +** 1) Fork a "Thread()" +** 2) Wait for 'interleave' seconds +** 3) For [0..'threads') repeat [1..2] +** 4) Mark all objects to stop +** 5) Collect the threads, accumulating the results +** 6) For [0..'max_virtual_procs') repeat [1..5] +** 7) Print accumulated results and exit +** +** Characteristic output (from IRIX) +** Random File: Using max_virtual_procs = 2, threads = 10, limit = 57 +** Random File: [min [avg] max] writes/sec average +***********************************************************************/ +PRIntn main (PRIntn argc, char *argv[]) +{ + RCLock ml; + PLOptStatus os; + RCCondition cv(&ml); + PRUint32 writesMax = 0, durationTot = 0; + RCThread::Scope thread_scope = RCThread::local; + PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0; + PRIntn active, poll, limit = 0, max_virtual_procs = 0, threads = 0, virtual_procs; + RCInterval interleave(RCInterval::FromMilliseconds(10000)), duration(0); + + const char *where[] = {"okay", "open", "close", "delete", "write", "seek"}; + + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + baseName = opt->value; + break; + case 'G': /* global threads */ + thread_scope = RCThread::global; + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'l': /* limiting number */ + limit = atoi(opt->value); + break; + case 't': /* number of threads */ + threads = atoi(opt->value); + break; + case 'i': /* iteration counter */ + max_virtual_procs = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + output = PR_GetSpecialFD(PR_StandardOutput); + + /* main test */ + + cv.SetTimeout(interleave); + + if (max_virtual_procs == 0) max_virtual_procs = 2; + if (limit == 0) limit = 57; + if (threads == 0) threads = 10; + + if (debug_mode) PR_fprintf(output, + "%s: Using %d virtual processors, %d threads, limit = %d and %s threads\n", + programName, max_virtual_procs, threads, limit, + (thread_scope == RCThread::local) ? "LOCAL" : "GLOBAL"); + + for (virtual_procs = 0; virtual_procs < max_virtual_procs; ++virtual_procs) + { + if (debug_mode) + PR_fprintf(output, + "%s: Setting number of virtual processors to %d\n", + programName, virtual_procs + 1); + RCPrimordialThread::SetVirtualProcessors(virtual_procs + 1); + for (active = 0; active < threads; active++) + { + hammer[active] = new Hammer(thread_scope, &ml, &cv, limit); + hammer[active]->Start(); /* then make it roll */ + RCThread::Sleep(interleave); /* start them slowly */ + } + + /* + * The last thread started has had the opportunity to run for + * 'interleave' seconds. Now gather them all back in. + */ + { + RCEnter scope(&ml); + for (poll = 0; poll < threads; poll++) + { + if (hammer[poll]->action == HammerData::sg_go) /* don't overwrite done */ + hammer[poll]->action = HammerData::sg_stop; /* ask him to stop */ + } + } + + while (active > 0) + { + for (poll = 0; poll < threads; poll++) + { + ml.Acquire(); + while (hammer[poll]->action < HammerData::sg_done) cv.Wait(); + ml.Release(); + + if (hammer[poll]->problem == HammerData::sg_okay) + { + duration = RCInterval(RCInterval::now) - hammer[poll]->timein; + writes = hammer[poll]->writes * 1000 / duration; + if (writes < writesMin) writesMin = writes; + if (writes > writesMax) writesMax = writes; + writesTot += hammer[poll]->writes; + durationTot += duration; + } + else + { + if (debug_mode) PR_fprintf(output, + "%s: test failed %s after %ld seconds\n", + programName, where[hammer[poll]->problem], duration); + else failed_already=1; + } + active -= 1; /* this is another one down */ + (void)hammer[poll]->Join(); + hammer[poll] = NULL; + } + } + if (debug_mode) PR_fprintf(output, + "%s: [%ld [%ld] %ld] writes/sec average\n", + programName, writesMin, + writesTot * 1000 / durationTot, writesMax); + } + + failed_already |= (PR_FAILURE == RCPrimordialThread::Cleanup()); + PR_fprintf(output, "%s\n", (failed_already) ? "FAIL\n" : "PASS\n"); + return failed_already; +} /* main */ diff --git a/nsprpub/pr/src/cplus/tests/switch.cpp b/nsprpub/pr/src/cplus/tests/switch.cpp new file mode 100644 index 00000000000..fddc580803c --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/switch.cpp @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: switch.cpp +** Description: trying to time context switches +*/ + +#include "rccv.h" +#include "rcinrval.h" +#include "rclock.h" +#include "rcthread.h" + +#include +#include +#include +#include +#include + +#include + +#define INNER_LOOPS 100 +#define DEFAULT_LOOPS 100 +#define DEFAULT_THREADS 10 + +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE; + +class Home: public RCCondition +{ +public: + virtual ~Home(); + Home(Home *link, RCLock* ml); + +public: + Home *next; + RCLock* ml; + PRBool twiddle; +}; /* Home */ + +Home::~Home() { } + +Home::Home(Home *link, RCLock* lock): RCCondition(lock) +{ + ml = lock; + next = link; + twiddle = PR_FALSE; +} /* Home::Home */ + +class Shared: public Home, public RCThread +{ +public: + Shared(RCThread::Scope scope, Home* link, RCLock* ml); + +private: + ~Shared(); + void RootFunction(); +}; /* Shared */ + +Shared::Shared(RCThread::Scope scope, Home* link, RCLock* lock): + Home(link, lock), RCThread(scope, RCThread::joinable) { } + +Shared::~Shared() { } + +void Shared::RootFunction() +{ + PRStatus status = PR_SUCCESS; + while (PR_SUCCESS == status) + { + RCEnter entry(ml); + while (twiddle && (PR_SUCCESS == status)) status = Wait(); + if (verbosity) PR_fprintf(debug_out, "+"); + twiddle = PR_TRUE; + next->twiddle = PR_FALSE; + next->Notify(); + } +} /* Shared::RootFunction */ + +static void Help(void) +{ + debug_out = PR_STDOUT; + + PR_fprintf( + debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\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, "-C n\tconcurrency setting (default: 1)\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRStatus status; + PRBool help = PR_FALSE; + PRUintn concurrency = 1; + RCThread::Scope thread_scope = RCThread::local; + PRUintn thread_count, inner_count, loop_count, average; + PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G"); + 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 */ + loop_limit = atoi(opt->value); + break; + case 't': /* thread limit */ + thread_limit = atoi(opt->value); + break; + case 'C': /* Concurrency limit */ + concurrency = atoi(opt->value); + break; + case 'G': /* global threads only */ + thread_scope = RCThread::global; + break; + case 'h': /* help message */ + Help(); + help = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (help) return -1; + + if (PR_TRUE == debug_mode) + { + debug_out = PR_STDOUT; + PR_fprintf(debug_out, "Test parameters\n"); + PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit); + PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit); + PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); + PR_fprintf( + debug_out, "\tThread type: %s\n", + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); + } + + /* + ** The interesting part starts here + */ + RCLock lock; + Shared* shared; + Home home(NULL, &lock); + Home* link = &home; + RCInterval timein, timeout = 0; + + /* Build up the string of objects */ + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + shared = new Shared(thread_scope, link, &lock); + shared->Start(); /* make it run */ + link = (Home*)shared; + } + + /* Pass the message around the horn a few times */ + for (loop_count = 1; loop_count <= loop_limit; ++loop_count) + { + timein.SetToNow(); + for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) + { + RCEnter entry(&lock); + home.twiddle = PR_TRUE; + shared->twiddle = PR_FALSE; + shared->Notify(); + while (home.twiddle) + { + failed = (PR_FAILURE == home.Wait()) ? PR_TRUE : PR_FALSE; + } + } + timeout += (RCInterval(RCInterval::now) - timein); + } + + /* Figure out how well we did */ + if (debug_mode) + { + average = timeout.ToMicroseconds() + / (INNER_LOOPS * loop_limit * thread_count); + PR_fprintf( + debug_out, "Average switch times %d usecs for %d threads\n", + average, thread_limit); + } + + /* Start reclamation process */ + link = shared; + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + if (&home == link) break; + status = ((Shared*)link)->Interrupt(); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to interrupt"); + } + link = link->next; + } + + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + link = shared->next; + status = shared->Join(); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to join"); + } + if (&home == link) break; + shared = (Shared*)link; + } + + PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); + + failed |= (PR_SUCCESS == RCPrimordialThread::Cleanup()); + + return ((failed) ? 1 : 0); +} /* main */ + +/* switch.c */ diff --git a/nsprpub/pr/src/cplus/tests/thread.cpp b/nsprpub/pr/src/cplus/tests/thread.cpp new file mode 100644 index 00000000000..801eee0da72 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/thread.cpp @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* thread.cpp - a test program */ + +#include "rcthread.h" + +#include + +#include + +class TestThread: public RCThread +{ +public: + TestThread(RCThread::State state, PRIntn count); + + virtual void RootFunction(); + +protected: + virtual ~TestThread(); + +private: + PRUint32 mydata; +}; + +TestThread::~TestThread() { } + +TestThread::TestThread(RCThread::State state, PRIntn count): + RCThread(RCThread::global, state, 0) { mydata = count; } + +void TestThread::RootFunction() +{ + SetPriority(RCThread::high); + printf("TestThread::RootFunction %d did it\n", mydata); +} /* TestThread::RootFunction */ + +class Foo1 +{ +public: + Foo1(); + virtual ~Foo1(); + + TestThread *thread; + PRIntn data; +}; + +Foo1::Foo1() +{ + data = 0xafaf; + thread = new TestThread(RCThread::joinable, 0xafaf); + thread->Start(); +} + +Foo1::~Foo1() +{ + PRStatus rv = thread->Join(); + PR_ASSERT(PR_SUCCESS == rv); +} /* Foo1::~Foo1 */ + +PRIntn main(PRIntn argc, char **agrv) +{ + PRStatus status; + PRIntn count = 100; + RCThread *thread[10]; + while (--count > 0) + { + TestThread *thread = new TestThread(RCThread::joinable, count); + status = thread->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + status = thread->Join(); /* this should work */ + PR_ASSERT(PR_SUCCESS == status); + } + while (++count < 100) + { + TestThread *thread = new TestThread(RCThread::unjoinable, count); + status = thread->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + } + + { + Foo1 *foo1 = new Foo1(); + PR_ASSERT(NULL != foo1); + delete foo1; + } + + { + for (count = 0; count < 10; ++count) + { + thread[count] = new TestThread( RCThread::joinable, count); + status = thread[count]->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + } + for (count = 0; count < 10; ++count) + { + PRStatus rv = thread[count]->Join(); + PR_ASSERT(PR_SUCCESS == rv); + } + } + + (void)RCPrimordialThread::Cleanup(); + + return 0; +} /* main */ + +/* thread.cpp */ + diff --git a/nsprpub/pr/src/cplus/tests/time.cpp b/nsprpub/pr/src/cplus/tests/time.cpp new file mode 100644 index 00000000000..c0a9c3e86fd --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/time.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* time.cpp - a test program */ + +#include "rctime.h" + +#include +#include + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + RCTime unitialized; + RCTime now(PR_Now()); + RCTime current(RCTime::now); + PRTime time = current; + + unitialized = now; + now.Now(); + + return 0; +} /* main */ + +/* time.cpp */ + diff --git a/nsprpub/pr/src/cplus/tests/tpd.cpp b/nsprpub/pr/src/cplus/tests/tpd.cpp new file mode 100644 index 00000000000..6e3dd95366c --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/tpd.cpp @@ -0,0 +1,368 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: tpd.cpp +** Description: Exercising the thread private data bailywick. +*/ + +#include "prlog.h" +#include "prprf.h" +#include "rcthread.h" + +#include + +#include "plgetopt.h" + +/* +** class MyThread +*/ +class MyThread: public RCThread +{ +public: + MyThread(); + +private: + ~MyThread(); + void RootFunction(); +}; /* MyThread */ + +/* +** class MyPrivateData +*/ +class MyPrivateData: public RCThreadPrivateData +{ +public: + virtual ~MyPrivateData(); + + MyPrivateData(); + MyPrivateData(char*); + MyPrivateData(const MyPrivateData&); + + void Release(); + +private: + char *string; +}; /* MyPrivateData */ + +static PRUintn key[128]; +static PRIntn debug = 0; +static PRBool failed = PR_FALSE; +static PRBool should = PR_TRUE; +static PRBool did = PR_TRUE; +static PRFileDesc *fout = NULL; + +static void PrintProgress(PRIntn line) +{ + failed = failed || (should && !did); + failed = failed || (!should && did); + if (debug > 0) + { + PR_fprintf( + fout, "@ line %d destructor should %shave been called and was%s\n", + line, ((should) ? "" : "NOT "), ((did) ? "" : " NOT")); + } +} /* PrintProgress */ + +static void MyAssert(const char *expr, const char *file, PRIntn line) +{ + if (debug > 0) + (void)PR_fprintf(fout, "'%s' in file: %s: %d\n", expr, file, line); +} /* MyAssert */ + +#define MY_ASSERT(_expr) \ + ((_expr)?((void)0):MyAssert(# _expr,__FILE__,__LINE__)) + +int main(PRIntn argc, char *argv[]) +{ + PRStatus rv; + PRUintn keys; + MyThread *thread; + const RCThreadPrivateData *pd; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + RCThread *primordial = RCThread::WrapPrimordialThread(); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + fout = PR_STDOUT; + + MyPrivateData extension = MyPrivateData("EXTENSION"); + MyPrivateData key_string[] = { + "Key #0", "Key #1", "Key #2", "Key #3", + "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; + + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = RCThread::NewPrivateIndex(&key[keys]); + key[keys + 4] = key[keys] + 4; + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* the first four should be bu null, the last four undefined and null */ + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + /* initially set private data for new keys */ + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = RCThread::SetPrivateData(key[keys], &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* re-assign the private data, albeit the same content */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + PR_ASSERT(NULL != pd); + rv = RCThread::SetPrivateData(key[keys], &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set private to */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* should all be null now */ + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + PR_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + /* allocate another batch of keys and assign data to them */ + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::NewPrivateIndex(&key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + rv = RCThread::SetPrivateData(key[keys], &extension); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set all the extended slots to */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set all the extended slots to again (noop) */ + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + + if (debug) PR_fprintf(fout, "Creating thread\n"); + thread = new MyThread(); + if (debug) PR_fprintf(fout, "Starting thread\n"); + thread->Start(); + if (debug) PR_fprintf(fout, "Joining thread\n"); + (void)thread->Join(); + if (debug) PR_fprintf(fout, "Joined thread\n"); + + failed |= (PR_FAILURE == RCPrimordialThread::Cleanup()); + + (void)PR_fprintf( + fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); + + return (failed) ? 1 : 0; + +} /* main */ + +/* +** class MyPrivateData +*/ +MyPrivateData::~MyPrivateData() +{ + PR_fprintf( + fout, "MyPrivateData::~MyPrivateData[%s]\n", + (NULL != string) ? string : "NULL"); +} /* MyPrivateData::~MyPrivateData */ + +MyPrivateData::MyPrivateData(): RCThreadPrivateData() +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData()\n"); + string = NULL; +} /* MyPrivateData::MyPrivateData */ + +MyPrivateData::MyPrivateData(char* data): RCThreadPrivateData() +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData(char* data)\n"); + string = data; +} /* MyPrivateData:: MyPrivateData */ + +MyPrivateData::MyPrivateData(const MyPrivateData& him): RCThreadPrivateData(him) +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData(const MyPrivateData& him)\n"); + string = him.string; +} /* MyPrivateData:: MyPrivateData */ + +void MyPrivateData::Release() +{ + if (should) did = PR_TRUE; + else failed = PR_TRUE; +} /* MyPrivateData::operator= */ + +/* +** class MyThread +*/ +MyThread::~MyThread() { } +MyThread::MyThread(): RCThread(RCThread::global, RCThread::joinable) { } + + +void MyThread::RootFunction() +{ + PRStatus rv; + PRUintn keys; + const RCThreadPrivateData *pd; + + MyPrivateData extension = MyPrivateData("EXTENSION"); + MyPrivateData key_string[] = { + "Key #0", "Key #1", "Key #2", "Key #3", + "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; + + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = GetPrivateData(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(keys, &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + +#if !defined(DEBUG) + did = should = PR_FALSE; + for (keys = 4; keys < 8; ++keys) + { + rv = SetPrivateData(keys, &key_string[keys]); + MY_ASSERT(PR_FAILURE == rv); + } + PrintProgress(__LINE__); +#endif + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(key[keys], &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys], &extension); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } +} /* MyThread::RootFunction */ + +/* tpd.c */ diff --git a/nsprpub/pr/src/io/.cvsignore b/nsprpub/pr/src/io/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/io/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/io/Makefile.in b/nsprpub/pr/src/io/Makefile.in new file mode 100644 index 00000000000..40dc6dedf42 --- /dev/null +++ b/nsprpub/pr/src/io/Makefile.in @@ -0,0 +1,97 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +CSRCS = \ + prfdcach.c \ + prmwait.c \ + priometh.c \ + pripv6.c \ + prmapopt.c \ + prlayer.c \ + prlog.c \ + prmmap.c \ + prpolevt.c \ + prprf.c \ + prscanf.c \ + prstdio.c \ + $(NULL) + +ifndef USE_PTHREADS + CSRCS += \ + prdir.c \ + prfile.c \ + prio.c \ + prsocket.c \ + $(NULL) +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +# An OS/2 Optimization bug causes PR_snprintf() to produce wrong result. +# This suppresses optimization for this single compilation unit. +ifeq ($(MOZ_OS2_TOOLS),VACPP) +$(OBJDIR)/prprf.obj: prprf.c + @$(MAKE_OBJDIR) + $(CC) -Fo$@ -c $(filter-out /O+, $(CFLAGS)) $< +endif + +export:: $(TARGETS) + diff --git a/nsprpub/pr/src/io/prdir.c b/nsprpub/pr/src/io/prdir.c new file mode 100644 index 00000000000..8679c9d5284 --- /dev/null +++ b/nsprpub/pr/src/io/prdir.c @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Roy Yokoyama + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name) +{ + PRDir *dir; + PRStatus sts; + + dir = PR_NEW(PRDir); + if (dir) { + sts = _PR_MD_OPEN_DIR(&dir->md,name); + if (sts != PR_SUCCESS) { + PR_DELETE(dir); + return NULL; + } + } else { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return dir; +} + +PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags) +{ + /* _MD_READ_DIR return a char* to the name; allocation in machine-dependent code */ + char* name = _PR_MD_READ_DIR(&dir->md, flags); + dir->d.name = name; + return name ? &dir->d : NULL; +} + +PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir) +{ +PRInt32 rv; + + if (dir) { + rv = _PR_MD_CLOSE_DIR(&dir->md); + PR_DELETE(dir); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode) +{ +PRInt32 rv; + + rv = _PR_MD_MKDIR(name, mode); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode) +{ +PRInt32 rv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_MAKE_DIR(name, mode); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name) +{ +PRInt32 rv; + + rv = _PR_MD_RMDIR(name); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +#ifdef MOZ_UNICODE +/* + * UTF16 Interface + */ +PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name) +{ + PRDirUTF16 *dir; + PRStatus sts; + + dir = PR_NEW(PRDirUTF16); + if (dir) { + sts = _PR_MD_OPEN_DIR_UTF16(&dir->md,name); + if (sts != PR_SUCCESS) { + PR_DELETE(dir); + return NULL; + } + } else { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return dir; +} + +PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags) +{ + /* + * _MD_READ_DIR_UTF16 return a PRUnichar* to the name; allocation in + * machine-dependent code + */ + PRUnichar* name = _PR_MD_READ_DIR_UTF16(&dir->md, flags); + dir->d.name = name; + return name ? &dir->d : NULL; +} + +PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir) +{ + PRInt32 rv; + + if (dir) { + rv = _PR_MD_CLOSE_DIR_UTF16(&dir->md); + PR_DELETE(dir); + if (rv < 0) + return PR_FAILURE; + else + return PR_SUCCESS; + } + return PR_SUCCESS; +} + +#endif /* MOZ_UNICODE */ diff --git a/nsprpub/pr/src/io/prfdcach.c b/nsprpub/pr/src/io/prfdcach.c new file mode 100644 index 00000000000..9654529f6f3 --- /dev/null +++ b/nsprpub/pr/src/io/prfdcach.c @@ -0,0 +1,324 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +/*****************************************************************************/ +/*****************************************************************************/ +/************************** 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(void) +{ + 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_faulty_methods == fd->methods); + PR_ASSERT(PR_INVALID_IO_LAYER == fd->identity); + 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 (!_pr_initialized) _PR_ImplicitInitialization(); + + 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; + PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher)); + } + _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_stack = (0 == _pr_fd_cache.limit_high); + _pr_fd_cache.limit_low = low; + _pr_fd_cache.limit_high = high; + if (was_using_stack) /* was using stack - feed into cache */ + { + PRStackElem *pop; + while (NULL != (pop = PR_StackPop(_pr_fd_cache.stack))) + { + PRFileDesc *fd = (PRFileDesc*) + ((PRPtrdiff)pop - (PRPtrdiff)stack2fd); + if (NULL == _pr_fd_cache.tail) _pr_fd_cache.tail = fd; + fd->higher = _pr_fd_cache.head; + _pr_fd_cache.head = fd; + _pr_fd_cache.count += 1; + } + } + } + PR_Unlock(_pr_fd_cache.ml); + return PR_SUCCESS; +} /* PR_SetFDCacheSize */ + +void _PR_InitFdCache(void) +{ + /* + ** 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"); + + /* + ** _low is allowed to be zero, _high is not. + ** If _high is zero, we're not doing the caching. + */ + + _pr_fd_cache.limit_low = 0; +#if defined(DEBUG) + _pr_fd_cache.limit_high = FD_SETSIZE; +#else + _pr_fd_cache.limit_high = 0; +#endif /* defined(DEBUG) */ + + if (NULL != low) _pr_fd_cache.limit_low = atoi(low); + if (NULL != high) _pr_fd_cache.limit_high = atoi(high); + + if (_pr_fd_cache.limit_low < 0) + _pr_fd_cache.limit_low = 0; + if (_pr_fd_cache.limit_low > FD_SETSIZE) + _pr_fd_cache.limit_low = FD_SETSIZE; + + if (_pr_fd_cache.limit_high > FD_SETSIZE) + _pr_fd_cache.limit_high = FD_SETSIZE; + + 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_fd_cache.head = NULL; + _pr_fd_cache.tail = NULL; + _pr_fd_cache.count = 0; + PR_DestroyLock(_pr_fd_cache.ml); + _pr_fd_cache.ml = NULL; + 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_fd_cache.stack = NULL; +} /* _PR_CleanupFdCache */ + +/* prfdcach.c */ diff --git a/nsprpub/pr/src/io/prfile.c b/nsprpub/pr/src/io/prfile.c new file mode 100644 index 00000000000..545fa712f7b --- /dev/null +++ b/nsprpub/pr/src/io/prfile.c @@ -0,0 +1,845 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include + +#ifdef XP_UNIX +#if defined(AIX) || defined(QNX) +/* To pick up sysconf */ +#include +#else +/* To pick up getrlimit, setrlimit */ +#include +#include +#endif +#endif /* XP_UNIX */ + +extern PRLock *_pr_flock_lock; +extern PRCondVar *_pr_flock_cv; + +static PRInt32 PR_CALLBACK FileRead(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + 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); + rv = -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + rv = -1; + } + if (rv == -1) + return rv; + + rv = _PR_MD_READ(fd, buf, amount); + if (rv < 0) { + PR_ASSERT(rv == -1); + } + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("read -> %d", rv)); + return rv; +} + +static PRInt32 PR_CALLBACK FileWrite(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + PRInt32 rv = 0; + PRInt32 temp, count; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + rv = -1; + } + if (rv != 0) + return rv; + + count = 0; +#if !defined(_PR_HAVE_O_APPEND) /* Bugzilla: 4090, 276330 */ + if (fd->secret->appendMode) { + if (PR_Seek64(fd, 0, PR_SEEK_END) == -1) { + return -1; + } + } /* if (fd->secret->appendMode...) */ +#endif /* _PR_HAVE_O_APPEND */ + while (amount > 0) { + temp = _PR_MD_WRITE(fd, buf, amount); + if (temp < 0) { + count = -1; + break; + } + count += temp; + if (fd->secret->nonblocking) { + break; + } + buf = (const void*) ((const char*)buf + temp); + amount -= temp; + } + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("write -> %d", count)); + return count; +} + +static PROffset32 PR_CALLBACK FileSeek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) +{ + PROffset32 result; + + result = _PR_MD_LSEEK(fd, offset, whence); + return result; +} + +static PROffset64 PR_CALLBACK FileSeek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) +{ +#ifdef XP_MAC +#pragma unused( fd, offset, whence ) +#endif + PROffset64 result; + + result = _PR_MD_LSEEK64(fd, offset, whence); + return result; +} + +static PRInt32 PR_CALLBACK FileAvailable(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; +} + +static PRInt64 PR_CALLBACK FileAvailable64(PRFileDesc *fd) +{ +#ifdef XP_MAC +#pragma unused( fd ) +#endif + 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; +} + +static PRInt32 PR_CALLBACK PipeAvailable(PRFileDesc *fd) +{ + PRInt32 rv; + rv = _PR_MD_PIPEAVAILABLE(fd); + return rv; +} + +static PRInt64 PR_CALLBACK PipeAvailable64(PRFileDesc *fd) +{ + PRInt64 rv; + LL_I2L(rv, _PR_MD_PIPEAVAILABLE(fd)); + return rv; +} + +static PRStatus PR_CALLBACK PipeSync(PRFileDesc *fd) +{ +#if defined(XP_MAC) +#pragma unused (fd) +#endif + + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK FileGetInfo(PRFileDesc *fd, PRFileInfo *info) +{ + PRInt32 rv; + + rv = _PR_MD_GETOPENFILEINFO(fd, info); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK FileGetInfo64(PRFileDesc *fd, PRFileInfo64 *info) +{ +#ifdef XP_MAC +#pragma unused( fd, info ) +#endif + /* $$$$ NOT YET IMPLEMENTED */ + PRInt32 rv; + + rv = _PR_MD_GETOPENFILEINFO64(fd, info); + if (rv < 0) return PR_FAILURE; + else return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK FileSync(PRFileDesc *fd) +{ + PRInt32 result; + result = _PR_MD_FSYNC(fd); + if (result < 0) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK FileClose(PRFileDesc *fd) +{ + 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; + } + + 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( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ +#ifdef XP_MAC +#pragma unused( fd, in_flags ) +#endif + *out_flags = 0; + return in_flags; +} /* FilePoll */ + +static PRIOMethods _pr_fileMethods = { + PR_DESC_FILE, + FileClose, + FileRead, + FileWrite, + FileAvailable, + FileAvailable64, + FileSync, + FileSeek, + FileSeek64, + FileGetInfo, + FileGetInfo64, + (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, + FilePoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void) +{ + return &_pr_fileMethods; +} + +static PRIOMethods _pr_pipeMethods = { + PR_DESC_PIPE, + FileClose, + FileRead, + FileWrite, + PipeAvailable, + PipeAvailable64, + PipeSync, + (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, + FilePoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void) +{ + return &_pr_pipeMethods; +} + +PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode) +{ + PROsfd osfd; + PRFileDesc *fd = 0; +#if !defined(_PR_HAVE_O_APPEND) + PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* Map pr open flags and mode to os specific flags */ + + osfd = _PR_MD_OPEN(name, flags, mode); + if (osfd != -1) { + fd = PR_AllocFileDesc(osfd, &_pr_fileMethods); + if (!fd) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { +#if !defined(_PR_HAVE_O_APPEND) + fd->secret->appendMode = appendMode; +#endif + _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); + } + } + return fd; +} + +PR_IMPLEMENT(PRFileDesc*) PR_OpenFile( + const char *name, PRIntn flags, PRIntn mode) +{ + PROsfd osfd; + PRFileDesc *fd = 0; +#if !defined(_PR_HAVE_O_APPEND) + PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* Map pr open flags and mode to os specific flags */ + + osfd = _PR_MD_OPEN_FILE(name, flags, mode); + if (osfd != -1) { + fd = PR_AllocFileDesc(osfd, &_pr_fileMethods); + if (!fd) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { +#if !defined(_PR_HAVE_O_APPEND) + fd->secret->appendMode = appendMode; +#endif + _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); + } + } + return fd; +} + +PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void) +{ +#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX) + struct rlimit rlim; + + if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) { + /* XXX need to call PR_SetError() */ + return -1; + } + + return rlim.rlim_max; +#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX) + return sysconf(_SC_OPEN_MAX); +#elif defined(WIN32) + /* + * There is a systemwide limit of 65536 user handles. + */ + return 16384; +#elif defined (WIN16) + return FOPEN_MAX; +#elif defined(XP_OS2) + ULONG ulReqCount = 0; + ULONG ulCurMaxFH = 0; + DosSetRelMaxFH(&ulReqCount, &ulCurMaxFH); + return ulCurMaxFH; +#elif defined (XP_MAC) || defined(XP_BEOS) + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +#else + write me; +#endif +} + +PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(int table_size) +{ +#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX) + struct rlimit rlim; + PRInt32 tableMax = PR_GetSysfdTableMax(); + + if (tableMax < 0) + return -1; + + if (tableMax > FD_SETSIZE) + tableMax = FD_SETSIZE; + + rlim.rlim_max = tableMax; + + /* Grow as much as we can; even if too big */ + if ( rlim.rlim_max < table_size ) + rlim.rlim_cur = rlim.rlim_max; + else + rlim.rlim_cur = table_size; + + if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) { + /* XXX need to call PR_SetError() */ + return -1; + } + + return rlim.rlim_cur; +#elif defined(XP_OS2) + PRInt32 tableMax = PR_GetSysfdTableMax(); + if (table_size > tableMax) { + APIRET rc = NO_ERROR; + rc = DosSetMaxFH(table_size); + if (rc == NO_ERROR) + return table_size; + else + return -1; + } + return tableMax; +#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX) \ + || defined(WIN32) || defined(WIN16) || defined(XP_BEOS) + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +#elif defined (XP_MAC) +#pragma unused (table_size) + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +#else + write me; +#endif +} + +PR_IMPLEMENT(PRStatus) PR_Delete(const char *name) +{ + PRInt32 rv; + + rv = _PR_MD_DELETE(name); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info) +{ + PRInt32 rv; + + rv = _PR_MD_GETFILEINFO(fn, info); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info) +{ +#ifdef XP_MAC +#pragma unused (fn, info) +#endif + PRInt32 rv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_GETFILEINFO64(fn, info); + if (rv < 0) { + return PR_FAILURE; + } else { + return PR_SUCCESS; + } +} + +PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to) +{ + PRInt32 rv; + + rv = _PR_MD_RENAME(from, to); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how) +{ +PRInt32 rv; + + rv = _PR_MD_ACCESS(name, how); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +/* +** Import an existing OS file to NSPR +*/ +PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PROsfd osfd) +{ + PRFileDesc *fd = NULL; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + fd = PR_AllocFileDesc(osfd, &_pr_fileMethods); + if( !fd ) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { + _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); + } + + return fd; +} + +/* +** Import an existing OS pipe to NSPR +*/ +PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PROsfd osfd) +{ + PRFileDesc *fd = NULL; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + fd = PR_AllocFileDesc(osfd, &_pr_pipeMethods); + if( !fd ) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { + _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); +#ifdef WINNT + fd->secret->md.sync_file_io = PR_TRUE; +#endif + } + + return fd; +} + +#ifndef NO_NSPR_10_SUPPORT +/* +** PR_Stat() for Win16 is defined in w16io.c +** it is a hack to circumvent problems in Gromit and Java +** See also: BugSplat: 98516. +*/ +#if !defined(WIN16) +/* + * This function is supposed to be for backward compatibility with + * nspr 1.0. Therefore, it still uses the nspr 1.0 error-reporting + * mechanism -- returns a PRInt32, which is the error code when the call + * fails. + * + * If we need this function in nspr 2.0, it should be changed to + * return PRStatus, as follows: + * + * PR_IMPLEMENT(PRStatus) PR_Stat(const char *name, struct stat *buf) + * { + * PRInt32 rv; + * + * rv = _PR_MD_STAT(name, buf); + * if (rv < 0) + * return PR_FAILURE; + * else + * return PR_SUCCESS; + * } + * + * -- wtc, 2/14/97. + */ +PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf) +{ + PRInt32 rv; + + rv = _PR_MD_STAT(name, buf); + return rv; +} + +#endif /* !defined(WIN16) */ +#endif /* ! NO_NSPR_10_SUPPORT */ + +PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + +#ifdef WINNT + if (!fd->secret->md.io_model_committed) { + PRInt32 rv; + rv = _md_Associate((HANDLE)fd->secret->md.osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } +#endif + + PR_Lock(_pr_flock_lock); + while (fd->secret->lockCount == -1) + PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT); + if (fd->secret->lockCount == 0) { + fd->secret->lockCount = -1; + PR_Unlock(_pr_flock_lock); + status = _PR_MD_LOCKFILE(fd->secret->md.osfd); + PR_Lock(_pr_flock_lock); + fd->secret->lockCount = (status == PR_SUCCESS) ? 1 : 0; + PR_NotifyAllCondVar(_pr_flock_cv); + } else { + fd->secret->lockCount++; + } + PR_Unlock(_pr_flock_lock); + + return status; +} + +PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + +#ifdef WINNT + if (!fd->secret->md.io_model_committed) { + PRInt32 rv; + rv = _md_Associate((HANDLE)fd->secret->md.osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } +#endif + + PR_Lock(_pr_flock_lock); + if (fd->secret->lockCount == 0) { + status = _PR_MD_TLOCKFILE(fd->secret->md.osfd); + PR_ASSERT(status == PR_SUCCESS || fd->secret->lockCount == 0); + if (status == PR_SUCCESS) + fd->secret->lockCount = 1; + } else { + fd->secret->lockCount++; + } + PR_Unlock(_pr_flock_lock); + + return status; +} + +PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd) +{ + PRStatus rv = PR_SUCCESS; + + PR_Lock(_pr_flock_lock); + if (fd->secret->lockCount == 1) { + rv = _PR_MD_UNLOCKFILE(fd->secret->md.osfd); + if (rv == PR_SUCCESS) + fd->secret->lockCount = 0; + } else { + fd->secret->lockCount--; + } + PR_Unlock(_pr_flock_lock); + + return rv; +} + +PR_IMPLEMENT(PRStatus) PR_CreatePipe( + PRFileDesc **readPipe, + PRFileDesc **writePipe +) +{ +#if defined(XP_MAC) +#pragma unused (readPipe, writePipe) +#endif + +#ifdef WIN32 + HANDLE readEnd, writeEnd; + SECURITY_ATTRIBUTES pipeAttributes; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + ZeroMemory(&pipeAttributes, sizeof(pipeAttributes)); + pipeAttributes.nLength = sizeof(pipeAttributes); + pipeAttributes.bInheritHandle = TRUE; + if (CreatePipe(&readEnd, &writeEnd, &pipeAttributes, 0) == 0) { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } + *readPipe = PR_AllocFileDesc((PROsfd)readEnd, &_pr_pipeMethods); + if (NULL == *readPipe) { + CloseHandle(readEnd); + CloseHandle(writeEnd); + return PR_FAILURE; + } + *writePipe = PR_AllocFileDesc((PROsfd)writeEnd, &_pr_pipeMethods); + if (NULL == *writePipe) { + PR_Close(*readPipe); + CloseHandle(writeEnd); + return PR_FAILURE; + } +#ifdef WINNT + (*readPipe)->secret->md.sync_file_io = PR_TRUE; + (*writePipe)->secret->md.sync_file_io = PR_TRUE; +#endif + (*readPipe)->secret->inheritable = _PR_TRI_TRUE; + (*writePipe)->secret->inheritable = _PR_TRI_TRUE; + return PR_SUCCESS; +#elif defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) +#ifdef XP_OS2 + HFILE pipefd[2]; +#else + int pipefd[2]; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#ifdef XP_OS2 + if (DosCreatePipe(&pipefd[0], &pipefd[1], 4096) != 0) { +#else + if (pipe(pipefd) == -1) { +#endif + /* XXX map pipe error */ + PR_SetError(PR_UNKNOWN_ERROR, errno); + return PR_FAILURE; + } + *readPipe = PR_AllocFileDesc(pipefd[0], &_pr_pipeMethods); + if (NULL == *readPipe) { + close(pipefd[0]); + close(pipefd[1]); + return PR_FAILURE; + } + *writePipe = PR_AllocFileDesc(pipefd[1], &_pr_pipeMethods); + if (NULL == *writePipe) { + PR_Close(*readPipe); + close(pipefd[1]); + return PR_FAILURE; + } +#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */ + _PR_MD_MAKE_NONBLOCK(*readPipe); +#endif + _PR_MD_INIT_FD_INHERITABLE(*readPipe, PR_FALSE); +#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */ + _PR_MD_MAKE_NONBLOCK(*writePipe); +#endif + _PR_MD_INIT_FD_INHERITABLE(*writePipe, PR_FALSE); + return PR_SUCCESS; +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +#endif +} + +#ifdef MOZ_UNICODE +/* ================ UTF16 Interfaces ================================ */ +PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16( + const PRUnichar *name, PRIntn flags, PRIntn mode) +{ + PROsfd osfd; + PRFileDesc *fd = 0; +#if !defined(_PR_HAVE_O_APPEND) + PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* Map pr open flags and mode to os specific flags */ + osfd = _PR_MD_OPEN_FILE_UTF16(name, flags, mode); + if (osfd != -1) { + fd = PR_AllocFileDesc(osfd, &_pr_fileMethods); + if (!fd) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { +#if !defined(_PR_HAVE_O_APPEND) + fd->secret->appendMode = appendMode; +#endif + _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); + } + } + return fd; +} + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info) +{ +#ifdef XP_MAC +#pragma unused (fn, info) +#endif + PRInt32 rv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_GETFILEINFO64_UTF16(fn, info); + if (rv < 0) { + return PR_FAILURE; + } else { + return PR_SUCCESS; + } +} + +/* ================ UTF16 Interfaces ================================ */ +#endif /* MOZ_UNICODE */ diff --git a/nsprpub/pr/src/io/prio.c b/nsprpub/pr/src/io/prio.c new file mode 100644 index 00000000000..be187756aba --- /dev/null +++ b/nsprpub/pr/src/io/prio.c @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include /* for memset() */ + + +/************************************************************************/ + +PRLock *_pr_flock_lock; +PRCondVar *_pr_flock_cv; + +void _PR_InitIO(void) +{ + const PRIOMethods *methods = PR_GetFileMethods(); + + _PR_InitFdCache(); + + _pr_flock_lock = PR_NewLock(); + _pr_flock_cv = PR_NewCondVar(_pr_flock_lock); + +#ifdef WIN32 + _pr_stdin = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_INPUT_HANDLE), + methods); + _pr_stdout = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_OUTPUT_HANDLE), + methods); + _pr_stderr = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_ERROR_HANDLE), + methods); +#ifdef WINNT + _pr_stdin->secret->md.sync_file_io = PR_TRUE; + _pr_stdout->secret->md.sync_file_io = PR_TRUE; + _pr_stderr->secret->md.sync_file_io = PR_TRUE; +#endif +#else + _pr_stdin = PR_AllocFileDesc(0, methods); + _pr_stdout = PR_AllocFileDesc(1, methods); + _pr_stderr = PR_AllocFileDesc(2, methods); +#endif + _PR_MD_INIT_FD_INHERITABLE(_pr_stdin, PR_TRUE); + _PR_MD_INIT_FD_INHERITABLE(_pr_stdout, PR_TRUE); + _PR_MD_INIT_FD_INHERITABLE(_pr_stderr, PR_TRUE); + + _PR_MD_INIT_IO(); +} + +void _PR_CleanupIO(void) +{ + PR_FreeFileDesc(_pr_stdin); + _pr_stdin = NULL; + PR_FreeFileDesc(_pr_stdout); + _pr_stdout = NULL; + PR_FreeFileDesc(_pr_stderr); + _pr_stderr = NULL; + + if (_pr_flock_cv) { + PR_DestroyCondVar(_pr_flock_cv); + _pr_flock_cv = NULL; + } + if (_pr_flock_lock) { + PR_DestroyLock(_pr_flock_lock); + _pr_flock_lock = NULL; + } + + _PR_CleanupFdCache(); +} + +PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd) +{ + PRFileDesc *result = NULL; + PR_ASSERT((int) osfd >= PR_StandardInput && osfd <= PR_StandardError); + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + switch (osfd) + { + case PR_StandardInput: result = _pr_stdin; break; + case PR_StandardOutput: result = _pr_stdout; break; + case PR_StandardError: result = _pr_stderr; break; + default: + (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + } + return result; +} + +PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc( + PROsfd osfd, const PRIOMethods *methods) +{ + PRFileDesc *fd; + +#ifdef XP_UNIX + /* + * Assert that the file descriptor is small enough to fit in the + * fd_set passed to select + */ + PR_ASSERT(osfd < FD_SETSIZE); +#endif + fd = _PR_Getfd(); + if (fd) { + /* Initialize the members of PRFileDesc and PRFilePrivate */ + fd->methods = methods; + fd->secret->state = _PR_FILEDESC_OPEN; + fd->secret->md.osfd = osfd; + _PR_MD_INIT_FILEDESC(fd); + } else { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + + return fd; +} + +PR_IMPLEMENT(void) PR_FreeFileDesc(PRFileDesc *fd) +{ + PR_ASSERT(fd); +#ifdef XP_MAC + _PR_MD_FREE_FILEDESC(fd); +#endif + _PR_Putfd(fd); +} + +/* +** 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) +{ + return(_PR_MD_PR_POLL(pds, npds, timeout)); +} + +/* +** Set the inheritance attribute of a file descriptor. +*/ +PR_IMPLEMENT(PRStatus) PR_SetFDInheritable( + PRFileDesc *fd, + PRBool inheritable) +{ +#if defined(XP_UNIX) || defined(WIN32) || defined(XP_OS2) || defined(XP_BEOS) + /* + * Only a non-layered, NSPR file descriptor can be inherited + * by a child process. + */ + if (fd->identity != PR_NSPR_IO_LAYER) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + if (fd->secret->inheritable != inheritable) { + if (_PR_MD_SET_FD_INHERITABLE(fd, inheritable) == PR_FAILURE) { + return PR_FAILURE; + } + fd->secret->inheritable = inheritable; + } + return PR_SUCCESS; +#else +#ifdef XP_MAC +#pragma unused (fd, inheritable) +#endif + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +#endif +} + +/* +** This function only has a useful implementation in the debug build of +** the pthreads version. +*/ +PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg) +{ + /* do nothing */ +} /* PT_FPrintStats */ diff --git a/nsprpub/pr/src/io/priometh.c b/nsprpub/pr/src/io/priometh.c new file mode 100644 index 00000000000..1ca474f0133 --- /dev/null +++ b/nsprpub/pr/src/io/priometh.c @@ -0,0 +1,628 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "primpl.h" + +#include + +/*****************************************************************************/ +/************************** 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, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PRIntn _PR_InvalidInt(void) +{ + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return -1; +} /* _PR_InvalidInt */ + +PRInt16 _PR_InvalidInt16(void) +{ + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return -1; +} /* _PR_InvalidInt */ + +PRInt64 _PR_InvalidInt64(void) +{ + PRInt64 rv; + LL_I2L(rv, -1); + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return rv; +} /* _PR_InvalidInt */ + +/* + * An invalid method that returns PRStatus + */ + +PRStatus _PR_InvalidStatus(void) +{ + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return PR_FAILURE; +} /* _PR_InvalidDesc */ + +/* + * An invalid method that returns a pointer + */ + +PRFileDesc *_PR_InvalidDesc(void) +{ + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return NULL; +} /* _PR_InvalidDesc */ + +PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file) +{ + return file->methods->file_type; +} + +PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc *fd) +{ + return (fd->methods->close)(fd); +} + +PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + return((fd->methods->read)(fd,buf,amount)); +} + +PR_IMPLEMENT(PRInt32) PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + return((fd->methods->write)(fd,buf,amount)); +} + +PR_IMPLEMENT(PRInt32) PR_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) +{ + return((fd->methods->seek)(fd, offset, whence)); +} + +PR_IMPLEMENT(PRInt64) PR_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) +{ + return((fd->methods->seek64)(fd, offset, whence)); +} + +PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc *fd) +{ + return((fd->methods->available)(fd)); +} + +PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc *fd) +{ + return((fd->methods->available64)(fd)); +} + +PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info) +{ + return((fd->methods->fileInfo)(fd, info)); +} + +PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info) +{ + return((fd->methods->fileInfo64)(fd, info)); +} + +PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc *fd) +{ + return((fd->methods->fsync)(fd)); +} + +PR_IMPLEMENT(PRStatus) PR_Connect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + return((fd->methods->connect)(fd,addr,timeout)); +} + +PR_IMPLEMENT(PRStatus) PR_ConnectContinue( + PRFileDesc *fd, PRInt16 out_flags) +{ + return((fd->methods->connectcontinue)(fd,out_flags)); +} + +PR_IMPLEMENT(PRFileDesc*) PR_Accept(PRFileDesc *fd, PRNetAddr *addr, +PRIntervalTime timeout) +{ + return((fd->methods->accept)(fd,addr,timeout)); +} + +PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr) +{ + return((fd->methods->bind)(fd,addr)); +} + +PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how) +{ + return((fd->methods->shutdown)(fd,how)); +} + +PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog) +{ + return((fd->methods->listen)(fd,backlog)); +} + +PR_IMPLEMENT(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount, +PRIntn flags, PRIntervalTime timeout) +{ + return((fd->methods->recv)(fd,buf,amount,flags,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, +PRIntn flags, PRIntervalTime timeout) +{ + return((fd->methods->send)(fd,buf,amount,flags,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_Writev(PRFileDesc *fd, const PRIOVec *iov, +PRInt32 iov_size, PRIntervalTime timeout) +{ + if (iov_size > PR_MAX_IOVECTOR_SIZE) + { + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); + return -1; + } + return((fd->methods->writev)(fd,iov,iov_size,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, +PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) +{ + return((fd->methods->recvfrom)(fd,buf,amount,flags,addr,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_SendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) +{ + return((fd->methods->sendto)(fd,buf,amount,flags,addr,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_TransmitFile( + PRFileDesc *sd, PRFileDesc *fd, const void *hdr, PRInt32 hlen, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + return((sd->methods->transmitfile)(sd,fd,hdr,hlen,flags,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_AcceptRead( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + return((sd->methods->acceptread)(sd, nd, raddr, buf, amount,timeout)); +} + +PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr) +{ + return((fd->methods->getsockname)(fd,addr)); +} + +PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) +{ + return((fd->methods->getpeername)(fd,addr)); +} + +PR_IMPLEMENT(PRStatus) PR_GetSocketOption( + PRFileDesc *fd, PRSocketOptionData *data) +{ + return((fd->methods->getsocketoption)(fd, data)); +} + +PR_IMPLEMENT(PRStatus) PR_SetSocketOption( + PRFileDesc *fd, const PRSocketOptionData *data) +{ + return((fd->methods->setsocketoption)(fd, data)); +} + +PR_IMPLEMENT(PRInt32) PR_SendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + return((sd->methods->sendfile)(sd,sfd,flags,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_EmulateAcceptRead( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + PRInt32 rv = -1; + PRNetAddr remote; + PRFileDesc *accepted = NULL; + + /* + ** 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 */ +#define AMASK ((PRPtrdiff)7) /* mask for alignment of PRNetAddr */ + PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK; + *raddr = (PRNetAddr*)(aligned & ~AMASK); + memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote)); + *nd = accepted; + return rv; + } + + PR_Close(accepted); + return rv; +} + +/* + * PR_EmulateSendFile + * + * Send file sfd->fd across socket sd. If header/trailer are specified + * they are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + */ + +#if defined(XP_UNIX) || defined(WIN32) + +/* + * An implementation based on memory-mapped files + */ + +#define SENDFILE_MMAP_CHUNK (256 * 1024) + +PR_IMPLEMENT(PRInt32) PR_EmulateSendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRInt32 rv, count = 0; + PRInt32 len, file_bytes, index = 0; + PRFileInfo info; + PRIOVec iov[3]; + PRFileMap *mapHandle = NULL; + void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */ + PRUint32 file_mmap_offset, alignment; + PRInt64 zero64; + PROffset64 file_mmap_offset64; + PRUint32 addr_offset, mmap_len; + + /* Get file size */ + if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) { + count = -1; + goto done; + } + if (sfd->file_nbytes && + (info.size < (sfd->file_offset + sfd->file_nbytes))) { + /* + * there are fewer bytes in file to send than specified + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + count = -1; + goto done; + } + if (sfd->file_nbytes) + file_bytes = sfd->file_nbytes; + else + file_bytes = info.size - sfd->file_offset; + + alignment = PR_GetMemMapAlignment(); + + /* number of initial bytes to skip in mmap'd segment */ + addr_offset = sfd->file_offset % alignment; + + /* find previous mmap alignment boundary */ + file_mmap_offset = sfd->file_offset - addr_offset; + + /* + * If the file is large, mmap and send the file in chunks so as + * to not consume too much virtual address space + */ + mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK); + len = mmap_len - addr_offset; + + /* + * Map in (part of) file. Take care of zero-length files. + */ + if (len) { + LL_I2L(zero64, 0); + mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY); + if (!mapHandle) { + count = -1; + goto done; + } + LL_I2L(file_mmap_offset64, file_mmap_offset); + addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len); + if (!addr) { + count = -1; + goto done; + } + } + /* + * send headers first, followed by the file + */ + if (sfd->hlen) { + iov[index].iov_base = (char *) sfd->header; + iov[index].iov_len = sfd->hlen; + index++; + } + if (len) { + iov[index].iov_base = (char*)addr + addr_offset; + iov[index].iov_len = len; + index++; + } + if ((file_bytes == len) && (sfd->tlen)) { + /* + * all file data is mapped in; send the trailer too + */ + iov[index].iov_base = (char *) sfd->trailer; + iov[index].iov_len = sfd->tlen; + index++; + } + rv = PR_Writev(sd, iov, index, timeout); + if (len) + PR_MemUnmap(addr, mmap_len); + if (rv < 0) { + count = -1; + goto done; + } + + PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0)); + + file_bytes -= len; + count += rv; + if (!file_bytes) /* header, file and trailer are sent */ + goto done; + + /* + * send remaining bytes of the file, if any + */ + len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); + while (len > 0) { + /* + * Map in (part of) file + */ + file_mmap_offset = sfd->file_offset + count - sfd->hlen; + PR_ASSERT((file_mmap_offset % alignment) == 0); + + LL_I2L(file_mmap_offset64, file_mmap_offset); + addr = PR_MemMap(mapHandle, file_mmap_offset64, len); + if (!addr) { + count = -1; + goto done; + } + rv = PR_Send(sd, addr, len, 0, timeout); + PR_MemUnmap(addr, len); + if (rv < 0) { + count = -1; + goto done; + } + + PR_ASSERT(rv == len); + file_bytes -= rv; + count += rv; + len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); + } + PR_ASSERT(0 == file_bytes); + if (sfd->tlen) { + rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); + if (rv >= 0) { + PR_ASSERT(rv == sfd->tlen); + count += rv; + } else + count = -1; + } +done: + if (mapHandle) + PR_CloseFileMap(mapHandle); + if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) + PR_Close(sd); + return count; +} + +#else + +PR_IMPLEMENT(PRInt32) PR_EmulateSendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRInt32 rv, count = 0; + PRInt32 rlen; + const void * buffer; + PRInt32 buflen; + PRInt32 sendbytes, readbytes; + char *buf; + +#define _SENDFILE_BUFSIZE (16 * 1024) + + buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE); + if (buf == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + + /* + * send header first + */ + buflen = sfd->hlen; + buffer = sfd->header; + while (buflen) { + rv = PR_Send(sd, buffer, buflen, 0, timeout); + if (rv < 0) { + /* PR_Send() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else { + count += rv; + buffer = (const void*) ((const char*)buffer + rv); + buflen -= rv; + } + } + + /* + * send file next + */ + if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) { + rv = -1; + goto done; + } + sendbytes = sfd->file_nbytes; + if (sendbytes == 0) { + /* send entire file */ + while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) { + while (rlen) { + char *bufptr = buf; + + rv = PR_Send(sd, bufptr, rlen, 0, timeout); + if (rv < 0) { + /* PR_Send() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else { + count += rv; + bufptr = ((char*)bufptr + rv); + rlen -= rv; + } + } + } + if (rlen < 0) { + /* PR_Read() has invoked PR_SetError(). */ + rv = -1; + goto done; + } + } else { + readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE); + while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) { + while (rlen) { + char *bufptr = buf; + + rv = PR_Send(sd, bufptr, rlen, 0, timeout); + if (rv < 0) { + /* PR_Send() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else { + count += rv; + sendbytes -= rv; + bufptr = ((char*)bufptr + rv); + rlen -= rv; + } + } + readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE); + } + if (rlen < 0) { + /* PR_Read() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else if (sendbytes != 0) { + /* + * there are fewer bytes in file to send than specified + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = -1; + goto done; + } + } + + /* + * send trailer last + */ + buflen = sfd->tlen; + buffer = sfd->trailer; + while (buflen) { + rv = PR_Send(sd, buffer, buflen, 0, timeout); + if (rv < 0) { + /* PR_Send() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else { + count += rv; + buffer = (const void*) ((const char*)buffer + rv); + buflen -= rv; + } + } + rv = count; + +done: + if (buf) + PR_DELETE(buf); + if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) + PR_Close(sd); + return rv; +} + +#endif + +/* priometh.c */ diff --git a/nsprpub/pr/src/io/pripv6.c b/nsprpub/pr/src/io/pripv6.c new file mode 100644 index 00000000000..e4af39c1163 --- /dev/null +++ b/nsprpub/pr/src/io/pripv6.c @@ -0,0 +1,396 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: pripv6.c +** Description: Support for various functions unique to IPv6 +*/ +#include "primpl.h" +#include + +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) + +static PRIOMethods ipv6_to_v4_tcpMethods; +static PRIOMethods ipv6_to_v4_udpMethods; +static PRDescIdentity _pr_ipv6_to_ipv4_id; +extern PRBool IsValidNetAddr(const PRNetAddr *addr); +extern PRIPv6Addr _pr_in6addr_any; +extern PRIPv6Addr _pr_in6addr_loopback; + +/* + * convert an IPv4-mapped IPv6 addr to an IPv4 addr + */ +static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr, + PRNetAddr *dst_v4addr) +{ +const PRUint8 *srcp; + + PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family); + + if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) { + srcp = src_v6addr->ipv6.ip.pr_s6_addr; + memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4); + } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) { + dst_v4addr->inet.ip = htonl(INADDR_ANY); + } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) { + dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK); + } + dst_v4addr->inet.family = PR_AF_INET; + dst_v4addr->inet.port = src_v6addr->ipv6.port; +} + +/* + * convert an IPv4 addr to an IPv4-mapped IPv6 addr + */ +static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr, + PRNetAddr *dst_v6addr) +{ +PRUint8 *dstp; + + PR_ASSERT(PR_AF_INET == src_v4addr->inet.family); + dst_v6addr->ipv6.family = PR_AF_INET6; + dst_v6addr->ipv6.port = src_v4addr->inet.port; + + if (htonl(INADDR_ANY) == src_v4addr->inet.ip) { + dst_v6addr->ipv6.ip = _pr_in6addr_any; + } else { + dstp = dst_v6addr->ipv6.ip.pr_s6_addr; + memset(dstp, 0, 10); + memset(dstp + 10, 0xff, 2); + memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4); + } +} + +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd, + const PRNetAddr *addr) +{ + PRNetAddr tmp_ipv4addr; + const PRNetAddr *tmp_addrp; + PRFileDesc *lo = fd->lower; + + if (PR_AF_INET6 != addr->raw.family) { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; + } + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || + PR_IsNetAddrType(addr, PR_IpAddrAny)) { + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); + tmp_addrp = &tmp_ipv4addr; + } else { + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); + return PR_FAILURE; + } + return((lo->methods->bind)(lo,tmp_addrp)); +} + +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRNetAddr tmp_ipv4addr; + const PRNetAddr *tmp_addrp; + + if (PR_AF_INET6 != addr->raw.family) { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; + } + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || + PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); + tmp_addrp = &tmp_ipv4addr; + } else { + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); + return PR_FAILURE; + } + return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout); +} + +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRNetAddr tmp_ipv4addr; + const PRNetAddr *tmp_addrp; + + if (PR_AF_INET6 != addr->raw.family) { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; + } + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || + PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); + tmp_addrp = &tmp_ipv4addr; + } else { + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); + return PR_FAILURE; + } + return (fd->lower->methods->sendto)( + fd->lower, buf, amount, flags, tmp_addrp, timeout); +} + +static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept ( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRStatus rv; + PRFileDesc *newfd; + PRFileDesc *newstack; + PRNetAddr tmp_ipv4addr; + PRNetAddr *addrlower = NULL; + + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + *newstack = *fd; /* make a copy of the accepting layer */ + + if (addr) + addrlower = &tmp_ipv4addr; + newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout); + if (NULL == newfd) + { + PR_DELETE(newstack); + return NULL; + } + if (addr) + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr); + + rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return newfd; /* that's it */ +} + +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd, + PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount, + PRIntervalTime timeout) +{ + PRInt32 nbytes; + PRStatus rv; + PRNetAddr tmp_ipv4addr; + PRFileDesc *newstack; + + PR_ASSERT(sd != NULL); + PR_ASSERT(sd->lower != NULL); + + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + *newstack = *sd; /* make a copy of the accepting layer */ + + nbytes = sd->lower->methods->acceptread( + sd->lower, nd, ipv6_raddr, buf, amount, timeout); + if (-1 == nbytes) + { + PR_DELETE(newstack); + return nbytes; + } + tmp_ipv4addr = **ipv6_raddr; /* copy */ + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr); + + /* this PR_PushIOLayer call cannot fail */ + rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return nbytes; +} + +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd, + PRNetAddr *ipv6addr) +{ + PRStatus result; + PRNetAddr tmp_ipv4addr; + + result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr); + if (PR_SUCCESS == result) { + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); + } + return result; +} + +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd, + PRNetAddr *ipv6addr) +{ + PRStatus result; + PRNetAddr tmp_ipv4addr; + + result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr); + if (PR_SUCCESS == result) { + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); + } + return result; +} + +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf, + PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr, + PRIntervalTime timeout) +{ + PRNetAddr tmp_ipv4addr; + PRInt32 result; + + result = (fd->lower->methods->recvfrom)( + fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout); + if (-1 != result) { + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); + } + return result; +} + +#if defined(_PR_INET6_PROBE) +static PRBool ipv6_is_present; +extern PRBool _pr_test_ipv6_socket(void); + +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) +extern PRStatus _pr_find_getipnodebyname(void); +#endif + +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) +extern PRStatus _pr_find_getaddrinfo(void); +#endif + +static PRBool +_pr_probe_ipv6_presence(void) +{ +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) + if (_pr_find_getipnodebyname() != PR_SUCCESS) + return PR_FALSE; +#endif + +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) + if (_pr_find_getaddrinfo() != PR_SUCCESS) + return PR_FALSE; +#endif + + return _pr_test_ipv6_socket(); +} +#endif /* _PR_INET6_PROBE */ + +static PRCallOnceType _pr_init_ipv6_once; + +static PRStatus PR_CALLBACK _pr_init_ipv6(void) +{ + const PRIOMethods *stubMethods; + +#if defined(_PR_INET6_PROBE) + ipv6_is_present = _pr_probe_ipv6_presence(); + if (ipv6_is_present) + return PR_SUCCESS; +#endif + + _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer"); + PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id); + + stubMethods = PR_GetDefaultIOMethods(); + + ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */ + /* then override the ones we care about */ + ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect; + ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind; + ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept; + ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead; + ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName; + ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; +/* + ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; + ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; +*/ + ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */ + /* then override the ones we care about */ + ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect; + ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind; + ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo; + ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom; + ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName; + ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; +/* + ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; + ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; +*/ + return PR_SUCCESS; +} + +#if defined(_PR_INET6_PROBE) +PRBool _pr_ipv6_is_present(void) +{ + if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) + return PR_FALSE; + return ipv6_is_present; +} +#endif + +PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd) +{ + PRFileDesc *ipv6_fd = NULL; + + if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) + return PR_FAILURE; + + /* + * For platforms with no support for IPv6 + * create layered socket for IPv4-mapped IPv6 addresses + */ + if (fd->methods->file_type == PR_DESC_SOCKET_TCP) + ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, + &ipv6_to_v4_tcpMethods); + else + ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, + &ipv6_to_v4_udpMethods); + if (NULL == ipv6_fd) { + goto errorExit; + } + ipv6_fd->secret = NULL; + + if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) { + goto errorExit; + } + + return PR_SUCCESS; +errorExit: + + if (ipv6_fd) + ipv6_fd->dtor(ipv6_fd); + return PR_FAILURE; +} + +#endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */ diff --git a/nsprpub/pr/src/io/prlayer.c b/nsprpub/pr/src/io/prlayer.c new file mode 100644 index 00000000000..cf48d23a350 --- /dev/null +++ b/nsprpub/pr/src/io/prlayer.c @@ -0,0 +1,768 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prlayer.c +** Description: Routines for handling pushable protocol modules on sockets. +*/ + +#include "primpl.h" +#include "prerror.h" +#include "prmem.h" +#include "prlock.h" +#include "prlog.h" +#include "prio.h" + +#include /* for memset() */ +static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack); + +void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd) +{ + PR_ASSERT(fd != NULL); + if (NULL != fd->lower) fd->lower->higher = fd->higher; + if (NULL != fd->higher) fd->higher->lower = fd->lower; + PR_DELETE(fd); +} + +/* +** Default methods that just call down to the next fd. +*/ +static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd) +{ + PRFileDesc *top, *lower; + PRStatus rv; + + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + PR_ASSERT(fd->secret == NULL); + PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED); + + if (PR_IO_LAYER_HEAD == fd->identity) { + /* + * new style stack; close all the layers, before deleting the + * stack head + */ + rv = fd->lower->methods->close(fd->lower); + _PR_DestroyIOLayer(fd); + return rv; + } else if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) { + /* + * lower layers of new style stack + */ + lower = fd->lower; + /* + * pop and cleanup current layer + */ + top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER); + top->dtor(top); + /* + * then call lower layer + */ + return (lower->methods->close(lower)); + } else { + /* old style stack */ + top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER); + top->dtor(top); + return (fd->methods->close)(fd); + } +} + +static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->read)(fd->lower, buf, amount); +} + +static PRInt32 PR_CALLBACK pl_DefWrite ( + PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->write)(fd->lower, buf, amount); +} + +static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->available)(fd->lower); +} + +static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->available64)(fd->lower); +} + +static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->fsync)(fd->lower); +} + +static PRInt32 PR_CALLBACK pl_DefSeek ( + PRFileDesc *fd, PRInt32 offset, PRSeekWhence how) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->seek)(fd->lower, offset, how); +} + +static PRInt64 PR_CALLBACK pl_DefSeek64 ( + PRFileDesc *fd, PRInt64 offset, PRSeekWhence how) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->seek64)(fd->lower, offset, how); +} + +static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->fileInfo)(fd->lower, info); +} + +static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->fileInfo64)(fd->lower, info); +} + +static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, const PRIOVec *iov, + PRInt32 size, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->writev)(fd->lower, iov, size, timeout); +} + +static PRStatus PR_CALLBACK pl_DefConnect ( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->connect)(fd->lower, addr, timeout); +} + +static PRStatus PR_CALLBACK pl_DefConnectcontinue ( + PRFileDesc *fd, PRInt16 out_flags) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->connectcontinue)(fd->lower, out_flags); +} + +static PRFileDesc* PR_CALLBACK pl_TopAccept ( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRStatus rv; + PRFileDesc *newfd, *layer = fd; + PRFileDesc *newstack; + PRBool newstyle_stack = PR_FALSE; + + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + /* test for new style stack */ + while (NULL != layer->higher) + layer = layer->higher; + newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE; + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + *newstack = *fd; /* make a copy of the accepting layer */ + + newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout); + if (NULL == newfd) + { + PR_DELETE(newstack); + return NULL; + } + + if (newstyle_stack) { + newstack->lower = newfd; + newfd->higher = newstack; + return newstack; + } else { + /* this PR_PushIOLayer call cannot fail */ + rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return newfd; /* that's it */ + } +} + +static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->bind)(fd->lower, addr); +} + +static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->listen)(fd->lower, backlog); +} + +static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->shutdown)(fd->lower, how); +} + +static PRInt32 PR_CALLBACK pl_DefRecv ( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->recv)( + fd->lower, buf, amount, flags, timeout); +} + +static PRInt32 PR_CALLBACK pl_DefSend ( + PRFileDesc *fd, const void *buf, + PRInt32 amount, PRIntn flags, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout); +} + +static PRInt32 PR_CALLBACK pl_DefRecvfrom ( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->recvfrom)( + fd->lower, buf, amount, flags, addr, timeout); +} + +static PRInt32 PR_CALLBACK pl_DefSendto ( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->sendto)( + fd->lower, buf, amount, flags, addr, timeout); +} + +static PRInt16 PR_CALLBACK pl_DefPoll ( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags); +} + +static PRInt32 PR_CALLBACK pl_DefAcceptread ( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf, + PRInt32 amount, PRIntervalTime t) +{ + PRInt32 nbytes; + PRStatus rv; + PRFileDesc *newstack; + PRFileDesc *layer = sd; + PRBool newstyle_stack = PR_FALSE; + + PR_ASSERT(sd != NULL); + PR_ASSERT(sd->lower != NULL); + + /* test for new style stack */ + while (NULL != layer->higher) + layer = layer->higher; + newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE; + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + *newstack = *sd; /* make a copy of the accepting layer */ + + nbytes = sd->lower->methods->acceptread( + sd->lower, nd, raddr, buf, amount, t); + if (-1 == nbytes) + { + PR_DELETE(newstack); + return nbytes; + } + if (newstyle_stack) { + newstack->lower = *nd; + (*nd)->higher = newstack; + *nd = newstack; + return nbytes; + } else { + /* this PR_PushIOLayer call cannot fail */ + rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return nbytes; + } +} + +static PRInt32 PR_CALLBACK pl_DefTransmitfile ( + PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen, + PRTransmitFileFlags flags, PRIntervalTime t) +{ + PR_ASSERT(sd != NULL); + PR_ASSERT(sd->lower != NULL); + + return sd->lower->methods->transmitfile( + sd->lower, fd, headers, hlen, flags, t); +} + +static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->getsockname)(fd->lower, addr); +} + +static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->getpeername)(fd->lower, addr); +} + +static PRStatus PR_CALLBACK pl_DefGetsocketoption ( + PRFileDesc *fd, PRSocketOptionData *data) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->getsocketoption)(fd->lower, data); +} + +static PRStatus PR_CALLBACK pl_DefSetsocketoption ( + PRFileDesc *fd, const PRSocketOptionData *data) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->setsocketoption)(fd->lower, data); +} + +static PRInt32 PR_CALLBACK pl_DefSendfile ( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PR_ASSERT(sd != NULL); + PR_ASSERT(sd->lower != NULL); + + return sd->lower->methods->sendfile( + sd->lower, sfd, flags, timeout); +} + +/* Methods for the top of the stack. Just call down to the next fd. */ +static PRIOMethods pl_methods = { + PR_DESC_LAYERED, + pl_TopClose, + pl_DefRead, + pl_DefWrite, + pl_DefAvailable, + pl_DefAvailable64, + pl_DefFsync, + pl_DefSeek, + pl_DefSeek64, + pl_DefFileInfo, + pl_DefFileInfo64, + pl_DefWritev, + pl_DefConnect, + pl_TopAccept, + pl_DefBind, + pl_DefListen, + pl_DefShutdown, + pl_DefRecv, + pl_DefSend, + pl_DefRecvfrom, + pl_DefSendto, + pl_DefPoll, + pl_DefAcceptread, + pl_DefTransmitfile, + pl_DefGetsockname, + pl_DefGetpeername, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + pl_DefGetsocketoption, + pl_DefSetsocketoption, + pl_DefSendfile, + pl_DefConnectcontinue, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void) +{ + return &pl_methods; +} /* PR_GetDefaultIOMethods */ + +PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub( + PRDescIdentity ident, const PRIOMethods *methods) +{ + PRFileDesc *fd = NULL; + PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident)); + if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident)) + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + else + { + fd = PR_NEWZAP(PRFileDesc); + if (NULL == fd) + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->methods = methods; + fd->dtor = pl_FDDestructor; + fd->identity = ident; + } + } + return fd; +} /* PR_CreateIOLayerStub */ + +/* + * PR_CreateIOLayer + * Create a new style stack, where the stack top is a dummy header. + * Unlike the old style stacks, the contents of the stack head + * are not modified when a layer is pushed onto or popped from a new + * style stack. + */ + +PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc *top) +{ + PRFileDesc *fd = NULL; + + fd = PR_NEWZAP(PRFileDesc); + if (NULL == fd) + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->methods = &pl_methods; + fd->dtor = pl_FDDestructor; + fd->identity = PR_IO_LAYER_HEAD; + fd->higher = NULL; + fd->lower = top; + top->higher = fd; + top->lower = NULL; + } + return fd; +} /* PR_CreateIOLayer */ + +/* + * _PR_DestroyIOLayer + * Delete the stack head of a new style stack. + */ + +static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack) +{ + if (NULL == stack) + return PR_FAILURE; + else { + PR_DELETE(stack); + return PR_SUCCESS; + } +} /* _PR_DestroyIOLayer */ + +PR_IMPLEMENT(PRStatus) PR_PushIOLayer( + PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd) +{ + PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id); + + PR_ASSERT(fd != NULL); + PR_ASSERT(stack != NULL); + PR_ASSERT(insert != NULL); + PR_ASSERT(PR_IO_LAYER_HEAD != id); + if ((NULL == stack) || (NULL == fd) || (NULL == insert)) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + if (stack == insert) + { + /* going on top of the stack */ + /* old-style stack */ + PRFileDesc copy = *stack; + *stack = *fd; + *fd = copy; + fd->higher = stack; + stack->lower = fd; + stack->higher = NULL; + } else { + /* + * going somewhere in the middle of the stack for both old and new + * style stacks, or going on top of stack for new style stack + */ + fd->lower = insert; + fd->higher = insert->higher; + + insert->higher->lower = fd; + insert->higher = fd; + } + + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id) +{ + PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id); + + PR_ASSERT(0 != id); + PR_ASSERT(NULL != stack); + PR_ASSERT(NULL != extract); + if ((NULL == stack) || (0 == id) || (NULL == extract)) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + + if (extract == stack) { + /* popping top layer of the stack */ + /* old style stack */ + PRFileDesc copy = *stack; + extract = stack->lower; + *stack = *extract; + *extract = copy; + stack->higher = NULL; + } else if ((PR_IO_LAYER_HEAD == stack->identity) && + (extract == stack->lower) && (extract->lower == NULL)) { + /* + * new style stack + * popping the only layer in the stack; delete the stack too + */ + stack->lower = NULL; + _PR_DestroyIOLayer(stack); + } else { + /* for both kinds of stacks */ + extract->lower->higher = extract->higher; + extract->higher->lower = extract->lower; + } + extract->higher = extract->lower = NULL; + return extract; +} /* PR_PopIOLayer */ + +#define ID_CACHE_INCREMENT 16 +typedef struct _PRIdentity_cache +{ + PRLock *ml; + char **name; + PRIntn length; + PRDescIdentity ident; +} _PRIdentity_cache; + +static _PRIdentity_cache identity_cache; + +PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name) +{ + PRDescIdentity identity, length; + char **names = NULL, *name = NULL, **old = NULL; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident); + + if (NULL != layer_name) + { + name = (char*)PR_Malloc(strlen(layer_name) + 1); + if (NULL == name) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_INVALID_IO_LAYER; + } + strcpy(name, layer_name); + } + + /* this initial code runs unsafe */ +retry: + PR_ASSERT(NULL == names); + length = identity_cache.length; + if (length < (identity_cache.ident + 1)) + { + length += ID_CACHE_INCREMENT; + names = (char**)PR_CALLOC(length * sizeof(char*)); + if (NULL == names) + { + if (NULL != name) PR_DELETE(name); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_INVALID_IO_LAYER; + } + } + + /* now we get serious about thread safety */ + PR_Lock(identity_cache.ml); + PR_ASSERT(identity_cache.ident <= identity_cache.length); + identity = identity_cache.ident + 1; + if (identity > identity_cache.length) /* there's no room */ + { + /* we have to do something - hopefully it's already done */ + if ((NULL != names) && (length >= identity)) + { + /* what we did is still okay */ + memcpy( + names, identity_cache.name, + identity_cache.length * sizeof(char*)); + old = identity_cache.name; + identity_cache.name = names; + identity_cache.length = length; + names = NULL; + } + else + { + PR_ASSERT(identity_cache.ident <= identity_cache.length); + PR_Unlock(identity_cache.ml); + if (NULL != names) PR_DELETE(names); + goto retry; + } + } + if (NULL != name) /* there's a name to be stored */ + { + identity_cache.name[identity] = name; + } + identity_cache.ident = identity; + PR_ASSERT(identity_cache.ident <= identity_cache.length); + PR_Unlock(identity_cache.ml); + + if (NULL != old) PR_DELETE(old); + if (NULL != names) PR_DELETE(names); + + return identity; +} /* PR_GetUniqueIdentity */ + +PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (PR_TOP_IO_LAYER == ident) return NULL; + + PR_ASSERT(ident <= identity_cache.ident); + return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident]; +} /* PR_GetNameForIdentity */ + +PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd) +{ + PR_ASSERT(NULL != fd); + if (PR_IO_LAYER_HEAD == fd->identity) { + PR_ASSERT(NULL != fd->lower); + return fd->lower->identity; + } else + return fd->identity; +} /* PR_GetLayersIdentity */ + +PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id) +{ + PRFileDesc *layer = fd; + + if (PR_TOP_IO_LAYER == id) { + if (PR_IO_LAYER_HEAD == fd->identity) + return fd->lower; + else + return fd; + } + + for (layer = fd; layer != NULL; layer = layer->lower) + { + if (id == layer->identity) return layer; + } + for (layer = fd; layer != NULL; layer = layer->higher) + { + if (id == layer->identity) return layer; + } + return NULL; +} /* PR_GetIdentitiesLayer */ + +void _PR_InitLayerCache(void) +{ + memset(&identity_cache, 0, sizeof(identity_cache)); + identity_cache.ml = PR_NewLock(); + PR_ASSERT(NULL != identity_cache.ml); +} /* _PR_InitLayerCache */ + +void _PR_CleanupLayerCache(void) +{ + if (identity_cache.ml) + { + PR_DestroyLock(identity_cache.ml); + identity_cache.ml = NULL; + } + + if (identity_cache.name) + { + PRDescIdentity ident; + + for (ident = 0; ident <= identity_cache.ident; ident++) + PR_DELETE(identity_cache.name[ident]); + + PR_DELETE(identity_cache.name); + } +} /* _PR_CleanupLayerCache */ + +/* prlayer.c */ diff --git a/nsprpub/pr/src/io/prlog.c b/nsprpub/pr/src/io/prlog.c new file mode 100644 index 00000000000..e159958891f --- /dev/null +++ b/nsprpub/pr/src/io/prlog.c @@ -0,0 +1,586 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Contributors: + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines Corporation, 2000. + * Modifications to Mozilla code or documentation identified per + * MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/10/2000 IBM Corp. Added DebugBreak() definitions for OS/2 + */ + +#include "primpl.h" +#include "prenv.h" +#include "prprf.h" +#include + +/* + * Lock used to lock the log. + * + * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may + * contain assertions. We have to avoid assertions in _PR_LOCK_LOG + * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG. + * This can lead to infinite recursion. + */ +static PRLock *_pr_logLock; +#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) +#define _PR_LOCK_LOG() PR_Lock(_pr_logLock); +#define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock); +#elif defined(_PR_GLOBAL_THREADS_ONLY) +#define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock) +#define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); } +#else + +#define _PR_LOCK_LOG() \ +{ \ + PRIntn _is; \ + PRThread *_me = _PR_MD_CURRENT_THREAD(); \ + if (!_PR_IS_NATIVE_THREAD(_me)) \ + _PR_INTSOFF(_is); \ + _PR_LOCK_LOCK(_pr_logLock) + +#define _PR_UNLOCK_LOG() \ + _PR_LOCK_UNLOCK(_pr_logLock); \ + PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \ + if (!_PR_IS_NATIVE_THREAD(_me)) \ + _PR_INTSON(_is); \ +} + +#endif + +#if defined(XP_PC) +#define strcasecmp stricmp +#define strncasecmp strnicmp +#endif + +/* + * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE, + * because every asynchronous file io operation leads to a fiber context + * switch. So we define _PUT_LOG as fputs (from stdio.h). A side + * benefit is that fputs handles the LF->CRLF translation. This + * code can also be used on other platforms with file stream io. + */ +#if defined(WIN32) || defined(XP_OS2) +#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) && defined(XP_PC) +#define _PUT_LOG(fd, buf, nb) \ + PR_BEGIN_MACRO \ + if (logFile == WIN32_DEBUG_FILE) { \ + char savebyte = buf[nb]; \ + buf[nb] = '\0'; \ + OutputDebugString(buf); \ + buf[nb] = savebyte; \ + } else { \ + fwrite(buf, 1, nb, fd); \ + fflush(fd); \ + } \ + PR_END_MACRO +#elif defined(_PR_USE_STDIO_FOR_LOGGING) +#define _PUT_LOG(fd, buf, nb) {fwrite(buf, 1, nb, fd); fflush(fd);} +#elif defined(_PR_PTHREADS) +#define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb) +#elif defined(XP_MAC) +#define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE_SYNC(fd, buf, nb) +#else +#define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb) +#endif + +/************************************************************************/ + +static PRLogModuleInfo *logModules; + +static char *logBuf = NULL; +static char *logp; +static char *logEndp; +#ifdef _PR_USE_STDIO_FOR_LOGGING +static FILE *logFile = NULL; +#else +static PRFileDesc *logFile = 0; +#endif + +#define LINE_BUF_SIZE 512 +#define DEFAULT_BUF_SIZE 16384 + +#ifdef _PR_NEED_STRCASECMP + +/* + * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms + * such as NCR and Unixware. Linking with both libc and libucb + * may cause some problem, so I just provide our own implementation + * of strcasecmp here. + */ + +static const unsigned char uc[] = +{ + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + ' ', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '{', '|', '}', '~', '\177' +}; + +PRIntn strcasecmp(const char *a, const char *b) +{ + const unsigned char *ua = (const unsigned char *)a; + const unsigned char *ub = (const unsigned char *)b; + + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + while( (uc[*ua] == uc[*ub]) && ('\0' != *a) ) + { + a++; + ua++; + ub++; + } + + return (PRIntn)(uc[*ua] - uc[*ub]); +} + +#endif /* _PR_NEED_STRCASECMP */ + +void _PR_InitLog(void) +{ + char *ev; + + _pr_logLock = PR_NewLock(); + + ev = PR_GetEnv("NSPR_LOG_MODULES"); + if (ev && ev[0]) { + char module[64]; /* Security-Critical: If you change this + * size, you must also change the sscanf + * format string to be size-1. + */ + PRBool isSync = PR_FALSE; + PRIntn evlen = strlen(ev), pos = 0; + PRInt32 bufSize = DEFAULT_BUF_SIZE; + while (pos < evlen) { + PRIntn level = 1, count = 0, delta = 0; + count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n", + module, &delta, &level, &delta); + pos += delta; + if (count == 0) break; + + /* + ** If count == 2, then we got module and level. If count + ** == 1, then level defaults to 1 (module enabled). + */ + if (strcasecmp(module, "sync") == 0) { + isSync = PR_TRUE; + } else if (strcasecmp(module, "bufsize") == 0) { + if (level >= LINE_BUF_SIZE) { + bufSize = level; + } + } else { + PRLogModuleInfo *lm = logModules; + PRBool skip_modcheck = + (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE; + + while (lm != NULL) { + if (skip_modcheck) lm -> level = (PRLogModuleLevel)level; + else if (strcasecmp(module, lm->name) == 0) { + lm->level = (PRLogModuleLevel)level; + break; + } + lm = lm->next; + } + } + /*found:*/ + count = sscanf(&ev[pos], " , %n", &delta); + pos += delta; + if (count == EOF) break; + } + PR_SetLogBuffering(isSync ? 0 : bufSize); + +#ifdef XP_UNIX + if ((getuid() != geteuid()) || (getgid() != getegid())) { + return; + } +#endif /* XP_UNIX */ + + ev = PR_GetEnv("NSPR_LOG_FILE"); + if (ev && ev[0]) { + if (!PR_SetLogFile(ev)) { +#ifdef XP_PC + char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev); + if (str) { + OutputDebugString(str); + PR_smprintf_free(str); + } +#else + fprintf(stderr, "Unable to create nspr log file '%s'\n", ev); +#endif + } + } else { +#ifdef _PR_USE_STDIO_FOR_LOGGING + logFile = stderr; +#else + logFile = _pr_stderr; +#endif + } + } +} + +void _PR_LogCleanup(void) +{ + PRLogModuleInfo *lm = logModules; + + PR_LogFlush(); + +#ifdef _PR_USE_STDIO_FOR_LOGGING + if (logFile + && logFile != stdout + && logFile != stderr +#ifdef XP_PC + && logFile != WIN32_DEBUG_FILE +#endif + ) { + fclose(logFile); + logFile = NULL; + } +#else + if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) { + PR_Close(logFile); + logFile = NULL; + } +#endif + + if (logBuf) + PR_DELETE(logBuf); + + while (lm != NULL) { + PRLogModuleInfo *next = lm->next; + free((/*const*/ char *)lm->name); + PR_Free(lm); + lm = next; + } + logModules = NULL; + + if (_pr_logLock) { + PR_DestroyLock(_pr_logLock); + _pr_logLock = NULL; + } +} + +static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm ) +{ + char *ev; + + ev = PR_GetEnv("NSPR_LOG_MODULES"); + if (ev && ev[0]) { + char module[64]; /* Security-Critical: If you change this + * size, you must also change the sscanf + * format string to be size-1. + */ + PRIntn evlen = strlen(ev), pos = 0; + while (pos < evlen) { + PRIntn level = 1, count = 0, delta = 0; + + count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n", + module, &delta, &level, &delta); + pos += delta; + if (count == 0) break; + + /* + ** If count == 2, then we got module and level. If count + ** == 1, then level defaults to 1 (module enabled). + */ + if (lm != NULL) + { + if ((strcasecmp(module, "all") == 0) + || (strcasecmp(module, lm->name) == 0)) + { + lm->level = (PRLogModuleLevel)level; + } + } + count = sscanf(&ev[pos], " , %n", &delta); + pos += delta; + if (count == EOF) break; + } + } +} /* end _PR_SetLogModuleLevel() */ + +PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name) +{ + PRLogModuleInfo *lm; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + lm = PR_NEWZAP(PRLogModuleInfo); + if (lm) { + lm->name = strdup(name); + lm->level = PR_LOG_NONE; + lm->next = logModules; + logModules = lm; + _PR_SetLogModuleLevel(lm); + } + return lm; +} + +PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file) +{ +#ifdef _PR_USE_STDIO_FOR_LOGGING + FILE *newLogFile; + +#ifdef XP_PC + if ( strcmp( file, "WinDebug") == 0) + { + newLogFile = WIN32_DEBUG_FILE; + } + else +#endif + { + newLogFile = fopen(file, "w"); + if (!newLogFile) + return PR_FALSE; + + /* We do buffering ourselves. */ + setvbuf(newLogFile, NULL, _IONBF, 0); + } + if (logFile + && logFile != stdout + && logFile != stderr +#ifdef XP_PC + && logFile != WIN32_DEBUG_FILE +#endif + ) { + fclose(logFile); + } + logFile = newLogFile; + return PR_TRUE; +#else + PRFileDesc *newLogFile; + + newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0666); + if (newLogFile) { + if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) { + PR_Close(logFile); + } + logFile = newLogFile; +#if defined(XP_MAC) + SetLogFileTypeCreator(file); +#endif + } + return (PRBool) (newLogFile != 0); +#endif /* _PR_USE_STDIO_FOR_LOGGING */ +} + +PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size) +{ + PR_LogFlush(); + + if (logBuf) + PR_DELETE(logBuf); + + if (buffer_size >= LINE_BUF_SIZE) { + logp = logBuf = (char*) PR_MALLOC(buffer_size); + logEndp = logp + buffer_size; + } +} + +PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...) +{ + va_list ap; + char line[LINE_BUF_SIZE]; + char *line_long = NULL; + PRUint32 nb_tid, nb; + PRThread *me; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (!logFile) { + return; + } + + me = PR_GetCurrentThread(); + nb_tid = PR_snprintf(line, sizeof(line)-1, "%ld[%p]: ", +#if defined(_PR_DCETHREADS) + /* The problem is that for _PR_DCETHREADS, pthread_t is not a + * pointer, but a structure; so you can't easily print it... + */ + me ? &(me->id): 0L, me); +#elif defined(_PR_BTHREADS) + me, me); +#else + me ? me->id : 0L, me); +#endif + + va_start(ap, fmt); + nb = nb_tid + PR_vsnprintf(line+nb_tid, sizeof(line)-nb_tid-1, fmt, ap); + va_end(ap); + + /* + * Check if we might have run out of buffer space (in case we have a + * long line), and malloc a buffer just this once. + */ + if (nb == sizeof(line)-2) { + va_start(ap, fmt); + line_long = PR_vsmprintf(fmt, ap); + va_end(ap); + /* If this failed, we'll fall back to writing the truncated line. */ + } + + if (line_long) { + nb = strlen(line_long); + _PR_LOCK_LOG(); + if (logBuf != 0) { + _PUT_LOG(logFile, logBuf, logp - logBuf); + logp = logBuf; + } + /* Write out the thread id and the malloc'ed buffer. */ + _PUT_LOG(logFile, line, nb_tid); + _PUT_LOG(logFile, line_long, nb); + /* Ensure there is a trailing newline. */ + if (!nb || (line_long[nb-1] != '\n')) { + char eol[2]; + eol[0] = '\n'; + eol[1] = '\0'; + _PUT_LOG(logFile, eol, 1); + } + _PR_UNLOCK_LOG(); + PR_smprintf_free(line_long); + } else { + /* Ensure there is a trailing newline. */ + if (nb && (line[nb-1] != '\n')) { + line[nb++] = '\n'; + line[nb] = '\0'; + } + _PR_LOCK_LOG(); + if (logBuf == 0) { + _PUT_LOG(logFile, line, nb); + } else { + /* If nb can't fit into logBuf, write out logBuf first. */ + if (logp + nb > logEndp) { + _PUT_LOG(logFile, logBuf, logp - logBuf); + logp = logBuf; + } + /* nb is guaranteed to fit into logBuf. */ + memcpy(logp, line, nb); + logp += nb; + } + _PR_UNLOCK_LOG(); + } + PR_LogFlush(); +} + +PR_IMPLEMENT(void) PR_LogFlush(void) +{ + if (logBuf && logFile) { + _PR_LOCK_LOG(); + if (logp > logBuf) { + _PUT_LOG(logFile, logBuf, logp - logBuf); + logp = logBuf; + } + _PR_UNLOCK_LOG(); + } +} + +PR_IMPLEMENT(void) PR_Abort(void) +{ + PR_LogPrint("Aborting"); + abort(); +} + +#if defined(XP_OS2) +/* + * Added definitions for DebugBreak() for 2 different OS/2 compilers. + * Doing the int3 on purpose for Visual Age so that a developer can + * step over the instruction if so desired. Not always possible if + * trapping due to exception handling IBM-AKR + */ +#if defined(XP_OS2_VACPP) +#include +static void DebugBreak(void) { _interrupt(3); } +#elif defined(XP_OS2_EMX) +static void DebugBreak(void) { asm("int $3"); } +#else +static void DebugBreak(void) { } +#endif +#endif /* XP_OS2 */ + +PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln) +{ + PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln); +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) + fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); +#endif +#ifdef XP_MAC + dprintf("Assertion failure: %s, at %s:%d\n", s, file, ln); +#endif +#if defined(WIN32) || defined(XP_OS2) + DebugBreak(); +#endif +#ifndef XP_MAC + abort(); +#endif +} + +#ifdef XP_MAC +PR_IMPLEMENT(void) PR_Init_Log(void) +{ + _PR_InitLog(); +} +#endif diff --git a/nsprpub/pr/src/io/prmapopt.c b/nsprpub/pr/src/io/prmapopt.c new file mode 100644 index 00000000000..e4811e5725f --- /dev/null +++ b/nsprpub/pr/src/io/prmapopt.c @@ -0,0 +1,517 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file defines _PR_MapOptionName(). The purpose of putting + * _PR_MapOptionName() in a separate file is to work around a Winsock + * header file problem on Windows NT. + * + * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order + * to use Service Pack 3 extensions), windows.h includes winsock2.h + * (instead of winsock.h), which doesn't define many socket options + * defined in winsock.h. + * + * We need the socket options defined in winsock.h. So this file + * includes winsock.h, with _WIN32_WINNT undefined. + */ + +#if defined(WINNT) || defined(__MINGW32__) +#include +#endif + +/* MinGW doesn't define these in its winsock.h. */ +#ifdef __MINGW32__ +#ifndef IP_TTL +#define IP_TTL 7 +#endif +#ifndef IP_TOS +#define IP_TOS 8 +#endif +#endif + +#include "primpl.h" + +#if defined(NEXTSTEP) +/* NEXTSTEP is special: this must come before netinet/tcp.h. */ +#include /* n_short, n_long, n_time */ +#endif + +#if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION)) +#include /* TCP_NODELAY, TCP_MAXSEG */ +#endif + +#ifndef _PR_PTHREADS + +PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data) +{ + PRStatus rv; + PRInt32 length; + PRInt32 level, name; + + /* + * PR_SockOpt_Nonblocking is a special case that does not + * translate to a getsockopt() call + */ + if (PR_SockOpt_Nonblocking == data->option) + { + data->value.non_blocking = fd->secret->nonblocking; + return PR_SUCCESS; + } + + rv = _PR_MapOptionName(data->option, &level, &name); + if (PR_SUCCESS == rv) + { + switch (data->option) + { + case PR_SockOpt_Linger: + { +#if !defined(XP_BEOS) || defined(BONE_VERSION) + struct linger linger; + length = sizeof(linger); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char *) &linger, &length); + if (PR_SUCCESS == rv) + { + PR_ASSERT(sizeof(linger) == length); + data->value.linger.polarity = + (linger.l_onoff) ? PR_TRUE : PR_FALSE; + data->value.linger.linger = + PR_SecondsToInterval(linger.l_linger); + } + break; +#else + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +#endif + } + case PR_SockOpt_Reuseaddr: + case PR_SockOpt_Keepalive: + case PR_SockOpt_NoDelay: + case PR_SockOpt_Broadcast: + { +#ifdef WIN32 /* Winsock */ + BOOL value; +#else + PRIntn value; +#endif + length = sizeof(value); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&value, &length); + if (PR_SUCCESS == rv) + data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE; + break; + } + case PR_SockOpt_McastLoopback: + { +#ifdef WIN32 /* Winsock */ + BOOL bool; +#else + PRUint8 bool; +#endif + length = sizeof(bool); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&bool, &length); + if (PR_SUCCESS == rv) + data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE; + break; + } + case PR_SockOpt_RecvBufferSize: + case PR_SockOpt_SendBufferSize: + case PR_SockOpt_MaxSegment: + { + PRIntn value; + length = sizeof(value); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&value, &length); + if (PR_SUCCESS == rv) + data->value.recv_buffer_size = value; + break; + } + case PR_SockOpt_IpTimeToLive: + case PR_SockOpt_IpTypeOfService: + { + /* These options should really be an int (or PRIntn). */ + length = sizeof(PRUintn); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&data->value.ip_ttl, &length); + break; + } + case PR_SockOpt_McastTimeToLive: + { +#ifdef WIN32 /* Winsock */ + int ttl; +#else + PRUint8 ttl; +#endif + length = sizeof(ttl); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&ttl, &length); + if (PR_SUCCESS == rv) + data->value.mcast_ttl = ttl; + break; + } +#ifdef IP_ADD_MEMBERSHIP + case PR_SockOpt_AddMember: + case PR_SockOpt_DropMember: + { + struct ip_mreq mreq; + length = sizeof(mreq); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&mreq, &length); + if (PR_SUCCESS == rv) + { + data->value.add_member.mcaddr.inet.ip = + mreq.imr_multiaddr.s_addr; + data->value.add_member.ifaddr.inet.ip = + mreq.imr_interface.s_addr; + } + break; + } +#endif /* IP_ADD_MEMBERSHIP */ + case PR_SockOpt_McastInterface: + { + /* This option is a struct in_addr. */ + length = sizeof(data->value.mcast_if.inet.ip); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, + (char*)&data->value.mcast_if.inet.ip, &length); + break; + } + default: + PR_NOT_REACHED("Unknown socket option"); + break; + } + } + return rv; +} /* _PR_SocketGetSocketOption */ + +PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data) +{ + PRStatus rv; + PRInt32 level, name; + + /* + * PR_SockOpt_Nonblocking is a special case that does not + * translate to a setsockopt call. + */ + if (PR_SockOpt_Nonblocking == data->option) + { +#ifdef WINNT + PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE) + || (fd->secret->nonblocking == data->value.non_blocking)); + if (fd->secret->md.io_model_committed + && (fd->secret->nonblocking != data->value.non_blocking)) + { + /* + * On NT, once we have associated a socket with the io + * completion port, we can't disassociate it. So we + * can't change the nonblocking option of the socket + * afterwards. + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } +#endif + fd->secret->nonblocking = data->value.non_blocking; + return PR_SUCCESS; + } + + rv = _PR_MapOptionName(data->option, &level, &name); + if (PR_SUCCESS == rv) + { + switch (data->option) + { + case PR_SockOpt_Linger: + { +#if !defined(XP_BEOS) || defined(BONE_VERSION) + struct linger linger; + linger.l_onoff = data->value.linger.polarity; + linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger); + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&linger, sizeof(linger)); + break; +#else + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +#endif + } + case PR_SockOpt_Reuseaddr: + case PR_SockOpt_Keepalive: + case PR_SockOpt_NoDelay: + case PR_SockOpt_Broadcast: + { +#ifdef WIN32 /* Winsock */ + BOOL value; +#else + PRIntn value; +#endif + value = (data->value.reuse_addr) ? 1 : 0; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&value, sizeof(value)); + break; + } + case PR_SockOpt_McastLoopback: + { +#ifdef WIN32 /* Winsock */ + BOOL bool; +#else + PRUint8 bool; +#endif + bool = data->value.mcast_loopback ? 1 : 0; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&bool, sizeof(bool)); + break; + } + case PR_SockOpt_RecvBufferSize: + case PR_SockOpt_SendBufferSize: + case PR_SockOpt_MaxSegment: + { + PRIntn value = data->value.recv_buffer_size; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&value, sizeof(value)); + break; + } + case PR_SockOpt_IpTimeToLive: + case PR_SockOpt_IpTypeOfService: + { + /* These options should really be an int (or PRIntn). */ + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn)); + break; + } + case PR_SockOpt_McastTimeToLive: + { +#ifdef WIN32 /* Winsock */ + int ttl; +#else + PRUint8 ttl; +#endif + ttl = data->value.mcast_ttl; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&ttl, sizeof(ttl)); + break; + } +#ifdef IP_ADD_MEMBERSHIP + case PR_SockOpt_AddMember: + case PR_SockOpt_DropMember: + { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = + data->value.add_member.mcaddr.inet.ip; + mreq.imr_interface.s_addr = + data->value.add_member.ifaddr.inet.ip; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&mreq, sizeof(mreq)); + break; + } +#endif /* IP_ADD_MEMBERSHIP */ + case PR_SockOpt_McastInterface: + { + /* This option is a struct in_addr. */ + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&data->value.mcast_if.inet.ip, + sizeof(data->value.mcast_if.inet.ip)); + break; + } + default: + PR_NOT_REACHED("Unknown socket option"); + break; + } + } + return rv; +} /* _PR_SocketSetSocketOption */ + +#endif /* ! _PR_PTHREADS */ + +/* + ********************************************************************* + ********************************************************************* + ** + ** Make sure that the following is at the end of this file, + ** because we will be playing with macro redefines. + ** + ********************************************************************* + ********************************************************************* + */ + +#if defined(VMS) +/* +** Sad but true. The DEC C header files define the following socket options +** differently to what UCX is expecting. The values that UCX expects are +** defined in SYS$LIBRARY:UCX$INETDEF.H. We redefine them here to the values +** that UCX expects. Note that UCX V4.x will only accept these values while +** UCX V5.x will accept either. So in theory this hack can be removed once +** UCX V5 is the minimum. +*/ +#undef IP_MULTICAST_IF +#undef IP_MULTICAST_TTL +#undef IP_MULTICAST_LOOP +#undef IP_ADD_MEMBERSHIP +#undef IP_DROP_MEMBERSHIP +#include +#define IP_MULTICAST_IF UCX$C_IP_MULTICAST_IF +#define IP_MULTICAST_TTL UCX$C_IP_MULTICAST_TTL +#define IP_MULTICAST_LOOP UCX$C_IP_MULTICAST_LOOP +#define IP_ADD_MEMBERSHIP UCX$C_IP_ADD_MEMBERSHIP +#define IP_DROP_MEMBERSHIP UCX$C_IP_DROP_MEMBERSHIP +#endif + +/* + * Not every platform has all the socket options we want to + * support. Some older operating systems such as SunOS 4.1.3 + * don't have the IP multicast socket options. Win32 doesn't + * have TCP_MAXSEG. + * + * To deal with this problem, we define the missing socket + * options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with + * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not + * available on the platform is requested. + */ + +/* + * Sanity check. SO_LINGER and TCP_NODELAY should be available + * on all platforms. Just to make sure we have included the + * appropriate header files. Then any undefined socket options + * are really missing. + */ + +#if !defined(SO_LINGER) +#error "SO_LINGER is not defined" +#endif + +/* + * Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined + * in + */ +#if !defined(NCR) +#if !defined(TCP_NODELAY) +#error "TCP_NODELAY is not defined" +#endif +#endif + +/* + * Make sure the value of _PR_NO_SUCH_SOCKOPT is not + * a valid socket option. + */ +#define _PR_NO_SUCH_SOCKOPT -1 + +#ifndef SO_KEEPALIVE +#define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef SO_SNDBUF +#define SO_SNDBUF _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef SO_RCVBUF +#define SO_RCVBUF _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_MULTICAST_IF /* set/get IP multicast interface */ +#define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */ +#define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */ +#define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */ +#define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */ +#define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_TTL /* set/get IP Time To Live */ +#define IP_TTL _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_TOS /* set/get IP Type Of Service */ +#define IP_TOS _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef TCP_NODELAY /* don't delay to coalesce data */ +#define TCP_NODELAY _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef TCP_MAXSEG /* maxumum segment size for tcp */ +#define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef SO_BROADCAST /* enable broadcast on udp sockets */ +#define SO_BROADCAST _PR_NO_SUCH_SOCKOPT +#endif + +PRStatus _PR_MapOptionName( + PRSockOption optname, PRInt32 *level, PRInt32 *name) +{ + static PRInt32 socketOptions[PR_SockOpt_Last] = + { + 0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF, + IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, + IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP, + TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST + }; + static PRInt32 socketLevels[PR_SockOpt_Last] = + { + 0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, + IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, + IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, + IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET + }; + + if ((optname < PR_SockOpt_Linger) + || (optname >= PR_SockOpt_Last)) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT) + { + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; + } + *name = socketOptions[optname]; + *level = socketLevels[optname]; + return PR_SUCCESS; +} /* _PR_MapOptionName */ diff --git a/nsprpub/pr/src/io/prmmap.c b/nsprpub/pr/src/io/prmmap.c new file mode 100644 index 00000000000..e5c1e5dc7a7 --- /dev/null +++ b/nsprpub/pr/src/io/prmmap.c @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + ********************************************************************* + * + * Memory-mapped files + * + ********************************************************************* + */ + +#include "primpl.h" + +PR_IMPLEMENT(PRFileMap *) PR_CreateFileMap( + PRFileDesc *fd, + PRInt64 size, + PRFileMapProtect prot) +{ + PRFileMap *fmap; + + PR_ASSERT(prot == PR_PROT_READONLY || prot == PR_PROT_READWRITE + || prot == PR_PROT_WRITECOPY); + fmap = PR_NEWZAP(PRFileMap); + if (NULL == fmap) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + fmap->fd = fd; + fmap->prot = prot; + if (_PR_MD_CREATE_FILE_MAP(fmap, size) == PR_SUCCESS) { + return fmap; + } else { + PR_DELETE(fmap); + return NULL; + } +} + +PR_IMPLEMENT(PRInt32) PR_GetMemMapAlignment(void) +{ + return _PR_MD_GET_MEM_MAP_ALIGNMENT(); +} + +PR_IMPLEMENT(void *) PR_MemMap( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len) +{ + return _PR_MD_MEM_MAP(fmap, offset, len); +} + +PR_IMPLEMENT(PRStatus) PR_MemUnmap(void *addr, PRUint32 len) +{ + return _PR_MD_MEM_UNMAP(addr, len); +} + +PR_IMPLEMENT(PRStatus) PR_CloseFileMap(PRFileMap *fmap) +{ + return _PR_MD_CLOSE_FILE_MAP(fmap); +} diff --git a/nsprpub/pr/src/io/prmwait.c b/nsprpub/pr/src/io/prmwait.c new file mode 100644 index 00000000000..6b3c46a34b1 --- /dev/null +++ b/nsprpub/pr/src/io/prmwait.c @@ -0,0 +1,1491 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include "pprmwait.h" + +#define _MW_REHASH_MAX 11 + +static PRLock *mw_lock = NULL; +static _PRGlobalState *mw_state = NULL; + +static PRIntervalTime max_polling_interval; + +#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) +{ + PRIntervalTime now; + PRIntervalTime timeout; + PRCList *head; + TimerEvent *timer; + + PR_Lock(tm_vars.ml); + while (1) + { + 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); +} + +static TimerEvent *CreateTimer( + PRIntervalTime timeout, + void (*func)(void *), + void *arg) +{ + TimerEvent *timer; + PRCList *links, *tail; + TimerEvent *elem; + + 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) + { + break; + } + 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; + } + PR_INIT_CLIST(&tm_vars.timer_queue); + 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; + } + 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; +} + +#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(LONG) == 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 */ + +void _PR_CleanupMW(void) +{ + PR_DestroyLock(mw_lock); + mw_lock = NULL; + if (mw_state->group) { + PR_DestroyWaitGroup(mw_state->group); + /* mw_state->group is set to NULL as a side effect. */ + } + PR_DELETE(mw_state); +} /* _PR_CleanupMW */ + +static PRWaitGroup *MW_Init2(void) +{ + PRWaitGroup *group = mw_state->group; /* it's the null group */ + if (NULL == group) /* there is this special case */ + { + group = PR_CreateWaitGroup(_PR_DEFAULT_HASH_LENGTH); + if (NULL == group) goto failed_alloc; + PR_Lock(mw_lock); + if (NULL == mw_state->group) + { + mw_state->group = group; + group = NULL; + } + PR_Unlock(mw_lock); + if (group != NULL) (void)PR_DestroyWaitGroup(group); + group = mw_state->group; /* somebody beat us to it */ + } +failed_alloc: + return group; /* whatever */ +} /* MW_Init2 */ + +static _PR_HashStory MW_AddHashInternal(PRRecvWait *desc, _PRWaiterHash *hash) +{ + /* + ** The entries are put in the table using the fd (PRFileDesc*) of + ** the receive descriptor as the key. This allows us to locate + ** the appropriate entry aqain when the poll operation finishes. + ** + ** The pointer to the file descriptor object is first divided by + ** the natural alignment of a pointer in the belief that object + ** 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 _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 = _MW_REHASH_MAX; + PRRecvWait **waiter; + PRUintn hidx = _MW_HASH(desc->fd, hash->length); + PRUintn hoffset = 0; + + while (rehash-- > 0) + { + waiter = &hash->recv_wait; + if (NULL == waiter[hidx]) + { + waiter[hidx] = desc; + hash->count += 1; +#if 0 + printf("Adding 0x%x->0x%x ", desc, desc->fd); + printf( + "table[%u:%u:*%u]: 0x%x->0x%x\n", + hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd); +#endif + return _prmw_success; + } + if (desc == waiter[hidx]) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); /* desc already in table */ + return _prmw_error; + } +#if 0 + printf("Failing 0x%x->0x%x ", desc, desc->fd); + printf( + "table[*%u:%u:%u]: 0x%x->0x%x\n", + hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd); +#endif + if (0 == hoffset) + { + hoffset = _MW_HASH2(desc->fd, hash->length); + PR_ASSERT(0 != hoffset); + } + hidx = (hidx + hoffset) % (hash->length); + } + return _prmw_rehash; +} /* MW_AddHashInternal */ + +static _PR_HashStory MW_ExpandHashInternal(PRWaitGroup *group) +{ + PRRecvWait **desc; + PRUint32 pidx, length; + _PRWaiterHash *newHash, *oldHash = group->waiter; + PRBool retry; + _PR_HashStory hrv; + + static const PRInt32 prime_number[] = { + _PR_DEFAULT_HASH_LENGTH, 179, 521, 907, 1427, + 2711, 3917, 5021, 8219, 11549, 18911, 26711, 33749, 44771}; + PRUintn primes = (sizeof(prime_number) / sizeof(PRInt32)); + + /* look up the next size we'd like to use for the hash table */ + for (pidx = 0; pidx < primes; ++pidx) + { + if (prime_number[pidx] == oldHash->length) + { + break; + } + } + /* table size must be one of the prime numbers */ + PR_ASSERT(pidx < primes); + + /* if pidx == primes - 1, we can't expand the table any more */ + while (pidx < primes - 1) + { + /* next size */ + ++pidx; + length = prime_number[pidx]; + + /* 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; + retry = PR_FALSE; + for (desc = &oldHash->recv_wait; + newHash->count < oldHash->count; ++desc) + { + PR_ASSERT(desc < &oldHash->recv_wait + oldHash->length); + if (NULL != *desc) + { + hrv = MW_AddHashInternal(*desc, newHash); + PR_ASSERT(_prmw_error != hrv); + if (_prmw_success != hrv) + { + PR_DELETE(newHash); + retry = PR_TRUE; + break; + } + } + } + if (retry) continue; + + PR_DELETE(group->waiter); + group->waiter = newHash; + group->p_timestamp += 1; + return _prmw_success; + } + + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return _prmw_error; /* we're hosed */ +} /* MW_ExpandHashInternal */ + +#ifndef WINNT +static void _MW_DoneInternal( + PRWaitGroup *group, PRRecvWait **waiter, PRMWStatus outcome) +{ + /* + ** Add this receive wait object to the list of finished I/O + ** operations for this particular group. If there are other + ** threads waiting on the group, notify one. If not, arrange + ** for this thread to return. + */ + +#if 0 + printf("Removing 0x%x->0x%x\n", *waiter, (*waiter)->fd); +#endif + (*waiter)->outcome = outcome; + PR_APPEND_LINK(&((*waiter)->internal), &group->io_ready); + PR_NotifyCondVar(group->io_complete); + PR_ASSERT(0 != group->waiter->count); + group->waiter->count -= 1; + *waiter = NULL; +} /* _MW_DoneInternal */ +#endif /* WINNT */ + +static PRRecvWait **_MW_LookupInternal(PRWaitGroup *group, PRFileDesc *fd) +{ + /* + ** Find the receive wait object corresponding to the file descriptor. + ** Only search the wait group specified. + */ + PRRecvWait **desc; + PRIntn rehash = _MW_REHASH_MAX; + _PRWaiterHash *hash = group->waiter; + PRUintn hidx = _MW_HASH(fd, hash->length); + PRUintn hoffset = 0; + + while (rehash-- > 0) + { + desc = (&hash->recv_wait) + hidx; + if ((*desc != NULL) && ((*desc)->fd == fd)) return desc; + if (0 == hoffset) + { + hoffset = _MW_HASH2(fd, hash->length); + PR_ASSERT(0 != hoffset); + } + hidx = (hidx + hoffset) % (hash->length); + } + return NULL; +} /* _MW_LookupInternal */ + +#ifndef WINNT +static PRStatus _MW_PollInternal(PRWaitGroup *group) +{ + PRRecvWait **waiter; + PRStatus rv = PR_FAILURE; + PRInt32 count, count_ready; + PRIntervalTime polling_interval; + + group->poller = PR_GetCurrentThread(); + + while (PR_TRUE) + { + PRIntervalTime now, since_last_poll; + 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? + */ + + while (group->polling_count < group->waiter->count) + { + 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) + { + 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; + } + + now = PR_IntervalNow(); + polling_interval = max_polling_interval; + since_last_poll = now - group->last_poll; + + 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 ((PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout) + && (since_last_poll >= (*waiter)->timeout)) + _MW_DoneInternal(group, waiter, PR_MW_TIMEOUT); + else + { + if (PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout) + { + (*waiter)->timeout -= since_last_poll; + 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; +#if 0 + printf( + "Polling 0x%x[%d]: [fd: 0x%x, tmo: %u]\n", + poll_list, count, poll_list->fd, (*waiter)->timeout); +#endif + poll_list += 1; + count += 1; + } + } + } + + PR_ASSERT(count == group->waiter->count); + + /* + ** 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; + + PR_Unlock(group->ml); + + count_ready = PR_Poll(group->polling_list, count, polling_interval); + + PR_Lock(group->ml); + + 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) + { + for (poll_list = group->polling_list; count > 0; + poll_list++, count--) + { + 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); + } + } + } + /* + ** If there are no more threads waiting for completion, + ** we need to return. + ** This thread was "borrowed" to do the polling, but it really + ** belongs to the client. + */ + 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) +{ + PRMWGroupState rv = group->state; + /* + ** Looking at the group's fields is safe because + ** once the group's state is no longer running, it + ** cannot revert and there is a safe check on entry + ** to make sure no more threads are made to wait. + */ + if ((_prmw_stopping == rv) + && (0 == group->waiting_threads)) + { + rv = group->state = _prmw_stopped; + PR_NotifyCondVar(group->mw_manage); + } + return rv; +} /* MW_TestForShutdownInternal */ + +#ifndef WINNT +static void _MW_InitialRecv(PRCList *io_ready) +{ + PRRecvWait *desc = (PRRecvWait*)io_ready; + if ((NULL == desc->buffer.start) + || (0 == desc->buffer.length)) + desc->bytesRecv = 0; + else + { + desc->bytesRecv = (desc->fd->methods->recv)( + desc->fd, desc->buffer.start, + desc->buffer.length, 0, desc->timeout); + if (desc->bytesRecv < 0) /* SetError should already be there */ + 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((LONG *)&desc->outcome, + (LONG)PR_MW_TIMEOUT, (LONG)PR_MW_PENDING) != (LONG)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 */ + +/******************************************************************/ +/******************************************************************/ +/********************** The public API portion ********************/ +/******************************************************************/ +/******************************************************************/ +PR_IMPLEMENT(PRStatus) PR_AddWaitFileDesc( + PRWaitGroup *group, PRRecvWait *desc) +{ + _PR_HashStory hrv; + PRStatus rv = PR_FAILURE; +#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); + + desc->outcome = PR_MW_PENDING; /* nice, well known value */ + desc->bytesRecv = 0; /* likewise, though this value is ambiguious */ + + PR_Lock(group->ml); + + if (_prmw_running != group->state) + { + /* Not allowed to add after cancelling the group */ + desc->outcome = PR_MW_INTERRUPT; + PR_SetError(PR_INVALID_STATE_ERROR, 0); + 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 + ** of the timing interval. As long as the list doesn't go empty, + ** it will maintain itself. + */ + if (0 == group->waiter->count) + group->last_poll = PR_IntervalNow(); + + do + { + hrv = MW_AddHashInternal(desc, group->waiter); + if (_prmw_rehash != hrv) break; + hrv = MW_ExpandHashInternal(group); /* gruesome */ + 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; + 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((LONG *)&desc->outcome, + (LONG)PR_MW_FAILURE, (LONG)PR_MW_PENDING) + == (LONG)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) +{ + PRCList *io_ready = NULL; +#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); + + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto invalid_state; + } + + 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); + if (_PR_PENDING_INTERRUPT(me)) { + PR_REMOVE_LINK(&me->waitQLinks); + _PR_MD_UNLOCK(&group->mdlock); + me->flags &= ~_PR_INTERRUPT; + me->io_suspended = PR_FALSE; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + goto aborted; + } + } + 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 + { + /* + ** If the I/O ready list isn't empty, have this thread + ** return with the first receive wait object that's available. + */ + if (PR_CLIST_IS_EMPTY(&group->io_ready)) + { + /* + ** Is there a polling thread yet? If not, grab this thread + ** and use it. + */ + if (NULL == group->poller) + { + /* + ** This thread will stay do polling until it becomes the only one + ** left to service a completion. Then it will return and there will + ** be none left to actually poll or to run completions. + ** + ** The polling function should only return w/ failure or + ** with some I/O ready. + */ + if (PR_FAILURE == _MW_PollInternal(group)) goto failed_poll; + } + 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; + do + { + 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; + } while (PR_CLIST_IS_EMPTY(&group->io_ready)); + + /* + ** 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); + +failed_poll: + +#endif + +aborted: + + 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(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; + case PR_MW_INTERRUPT: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + break; + default: break; + } +#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 (NULL == group) group = mw_state->group; + PR_ASSERT(NULL != group); + if (NULL == group) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + PR_Lock(group->ml); + + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + rv = PR_FAILURE; + goto unlock; + } + +#ifdef WINNT + if (InterlockedCompareExchange((LONG *)&desc->outcome, + (LONG)PR_MW_INTERRUPT, (LONG)PR_MW_PENDING) == (LONG)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 unlock; + } + 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 */ + _MW_DoneInternal(group, recv_wait, PR_MW_INTERRUPT); + goto unlock; + } + if (!PR_CLIST_IS_EMPTY(&group->io_ready)) + { + /* is it already complete? */ + PRCList *head = PR_LIST_HEAD(&group->io_ready); + do + { + PRRecvWait *done = (PRRecvWait*)head; + if (done == desc) goto unlock; + head = PR_NEXT_LINK(head); + } while (head != &group->io_ready); + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + +#endif +unlock: + PR_Unlock(group->ml); + return rv; +} /* PR_CancelWaitFileDesc */ + +PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group) +{ + PRRecvWait **desc; + PRRecvWait *recv_wait = 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) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + + PR_Lock(group->ml); + if (_prmw_stopped != group->state) + { + if (_prmw_running == group->state) + 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); + } + +#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 (InterlockedCompareExchange((LONG *)&(*desc)->outcome, + (LONG)PR_MW_INTERRUPT, (LONG)PR_MW_PENDING) + == (LONG)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); + } + } + } + } + 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)) + PR_SetError(PR_GROUP_EMPTY_ERROR, 0); + else + { + 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; + 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 + recv_wait = (PRRecvWait*)head; + } +#ifdef WINNT +invalid_arg: + _PR_MD_UNLOCK(&group->mdlock); +#endif + PR_Unlock(group->ml); + + return recv_wait; +} /* PR_CancelWaitGroup */ + +PR_IMPLEMENT(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size /* ignored */) +{ +#ifdef XP_MAC +#pragma unused (size) +#endif + PRWaitGroup *wg; + + 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; + wg->io_taken = PR_NewCondVar(wg->ml); + if (NULL == wg->io_taken) goto failed_cvar0; + wg->io_complete = PR_NewCondVar(wg->ml); + if (NULL == wg->io_complete) goto failed_cvar1; + wg->new_business = PR_NewCondVar(wg->ml); + if (NULL == wg->new_business) goto failed_cvar2; + wg->mw_manage = PR_NewCondVar(wg->ml); + if (NULL == wg->mw_manage) goto failed_cvar3; + + PR_INIT_CLIST(&wg->group_link); + PR_INIT_CLIST(&wg->io_ready); + + /* the waiters sequence */ + wg->waiter = (_PRWaiterHash*)PR_CALLOC( + sizeof(_PRWaiterHash) + + (_PR_DEFAULT_HASH_LENGTH * sizeof(PRRecvWait*))); + 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); + return wg; + +failed_waiter: + PR_DestroyCondVar(wg->mw_manage); +failed_cvar3: + PR_DestroyCondVar(wg->new_business); +failed_cvar2: + 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; +} /* MW_CreateWaitGroup */ + +PR_IMPLEMENT(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group) +{ + PRStatus rv = PR_SUCCESS; + if (NULL == group) group = mw_state->group; + PR_ASSERT(NULL != group); + if (NULL != group) + { + PR_Lock(group->ml); + if ((group->waiting_threads == 0) + && (group->waiter->count == 0) + && PR_CLIST_IS_EMPTY(&group->io_ready)) + { + 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); + PR_DestroyLock(group->ml); + 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/nsprpub/pr/src/io/prpolevt.c b/nsprpub/pr/src/io/prpolevt.c new file mode 100644 index 00000000000..de5f991c56d --- /dev/null +++ b/nsprpub/pr/src/io/prpolevt.c @@ -0,0 +1,530 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + ********************************************************************* + * + * Pollable events + * + * Pollable events are implemented using layered I/O. The only + * I/O methods that are implemented for pollable events are poll + * and close. No other methods can be invoked on a pollable + * event. + * + * A pipe or socket pair is created and the pollable event layer + * is pushed onto the read end. A pointer to the write end is + * saved in the PRFilePrivate structure of the pollable event. + * + ********************************************************************* + */ + +#include "prinit.h" +#include "prio.h" +#include "prmem.h" +#include "prerror.h" +#include "prlog.h" + +#ifdef VMS + +/* + * On OpenVMS we use an event flag instead of a pipe or a socket since + * event flags are much more efficient on OpenVMS. + */ +#include "pprio.h" +#include +#include +#include + +PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void) +{ + unsigned int status; + int flag = -1; + PRFileDesc *event; + + /* + ** Allocate an event flag and clear it. + */ + status = lib$get_ef(&flag); + if ((!$VMS_STATUS_SUCCESS(status)) || (flag == -1)) { + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, status); + return NULL; + } + sys$clref(flag); + + /* + ** Give NSPR the event flag's negative value. We do this because our + ** select interprets a negative fd as an event flag rather than a + ** regular file fd. + */ + event = PR_CreateSocketPollFd(-flag); + if (NULL == event) { + lib$free_ef(&flag); + return NULL; + } + + return event; +} + +PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event) +{ + int flag = -PR_FileDesc2NativeHandle(event); + PR_DestroySocketPollFd(event); + lib$free_ef(&flag); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event) +{ + /* + ** Just set the event flag. + */ + unsigned int status; + status = sys$setef(-PR_FileDesc2NativeHandle(event)); + if (!$VMS_STATUS_SUCCESS(status)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, status); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event) +{ + /* + ** Just clear the event flag. + */ + unsigned int status; + status = sys$clref(-PR_FileDesc2NativeHandle(event)); + if (!$VMS_STATUS_SUCCESS(status)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, status); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#elif defined (XP_MAC) + +#include "primpl.h" + +/* + * On Mac, local sockets cannot be used, because the networking stack + * closes them when the machine goes to sleep. Instead, we'll use a simple + * flag. + */ + + +/* + * PRFilePrivate structure for the NSPR pollable events layer + */ +typedef struct PRPollableDesc { + PRBool gotEvent; + PRThread *pollingThread; +} PRPollableDesc; + +static PRStatus PR_CALLBACK _pr_MacPolEvtClose(PRFileDesc *fd); + +static PRInt16 PR_CALLBACK _pr_MacPolEvtPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); + +static PRIOMethods _pr_mac_polevt_methods = { + PR_DESC_LAYERED, + _pr_MacPolEvtClose, + (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, + _pr_MacPolEvtPoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRDescIdentity _pr_mac_polevt_id; +static PRCallOnceType _pr_mac_polevt_once_control; +static PRStatus PR_CALLBACK _pr_MacPolEvtInit(void); + +static PRInt16 PR_CALLBACK _pr_MacPolEvtPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + PRPollableDesc *pollDesc = (PRPollableDesc *)fd->secret; + PR_ASSERT(pollDesc); + + // set the current thread so that we can wake up the poll thread + pollDesc->pollingThread = PR_GetCurrentThread(); + + if ((in_flags & PR_POLL_READ) && pollDesc->gotEvent) + *out_flags = PR_POLL_READ; + else + *out_flags = 0; + return pollDesc->gotEvent ? 1 : 0; +} + +static PRStatus PR_CALLBACK _pr_MacPolEvtInit(void) +{ + _pr_mac_polevt_id = PR_GetUniqueIdentity("NSPR pollable events"); + if (PR_INVALID_IO_LAYER == _pr_mac_polevt_id) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK _pr_MacPolEvtClose(PRFileDesc *fd) +{ + PRPollableDesc *pollDesc = (PRPollableDesc *)fd->secret; + PR_ASSERT(NULL == fd->higher && NULL == fd->lower); + PR_ASSERT(pollDesc); + PR_DELETE(pollDesc); + fd->dtor(fd); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void) +{ + PRFileDesc *event; + PRPollableDesc *pollDesc; + + if (PR_CallOnce(&_pr_mac_polevt_once_control, _pr_MacPolEvtInit) == PR_FAILURE) { + return NULL; + } + + event = PR_CreateIOLayerStub(_pr_mac_polevt_id, &_pr_mac_polevt_methods); + if (NULL == event) { + return NULL; + } + + /* + ** Allocate an event flag and clear it. + */ + pollDesc = PR_NEW(PRPollableDesc); + if (!pollDesc) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + pollDesc->gotEvent = PR_FALSE; + pollDesc->pollingThread = NULL; + + event->secret = (PRFilePrivate*)pollDesc; + return event; + +errorExit: + + if (event) { + PR_DELETE(event->secret); + event->dtor(event); + } + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event) +{ + return PR_Close(event); +} + +/* from macsockotpt.c. I wish there was a cleaner way */ +extern void WakeUpNotifiedThread(PRThread *thread, OTResult result); + +PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event) +{ + PRPollableDesc *pollDesc = (PRPollableDesc *)event->secret; + PR_ASSERT(pollDesc); + PR_ASSERT(pollDesc->pollingThread->state != _PR_DEAD_STATE); + + if (pollDesc->pollingThread->state == _PR_DEAD_STATE) + return PR_FAILURE; + + pollDesc->gotEvent = PR_TRUE; + + if (pollDesc->pollingThread) + WakeUpNotifiedThread(pollDesc->pollingThread, noErr); + + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event) +{ + PRPollableDesc *pollDesc = (PRPollableDesc *)event->secret; + PRStatus status; + PR_ASSERT(pollDesc); + + /* + FIXME: Danger Will Robinson! + + The current implementation of PR_WaitForPollableEvent is somewhat + bogus; it makes the assumption that, in Mozilla, this will only + ever be called when PR_Poll has returned, telling us that an + event has been set. + */ + + PR_ASSERT(pollDesc->gotEvent); + + status = (pollDesc->gotEvent) ? PR_SUCCESS : PR_FAILURE; + pollDesc->gotEvent = PR_FALSE; + return status; +} + +#else /* VMS */ + +/* + * These internal functions are declared in primpl.h, + * but we can't include primpl.h because the definition + * of struct PRFilePrivate in this file (for the pollable + * event layer) will conflict with the definition of + * struct PRFilePrivate in primpl.h (for the NSPR layer). + */ +extern PRIntn _PR_InvalidInt(void); +extern PRInt64 _PR_InvalidInt64(void); +extern PRStatus _PR_InvalidStatus(void); +extern PRFileDesc *_PR_InvalidDesc(void); + +/* + * PRFilePrivate structure for the NSPR pollable events layer + */ +struct PRFilePrivate { + PRFileDesc *writeEnd; /* the write end of the pipe/socketpair */ +}; + +static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd); + +static PRInt16 PR_CALLBACK _pr_PolEvtPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); + +static PRIOMethods _pr_polevt_methods = { + PR_DESC_LAYERED, + _pr_PolEvtClose, + (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, + _pr_PolEvtPoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRDescIdentity _pr_polevt_id; +static PRCallOnceType _pr_polevt_once_control; +static PRStatus PR_CALLBACK _pr_PolEvtInit(void); + +static PRInt16 PR_CALLBACK _pr_PolEvtPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags); +} + +static PRStatus PR_CALLBACK _pr_PolEvtInit(void) +{ + _pr_polevt_id = PR_GetUniqueIdentity("NSPR pollable events"); + if (PR_INVALID_IO_LAYER == _pr_polevt_id) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#if !defined(XP_UNIX) +#define USE_TCP_SOCKETPAIR +#endif + +PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void) +{ + PRFileDesc *event; + PRFileDesc *fd[2]; /* fd[0] is the read end; fd[1] is the write end */ +#ifdef USE_TCP_SOCKETPAIR + PRSocketOptionData socket_opt; + PRStatus rv; +#endif + + fd[0] = fd[1] = NULL; + + if (PR_CallOnce(&_pr_polevt_once_control, _pr_PolEvtInit) == PR_FAILURE) { + return NULL; + } + + event = PR_CreateIOLayerStub(_pr_polevt_id, &_pr_polevt_methods); + if (NULL == event) { + goto errorExit; + } + event->secret = PR_NEW(PRFilePrivate); + if (event->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) { + fd[0] = fd[1] = NULL; + goto errorExit; + } +#else + if (PR_NewTCPSocketPair(fd) == PR_FAILURE) { + fd[0] = fd[1] = NULL; + goto errorExit; + } + /* + * set the TCP_NODELAY option to reduce notification latency + */ + socket_opt.option = PR_SockOpt_NoDelay; + socket_opt.value.no_delay = PR_TRUE; + rv = PR_SetSocketOption(fd[1], &socket_opt); + PR_ASSERT(PR_SUCCESS == rv); +#endif + + event->secret->writeEnd = fd[1]; + if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, event) == PR_FAILURE) { + goto errorExit; + } + + return fd[0]; + +errorExit: + if (fd[0]) { + PR_Close(fd[0]); + PR_Close(fd[1]); + } + if (event) { + PR_DELETE(event->secret); + event->dtor(event); + } + return NULL; +} + +static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd) +{ + PRFileDesc *event; + + event = PR_PopIOLayer(fd, PR_TOP_IO_LAYER); + PR_ASSERT(NULL == event->higher && NULL == event->lower); + PR_Close(fd); + PR_Close(event->secret->writeEnd); + PR_DELETE(event->secret); + event->dtor(event); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event) +{ + return PR_Close(event); +} + +static const char magicChar = '\x38'; + +PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event) +{ + if (PR_Write(event->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->lower, 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; +} + +#endif /* VMS */ diff --git a/nsprpub/pr/src/io/prprf.c b/nsprpub/pr/src/io/prprf.c new file mode 100644 index 00000000000..fa444e2cdfb --- /dev/null +++ b/nsprpub/pr/src/io/prprf.c @@ -0,0 +1,1235 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Portable safe sprintf code. +** +** Author: Kipp E.B. Hickman +*/ +#include +#include +#include +#include +#include "primpl.h" +#include "prprf.h" +#include "prlong.h" +#include "prlog.h" +#include "prmem.h" + +/* +** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it) +*/ + +/* +** XXX This needs to be internationalized! +*/ + +typedef struct SprintfStateStr SprintfState; + +struct SprintfStateStr { + int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len); + + char *base; + char *cur; + PRUint32 maxlen; + + int (*func)(void *arg, const char *sp, PRUint32 len); + void *arg; +}; + +/* +** Numbered Argument +*/ +struct NumArg { + int type; /* type of the numbered argument */ + union { /* the numbered argument */ + int i; + unsigned int ui; + PRInt32 i32; + PRUint32 ui32; + PRInt64 ll; + PRUint64 ull; + double d; + const char *s; + int *ip; + } u; +}; + +#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgument array */ + + +#define TYPE_INT16 0 +#define TYPE_UINT16 1 +#define TYPE_INTN 2 +#define TYPE_UINTN 3 +#define TYPE_INT32 4 +#define TYPE_UINT32 5 +#define TYPE_INT64 6 +#define TYPE_UINT64 7 +#define TYPE_STRING 8 +#define TYPE_DOUBLE 9 +#define TYPE_INTSTR 10 +#define TYPE_UNKNOWN 20 + +#define FLAG_LEFT 0x1 +#define FLAG_SIGNED 0x2 +#define FLAG_SPACED 0x4 +#define FLAG_ZEROS 0x8 +#define FLAG_NEG 0x10 + +/* +** Fill into the buffer using the data in src +*/ +static int fill2(SprintfState *ss, const char *src, int srclen, int width, + int flags) +{ + char space = ' '; + int rv; + + width -= srclen; + if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */ + if (flags & FLAG_ZEROS) { + space = '0'; + } + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Copy out the source data */ + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + + if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */ + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + return 0; +} + +/* +** Fill a number. The order is: optional-sign zero-filling conversion-digits +*/ +static int fill_n(SprintfState *ss, const char *src, int srclen, int width, + int prec, int type, int flags) +{ + int zerowidth = 0; + int precwidth = 0; + int signwidth = 0; + int leftspaces = 0; + int rightspaces = 0; + int cvtwidth; + int rv; + char sign; + + if ((type & 1) == 0) { + if (flags & FLAG_NEG) { + sign = '-'; + signwidth = 1; + } else if (flags & FLAG_SIGNED) { + sign = '+'; + signwidth = 1; + } else if (flags & FLAG_SPACED) { + sign = ' '; + signwidth = 1; + } + } + cvtwidth = signwidth + srclen; + + if (prec > 0) { + if (prec > srclen) { + precwidth = prec - srclen; /* Need zero filling */ + cvtwidth += precwidth; + } + } + + if ((flags & FLAG_ZEROS) && (prec < 0)) { + if (width > cvtwidth) { + zerowidth = width - cvtwidth; /* Zero filling */ + cvtwidth += zerowidth; + } + } + + if (flags & FLAG_LEFT) { + if (width > cvtwidth) { + /* Space filling on the right (i.e. left adjusting) */ + rightspaces = width - cvtwidth; + } + } else { + if (width > cvtwidth) { + /* Space filling on the left (i.e. right adjusting) */ + leftspaces = width - cvtwidth; + } + } + while (--leftspaces >= 0) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + if (signwidth) { + rv = (*ss->stuff)(ss, &sign, 1); + if (rv < 0) { + return rv; + } + } + while (--precwidth >= 0) { + rv = (*ss->stuff)(ss, "0", 1); + if (rv < 0) { + return rv; + } + } + while (--zerowidth >= 0) { + rv = (*ss->stuff)(ss, "0", 1); + if (rv < 0) { + return rv; + } + } + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + while (--rightspaces >= 0) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + return 0; +} + +/* +** Convert a long into its printable form +*/ +static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix, + int type, int flags, const char *hexp) +{ + char cvtbuf[100]; + char *cvt; + int digits; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (num == 0)) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + cvt = cvtbuf + sizeof(cvtbuf); + digits = 0; + while (num) { + int digit = (((unsigned long)num) % radix) & 0xF; + *--cvt = hexp[digit]; + digits++; + num = (long)(((unsigned long)num) / radix); + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a 64-bit integer into its printable form +*/ +static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, int radix, + int type, int flags, const char *hexp) +{ + char cvtbuf[100]; + char *cvt; + int digits; + PRInt64 rad; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (LL_IS_ZERO(num))) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + LL_I2L(rad, radix); + cvt = cvtbuf + sizeof(cvtbuf); + digits = 0; + while (!LL_IS_ZERO(num)) { + PRInt32 digit; + PRInt64 quot, rem; + LL_UDIVMOD(", &rem, num, rad); + LL_L2I(digit, rem); + *--cvt = hexp[digit & 0xf]; + digits++; + num = quot; + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a double precision floating point number into its printable +** form. +** +** XXX stop using sprintf to convert floating point +*/ +static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1) +{ + char fin[20]; + char fout[300]; + int amount = fmt1 - fmt0; + + PR_ASSERT((amount > 0) && (amount < sizeof(fin))); + if (amount >= sizeof(fin)) { + /* Totally bogus % command to sprintf. Just ignore it */ + return 0; + } + memcpy(fin, fmt0, amount); + fin[amount] = 0; + + /* Convert floating point using the native sprintf code */ +#ifdef DEBUG + { + const char *p = fin; + while (*p) { + PR_ASSERT(*p != 'L'); + p++; + } + } +#endif + sprintf(fout, fin, d); + + /* + ** This assert will catch overflow's of fout, when building with + ** debugging on. At least this way we can track down the evil piece + ** of calling code and fix it! + */ + PR_ASSERT(strlen(fout) < sizeof(fout)); + + return (*ss->stuff)(ss, fout, strlen(fout)); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_s(SprintfState *ss, const char *str, int width, int prec, + int flags) +{ + int slen; + + if (prec == 0) + return 0; + + /* Limit string length by precision value */ + if (!str) { + str = "(null)"; + } + if (prec > 0) { + /* this is: slen = strnlen(str, prec); */ + register const char *s; + + for(s = str; prec && *s; s++, prec-- ) + ; + slen = s - str; + } else { + slen = strlen(str); + } + + /* and away we go */ + return fill2(ss, str, slen, width, flags); +} + +/* +** BuildArgArray stands for Numbered Argument list Sprintf +** for example, +** fmp = "%4$i, %2$d, %3s, %1d"; +** the number must start from 1, and no gap among them +*/ + +static struct NumArg* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArg* nasArray ) +{ + int number = 0, cn = 0, i; + const char* p; + char c; + struct NumArg* nas; + + + /* + ** first pass: + ** determine how many legal % I have got, then allocate space + */ + + p = fmt; + *rv = 0; + i = 0; + while( ( c = *p++ ) != 0 ){ + if( c != '%' ) + continue; + if( ( c = *p++ ) == '%' ) /* skip %% case */ + continue; + + while( c != 0 ){ + if( c > '9' || c < '0' ){ + if( c == '$' ){ /* numbered argument case */ + if( i > 0 ){ + *rv = -1; + return NULL; + } + number++; + } else{ /* non-numbered argument case */ + if( number > 0 ){ + *rv = -1; + return NULL; + } + i = 1; + } + break; + } + + c = *p++; + } + } + + if( number == 0 ){ + return NULL; + } + + + if( number > NAS_DEFAULT_NUM ){ + nas = (struct NumArg*)PR_MALLOC( number * sizeof( struct NumArg ) ); + if( !nas ){ + *rv = -1; + return NULL; + } + } else { + nas = nasArray; + } + + for( i = 0; i < number; i++ ){ + nas[i].type = TYPE_UNKNOWN; + } + + + /* + ** second pass: + ** set nas[].type + */ + + p = fmt; + while( ( c = *p++ ) != 0 ){ + if( c != '%' ) continue; + c = *p++; + if( c == '%' ) continue; + + cn = 0; + while( c && c != '$' ){ /* should imporve error check later */ + cn = cn*10 + c - '0'; + c = *p++; + } + + if( !c || cn < 1 || cn > number ){ + *rv = -1; + break; + } + + /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */ + cn--; + if( nas[cn].type != TYPE_UNKNOWN ) + continue; + + c = *p++; + + /* width */ + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } + + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + + /* precision */ + if (c == '.') { + c = *p++; + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } + + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + + /* size */ + nas[cn].type = TYPE_INTN; + if (c == 'h') { + nas[cn].type = TYPE_INT16; + c = *p++; + } else if (c == 'L') { + /* XXX not quite sure here */ + nas[cn].type = TYPE_INT64; + c = *p++; + } else if (c == 'l') { + nas[cn].type = TYPE_INT32; + c = *p++; + if (c == 'l') { + nas[cn].type = TYPE_INT64; + c = *p++; + } + } + + /* format */ + switch (c) { + case 'd': + case 'c': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + break; + + case 'e': + case 'f': + case 'g': + nas[ cn ].type = TYPE_DOUBLE; + break; + + case 'p': + /* XXX should use cpp */ + if (sizeof(void *) == sizeof(PRInt32)) { + nas[ cn ].type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + nas[ cn ].type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(PRIntn)) { + nas[ cn ].type = TYPE_UINTN; + } else { + nas[ cn ].type = TYPE_UNKNOWN; + } + break; + + case 'C': + case 'S': + case 'E': + case 'G': + /* XXX not supported I suppose */ + PR_ASSERT(0); + nas[ cn ].type = TYPE_UNKNOWN; + break; + + case 's': + nas[ cn ].type = TYPE_STRING; + break; + + case 'n': + nas[ cn ].type = TYPE_INTSTR; + break; + + default: + PR_ASSERT(0); + nas[ cn ].type = TYPE_UNKNOWN; + break; + } + + /* get a legal para. */ + if( nas[ cn ].type == TYPE_UNKNOWN ){ + *rv = -1; + break; + } + } + + + /* + ** third pass + ** fill the nas[cn].ap + */ + + if( *rv < 0 ){ + if( nas != nasArray ) + PR_DELETE( nas ); + return NULL; + } + + cn = 0; + while( cn < number ){ + if( nas[cn].type == TYPE_UNKNOWN ){ + cn++; + continue; + } + + switch( nas[cn].type ){ + case TYPE_INT16: + case TYPE_UINT16: + case TYPE_INTN: + nas[cn].u.i = va_arg( ap, int ); + break; + + case TYPE_UINTN: + nas[cn].u.ui = va_arg( ap, unsigned int ); + break; + + case TYPE_INT32: + nas[cn].u.i32 = va_arg( ap, PRInt32 ); + break; + + case TYPE_UINT32: + nas[cn].u.ui32 = va_arg( ap, PRUint32 ); + break; + + case TYPE_INT64: + nas[cn].u.ll = va_arg( ap, PRInt64 ); + break; + + case TYPE_UINT64: + nas[cn].u.ull = va_arg( ap, PRUint64 ); + break; + + case TYPE_STRING: + nas[cn].u.s = va_arg( ap, char* ); + break; + + case TYPE_INTSTR: + nas[cn].u.ip = va_arg( ap, int* ); + break; + + case TYPE_DOUBLE: + nas[cn].u.d = va_arg( ap, double ); + break; + + default: + if( nas != nasArray ) + PR_DELETE( nas ); + *rv = -1; + return NULL; + } + + cn++; + } + + + return nas; +} + +/* +** The workhorse sprintf code. +*/ +static int dosprintf(SprintfState *ss, const char *fmt, va_list ap) +{ + char c; + int flags, width, prec, radix, type; + union { + char ch; + int i; + long l; + PRInt64 ll; + double d; + const char *s; + int *ip; + } u; + const char *fmt0; + static char *hex = "0123456789abcdef"; + static char *HEX = "0123456789ABCDEF"; + char *hexp; + int rv, i; + struct NumArg* nas = NULL; + struct NumArg* nap; + struct NumArg nasArray[ NAS_DEFAULT_NUM ]; + char pattern[20]; + const char* dolPt = NULL; /* in "%4$.2f", dolPt will point to . */ + + + /* + ** build an argument array, IF the fmt is numbered argument + ** list style, to contain the Numbered Argument list pointers + */ + + nas = BuildArgArray( fmt, ap, &rv, nasArray ); + if( rv < 0 ){ + /* the fmt contains error Numbered Argument format, jliu@netscape.com */ + PR_ASSERT(0); + return rv; + } + + while ((c = *fmt++) != 0) { + if (c != '%') { + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + fmt0 = fmt - 1; + + /* + ** Gobble up the % format string. Hopefully we have handled all + ** of the strange cases! + */ + flags = 0; + c = *fmt++; + if (c == '%') { + /* quoting a % with %% */ + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + + if( nas != NULL ){ + /* the fmt contains the Numbered Arguments feature */ + i = 0; + while( c && c != '$' ){ /* should imporve error check later */ + i = ( i * 10 ) + ( c - '0' ); + c = *fmt++; + } + + if( nas[i-1].type == TYPE_UNKNOWN ){ + if( nas && ( nas != nasArray ) ) + PR_DELETE( nas ); + return -1; + } + + nap = &nas[i-1]; + dolPt = fmt; + c = *fmt++; + } + + /* + * Examine optional flags. Note that we do not implement the + * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is + * somewhat ambiguous and not ideal, which is perhaps why + * the various sprintf() implementations are inconsistent + * on this feature. + */ + while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { + if (c == '-') flags |= FLAG_LEFT; + if (c == '+') flags |= FLAG_SIGNED; + if (c == ' ') flags |= FLAG_SPACED; + if (c == '0') flags |= FLAG_ZEROS; + c = *fmt++; + } + if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED; + if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS; + + /* width */ + if (c == '*') { + c = *fmt++; + width = va_arg(ap, int); + } else { + width = 0; + while ((c >= '0') && (c <= '9')) { + width = (width * 10) + (c - '0'); + c = *fmt++; + } + } + + /* precision */ + prec = -1; + if (c == '.') { + c = *fmt++; + if (c == '*') { + c = *fmt++; + prec = va_arg(ap, int); + } else { + prec = 0; + while ((c >= '0') && (c <= '9')) { + prec = (prec * 10) + (c - '0'); + c = *fmt++; + } + } + } + + /* size */ + type = TYPE_INTN; + if (c == 'h') { + type = TYPE_INT16; + c = *fmt++; + } else if (c == 'L') { + /* XXX not quite sure here */ + type = TYPE_INT64; + c = *fmt++; + } else if (c == 'l') { + type = TYPE_INT32; + c = *fmt++; + if (c == 'l') { + type = TYPE_INT64; + c = *fmt++; + } + } + + /* format */ + hexp = hex; + switch (c) { + case 'd': case 'i': /* decimal/integer */ + radix = 10; + goto fetch_and_convert; + + case 'o': /* octal */ + radix = 8; + type |= 1; + goto fetch_and_convert; + + case 'u': /* unsigned decimal */ + radix = 10; + type |= 1; + goto fetch_and_convert; + + case 'x': /* unsigned hex */ + radix = 16; + type |= 1; + goto fetch_and_convert; + + case 'X': /* unsigned HEX */ + radix = 16; + hexp = HEX; + type |= 1; + goto fetch_and_convert; + + fetch_and_convert: + switch (type) { + case TYPE_INT16: + u.l = nas ? nap->u.i : va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINT16: + u.l = (nas ? nap->u.i : va_arg(ap, int)) & 0xffff; + goto do_long; + case TYPE_INTN: + u.l = nas ? nap->u.i : va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINTN: + u.l = (long)(nas ? nap->u.ui : va_arg(ap, unsigned int)); + goto do_long; + + case TYPE_INT32: + u.l = nas ? nap->u.i32 : va_arg(ap, PRInt32); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINT32: + u.l = (long)(nas ? nap->u.ui32 : va_arg(ap, PRUint32)); + do_long: + rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + + case TYPE_INT64: + u.ll = nas ? nap->u.ll : va_arg(ap, PRInt64); + if (!LL_GE_ZERO(u.ll)) { + LL_NEG(u.ll, u.ll); + flags |= FLAG_NEG; + } + goto do_longlong; + case TYPE_UINT64: + u.ll = nas ? nap->u.ull : va_arg(ap, PRUint64); + do_longlong: + rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + } + break; + + case 'e': + case 'E': + case 'f': + case 'g': + u.d = nas ? nap->u.d : va_arg(ap, double); + if( nas != NULL ){ + i = fmt - dolPt; + if( i < sizeof( pattern ) ){ + pattern[0] = '%'; + memcpy( &pattern[1], dolPt, i ); + rv = cvt_f(ss, u.d, pattern, &pattern[i+1] ); + } + } else + rv = cvt_f(ss, u.d, fmt0, fmt); + + if (rv < 0) { + return rv; + } + break; + + case 'c': + u.ch = nas ? nap->u.i : va_arg(ap, int); + if ((flags & FLAG_LEFT) == 0) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + } + rv = (*ss->stuff)(ss, &u.ch, 1); + if (rv < 0) { + return rv; + } + if (flags & FLAG_LEFT) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + } + break; + + case 'p': + if (sizeof(void *) == sizeof(PRInt32)) { + type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(int)) { + type = TYPE_UINTN; + } else { + PR_ASSERT(0); + break; + } + radix = 16; + goto fetch_and_convert; + +#if 0 + case 'C': + case 'S': + case 'E': + case 'G': + /* XXX not supported I suppose */ + PR_ASSERT(0); + break; +#endif + + case 's': + u.s = nas ? nap->u.s : va_arg(ap, const char*); + rv = cvt_s(ss, u.s, width, prec, flags); + if (rv < 0) { + return rv; + } + break; + + case 'n': + u.ip = nas ? nap->u.ip : va_arg(ap, int*); + if (u.ip) { + *u.ip = ss->cur - ss->base; + } + break; + + default: + /* Not a % token after all... skip it */ +#if 0 + PR_ASSERT(0); +#endif + rv = (*ss->stuff)(ss, "%", 1); + if (rv < 0) { + return rv; + } + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Stuff trailing NUL */ + rv = (*ss->stuff)(ss, "\0", 1); + + if( nas && ( nas != nasArray ) ){ + PR_DELETE( nas ); + } + + return rv; +} + +/************************************************************************/ + +static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len) +{ + int rv; + + rv = (*ss->func)(ss->arg, sp, len); + if (rv < 0) { + return rv; + } + ss->maxlen += len; + return 0; +} + +PR_IMPLEMENT(PRUint32) PR_sxprintf(PRStuffFunc func, void *arg, + const char *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + va_start(ap, fmt); + rv = PR_vsxprintf(func, arg, fmt, ap); + va_end(ap); + return rv; +} + +PR_IMPLEMENT(PRUint32) PR_vsxprintf(PRStuffFunc func, void *arg, + const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = FuncStuff; + ss.func = func; + ss.arg = arg; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + return (rv < 0) ? (PRUint32)-1 : ss.maxlen; +} + +/* +** Stuff routine that automatically grows the malloc'd output buffer +** before it overflows. +*/ +static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len) +{ + ptrdiff_t off; + char *newbase; + PRUint32 newlen; + + off = ss->cur - ss->base; + if (off + len >= ss->maxlen) { + /* Grow the buffer */ + newlen = ss->maxlen + ((len > 32) ? len : 32); + if (ss->base) { + newbase = (char*) PR_REALLOC(ss->base, newlen); + } else { + newbase = (char*) PR_MALLOC(newlen); + } + if (!newbase) { + /* Ran out of memory */ + return -1; + } + ss->base = newbase; + ss->maxlen = newlen; + ss->cur = ss->base + off; + } + + /* Copy data */ + while (len) { + --len; + *ss->cur++ = *sp++; + } + PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen); + return 0; +} + +/* +** sprintf into a malloc'd buffer +*/ +PR_IMPLEMENT(char *) PR_smprintf(const char *fmt, ...) +{ + va_list ap; + char *rv; + + va_start(ap, fmt); + rv = PR_vsmprintf(fmt, ap); + va_end(ap); + return rv; +} + +/* +** Free memory allocated, for the caller, by PR_smprintf +*/ +PR_IMPLEMENT(void) PR_smprintf_free(char *mem) +{ + PR_DELETE(mem); +} + +PR_IMPLEMENT(char *) PR_vsmprintf(const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} + +/* +** Stuff routine that discards overflow data +*/ +static int LimitStuff(SprintfState *ss, const char *sp, PRUint32 len) +{ + PRUint32 limit = ss->maxlen - (ss->cur - ss->base); + + if (len > limit) { + len = limit; + } + while (len) { + --len; + *ss->cur++ = *sp++; + } + return 0; +} + +/* +** sprintf into a fixed size buffer. Make sure there is a NUL at the end +** when finished. +*/ +PR_IMPLEMENT(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + va_start(ap, fmt); + rv = PR_vsnprintf(out, outlen, fmt, ap); + va_end(ap); + return rv; +} + +PR_IMPLEMENT(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen,const char *fmt, + va_list ap) +{ + SprintfState ss; + PRUint32 n; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + ss.stuff = LimitStuff; + ss.base = out; + ss.cur = out; + ss.maxlen = outlen; + (void) dosprintf(&ss, fmt, ap); + + /* If we added chars, and we didn't append a null, do it now. */ + if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') ) + *(ss.cur - 1) = '\0'; + + n = ss.cur - ss.base; + return n ? n - 1 : n; +} + +PR_IMPLEMENT(char *) PR_sprintf_append(char *last, const char *fmt, ...) +{ + va_list ap; + char *rv; + + va_start(ap, fmt); + rv = PR_vsprintf_append(last, fmt, ap); + va_end(ap); + return rv; +} + +PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + if (last) { + int lastlen = strlen(last); + ss.base = last; + ss.cur = last + lastlen; + ss.maxlen = lastlen; + } else { + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + } + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} + diff --git a/nsprpub/pr/src/io/prscanf.c b/nsprpub/pr/src/io/prscanf.c new file mode 100644 index 00000000000..618f184f5f9 --- /dev/null +++ b/nsprpub/pr/src/io/prscanf.c @@ -0,0 +1,669 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Scan functions for NSPR types + * + * Author: Wan-Teh Chang + * + * Acknowledgment: The implementation is inspired by the source code + * in P.J. Plauger's "The Standard C Library," Prentice-Hall, 1992. + */ + +#include +#include +#include +#include +#ifdef SUNOS4 +#include "md/sunos4.h" /* for strtoul */ +#endif +#include "prprf.h" +#include "prdtoa.h" +#include "prlog.h" +#include "prerror.h" + +/* + * A function that reads a character from 'stream'. + * Returns the character read, or EOF if end of stream is reached. + */ +typedef int (*_PRGetCharFN)(void *stream); + +/* + * A function that pushes the character 'ch' back to 'stream'. + */ +typedef void (*_PRUngetCharFN)(void *stream, int ch); + +/* + * The size specifier for the integer and floating point number + * conversions in format control strings. + */ +typedef enum { + _PR_size_none, /* No size specifier is given */ + _PR_size_h, /* The 'h' specifier, suggesting "short" */ + _PR_size_l, /* The 'l' specifier, suggesting "long" */ + _PR_size_L, /* The 'L' specifier, meaning a 'long double' */ + _PR_size_ll /* The 'll' specifier, suggesting "long long" */ +} _PRSizeSpec; + +/* + * The collection of data that is passed between the scan function + * and its subordinate functions. The fields of this structure + * serve as the input or output arguments for these functions. + */ +typedef struct { + _PRGetCharFN get; /* get a character from input stream */ + _PRUngetCharFN unget; /* unget (push back) a character */ + void *stream; /* argument for get and unget */ + va_list ap; /* the variable argument list */ + int nChar; /* number of characters read from 'stream' */ + + PRBool assign; /* assign, or suppress assignment? */ + int width; /* field width */ + _PRSizeSpec sizeSpec; /* 'h', 'l', 'L', or 'll' */ + + PRBool converted; /* is the value actually converted? */ +} ScanfState; + +#define GET(state) ((state)->nChar++, (state)->get((state)->stream)) +#define UNGET(state, ch) \ + ((state)->nChar--, (state)->unget((state)->stream, ch)) + +/* + * The following two macros, GET_IF_WITHIN_WIDTH and WITHIN_WIDTH, + * are always used together. + * + * GET_IF_WITHIN_WIDTH calls the GET macro and assigns its return + * value to 'ch' only if we have not exceeded the field width of + * 'state'. Therefore, after GET_IF_WITHIN_WIDTH, the value of + * 'ch' is valid only if the macro WITHIN_WIDTH evaluates to true. + */ + +#define GET_IF_WITHIN_WIDTH(state, ch) \ + if (--(state)->width >= 0) { \ + (ch) = GET(state); \ + } +#define WITHIN_WIDTH(state) ((state)->width >= 0) + +/* + * _pr_strtoull: + * Convert a string to an unsigned 64-bit integer. The string + * 'str' is assumed to be a representation of the integer in + * base 'base'. + * + * Warning: + * - Only handle base 8, 10, and 16. + * - No overflow checking. + */ + +static PRUint64 +_pr_strtoull(const char *str, char **endptr, int base) +{ + static const int BASE_MAX = 16; + static const char digits[] = "0123456789abcdef"; + char *digitPtr; + PRUint64 x; /* return value */ + PRInt64 base64; + const char *cPtr; + PRBool negative; + const char *digitStart; + + PR_ASSERT(base == 0 || base == 8 || base == 10 || base == 16); + if (base < 0 || base == 1 || base > BASE_MAX) { + if (endptr) { + *endptr = (char *) str; + return LL_ZERO; + } + } + + cPtr = str; + while (isspace(*cPtr)) { + ++cPtr; + } + + negative = PR_FALSE; + if (*cPtr == '-') { + negative = PR_TRUE; + cPtr++; + } else if (*cPtr == '+') { + cPtr++; + } + + if (base == 16) { + if (*cPtr == '0' && (cPtr[1] == 'x' || cPtr[1] == 'X')) { + cPtr += 2; + } + } else if (base == 0) { + if (*cPtr != '0') { + base = 10; + } else if (cPtr[1] == 'x' || cPtr[1] == 'X') { + base = 16; + cPtr += 2; + } else { + base = 8; + } + } + PR_ASSERT(base != 0); + LL_I2L(base64, base); + digitStart = cPtr; + + /* Skip leading zeros */ + while (*cPtr == '0') { + cPtr++; + } + + LL_I2L(x, 0); + while ((digitPtr = (char*)memchr(digits, tolower(*cPtr), base)) != NULL) { + PRUint64 d; + + LL_I2L(d, (digitPtr - digits)); + LL_MUL(x, x, base64); + LL_ADD(x, x, d); + cPtr++; + } + + if (cPtr == digitStart) { + if (endptr) { + *endptr = (char *) str; + } + return LL_ZERO; + } + + if (negative) { +#ifdef HAVE_LONG_LONG + /* The cast to a signed type is to avoid a compiler warning */ + x = -(PRInt64)x; +#else + LL_NEG(x, x); +#endif + } + + if (endptr) { + *endptr = (char *) cPtr; + } + return x; +} + +/* + * The maximum field width (in number of characters) that is enough + * (may be more than necessary) to represent a 64-bit integer or + * floating point number. + */ +#define FMAX 31 +#define DECIMAL_POINT '.' + +static PRStatus +GetInt(ScanfState *state, int code) +{ + char buf[FMAX + 1], *p; + int ch; + static const char digits[] = "0123456789abcdefABCDEF"; + PRBool seenDigit = PR_FALSE; + int base; + int dlen; + + switch (code) { + case 'd': case 'u': + base = 10; + break; + case 'i': + base = 0; + break; + case 'x': case 'X': case 'p': + base = 16; + break; + case 'o': + base = 8; + break; + default: + return PR_FAILURE; + } + if (state->width == 0 || state->width > FMAX) { + state->width = FMAX; + } + p = buf; + GET_IF_WITHIN_WIDTH(state, ch); + if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } + if (WITHIN_WIDTH(state) && ch == '0') { + seenDigit = PR_TRUE; + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + if (WITHIN_WIDTH(state) + && (ch == 'x' || ch == 'X') + && (base == 0 || base == 16)) { + base = 16; + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } else if (base == 0) { + base = 8; + } + } + if (base == 0 || base == 10) { + dlen = 10; + } else if (base == 8) { + dlen = 8; + } else { + PR_ASSERT(base == 16); + dlen = 16 + 6; /* 16 digits, plus 6 in uppercase */ + } + while (WITHIN_WIDTH(state) && memchr(digits, ch, dlen)) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + seenDigit = PR_TRUE; + } + if (WITHIN_WIDTH(state)) { + UNGET(state, ch); + } + if (!seenDigit) { + return PR_FAILURE; + } + *p = '\0'; + if (state->assign) { + if (code == 'd' || code == 'i') { + if (state->sizeSpec == _PR_size_ll) { + PRInt64 llval = _pr_strtoull(buf, NULL, base); + *va_arg(state->ap, PRInt64 *) = llval; + } else { + long lval = strtol(buf, NULL, base); + + if (state->sizeSpec == _PR_size_none) { + *va_arg(state->ap, PRIntn *) = lval; + } else if (state->sizeSpec == _PR_size_h) { + *va_arg(state->ap, PRInt16 *) = (PRInt16)lval; + } else if (state->sizeSpec == _PR_size_l) { + *va_arg(state->ap, PRInt32 *) = lval; + } else { + return PR_FAILURE; + } + } + } else { + if (state->sizeSpec == _PR_size_ll) { + PRUint64 llval = _pr_strtoull(buf, NULL, base); + *va_arg(state->ap, PRUint64 *) = llval; + } else { + unsigned long lval = strtoul(buf, NULL, base); + + if (state->sizeSpec == _PR_size_none) { + *va_arg(state->ap, PRUintn *) = lval; + } else if (state->sizeSpec == _PR_size_h) { + *va_arg(state->ap, PRUint16 *) = (PRUint16)lval; + } else if (state->sizeSpec == _PR_size_l) { + *va_arg(state->ap, PRUint32 *) = lval; + } else { + return PR_FAILURE; + } + } + } + state->converted = PR_TRUE; + } + return PR_SUCCESS; +} + +static PRStatus +GetFloat(ScanfState *state) +{ + char buf[FMAX + 1], *p; + int ch; + PRBool seenDigit = PR_FALSE; + + if (state->width == 0 || state->width > FMAX) { + state->width = FMAX; + } + p = buf; + GET_IF_WITHIN_WIDTH(state, ch); + if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } + while (WITHIN_WIDTH(state) && isdigit(ch)) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + seenDigit = PR_TRUE; + } + if (WITHIN_WIDTH(state) && ch == DECIMAL_POINT) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + while (WITHIN_WIDTH(state) && isdigit(ch)) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + seenDigit = PR_TRUE; + } + } + + /* + * This is not robust. For example, "1.2e+" would confuse + * the code below to read 'e' and '+', only to realize that + * it should have stopped at "1.2". But we can't push back + * more than one character, so there is nothing I can do. + */ + + /* Parse exponent */ + if (WITHIN_WIDTH(state) && (ch == 'e' || ch == 'E') && seenDigit) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } + while (WITHIN_WIDTH(state) && isdigit(ch)) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } + } + if (WITHIN_WIDTH(state)) { + UNGET(state, ch); + } + if (!seenDigit) { + return PR_FAILURE; + } + *p = '\0'; + if (state->assign) { + PRFloat64 dval = PR_strtod(buf, NULL); + + state->converted = PR_TRUE; + if (state->sizeSpec == _PR_size_l) { + *va_arg(state->ap, PRFloat64 *) = dval; + } else if (state->sizeSpec == _PR_size_L) { +#if defined(OSF1) || defined(IRIX) + *va_arg(state->ap, double *) = dval; +#else + *va_arg(state->ap, long double *) = dval; +#endif + } else { + *va_arg(state->ap, float *) = (float) dval; + } + } + return PR_SUCCESS; +} + +/* + * Convert, and return the end of the conversion spec. + * Return NULL on error. + */ + +static const char * +Convert(ScanfState *state, const char *fmt) +{ + const char *cPtr; + int ch; + char *cArg = NULL; + + state->converted = PR_FALSE; + cPtr = fmt; + if (*cPtr != 'c' && *cPtr != 'n' && *cPtr != '[') { + do { + ch = GET(state); + } while (isspace(ch)); + UNGET(state, ch); + } + switch (*cPtr) { + case 'c': + if (state->assign) { + cArg = va_arg(state->ap, char *); + } + if (state->width == 0) { + state->width = 1; + } + for (; state->width > 0; state->width--) { + ch = GET(state); + if (ch == EOF) { + return NULL; + } else if (state->assign) { + *cArg++ = ch; + } + } + if (state->assign) { + state->converted = PR_TRUE; + } + break; + case 'p': + case 'd': case 'i': case 'o': + case 'u': case 'x': case 'X': + if (GetInt(state, *cPtr) == PR_FAILURE) { + return NULL; + } + break; + case 'e': case 'E': case 'f': + case 'g': case 'G': + if (GetFloat(state) == PR_FAILURE) { + return NULL; + } + break; + case 'n': + /* do not consume any input */ + if (state->assign) { + switch (state->sizeSpec) { + case _PR_size_none: + *va_arg(state->ap, PRIntn *) = state->nChar; + break; + case _PR_size_h: + *va_arg(state->ap, PRInt16 *) = state->nChar; + break; + case _PR_size_l: + *va_arg(state->ap, PRInt32 *) = state->nChar; + break; + case _PR_size_ll: + LL_I2L(*va_arg(state->ap, PRInt64 *), state->nChar); + break; + default: + PR_ASSERT(0); + } + } + break; + case 's': + if (state->width == 0) { + state->width = INT_MAX; + } + if (state->assign) { + cArg = va_arg(state->ap, char *); + } + for (; state->width > 0; state->width--) { + ch = GET(state); + if ((ch == EOF) || isspace(ch)) { + UNGET(state, ch); + break; + } + if (state->assign) { + *cArg++ = ch; + } + } + if (state->assign) { + *cArg = '\0'; + state->converted = PR_TRUE; + } + break; + case '%': + ch = GET(state); + if (ch != '%') { + UNGET(state, ch); + return NULL; + } + break; + case '[': + { + PRBool complement = PR_FALSE; + const char *closeBracket; + size_t n; + + if (*++cPtr == '^') { + complement = PR_TRUE; + cPtr++; + } + closeBracket = strchr(*cPtr == ']' ? cPtr + 1 : cPtr, ']'); + if (closeBracket == NULL) { + return NULL; + } + n = closeBracket - cPtr; + if (state->width == 0) { + state->width = INT_MAX; + } + if (state->assign) { + cArg = va_arg(state->ap, char *); + } + for (; state->width > 0; state->width--) { + ch = GET(state); + if ((ch == EOF) + || (!complement && !memchr(cPtr, ch, n)) + || (complement && memchr(cPtr, ch, n))) { + UNGET(state, ch); + break; + } + if (state->assign) { + *cArg++ = ch; + } + } + if (state->assign) { + *cArg = '\0'; + state->converted = PR_TRUE; + } + cPtr = closeBracket; + } + break; + default: + return NULL; + } + return cPtr; +} + +static PRInt32 +DoScanf(ScanfState *state, const char *fmt) +{ + PRInt32 nConverted = 0; + const char *cPtr; + int ch; + + state->nChar = 0; + cPtr = fmt; + while (1) { + if (isspace(*cPtr)) { + /* white space: skip */ + do { + cPtr++; + } while (isspace(*cPtr)); + do { + ch = GET(state); + } while (isspace(ch)); + UNGET(state, ch); + } else if (*cPtr == '%') { + /* format spec: convert */ + cPtr++; + state->assign = PR_TRUE; + if (*cPtr == '*') { + cPtr++; + state->assign = PR_FALSE; + } + for (state->width = 0; isdigit(*cPtr); cPtr++) { + state->width = state->width * 10 + *cPtr - '0'; + } + state->sizeSpec = _PR_size_none; + if (*cPtr == 'h') { + cPtr++; + state->sizeSpec = _PR_size_h; + } else if (*cPtr == 'l') { + cPtr++; + if (*cPtr == 'l') { + cPtr++; + state->sizeSpec = _PR_size_ll; + } else { + state->sizeSpec = _PR_size_l; + } + } else if (*cPtr == 'L') { + cPtr++; + state->sizeSpec = _PR_size_L; + } + cPtr = Convert(state, cPtr); + if (cPtr == NULL) { + return (nConverted > 0 ? nConverted : EOF); + } + if (state->converted) { + nConverted++; + } + cPtr++; + } else { + /* others: must match */ + if (*cPtr == '\0') { + return nConverted; + } + ch = GET(state); + if (ch != *cPtr) { + UNGET(state, ch); + return nConverted; + } + cPtr++; + } + } +} + +static int +StringGetChar(void *stream) +{ + char *cPtr = *((char **) stream); + + if (*cPtr == '\0') { + return EOF; + } else { + *((char **) stream) = cPtr + 1; + return (unsigned char) *cPtr; + } +} + +static void +StringUngetChar(void *stream, int ch) +{ + char *cPtr = *((char **) stream); + + if (ch != EOF) { + *((char **) stream) = cPtr - 1; + } +} + +PR_IMPLEMENT(PRInt32) +PR_sscanf(const char *buf, const char *fmt, ...) +{ + PRInt32 rv; + ScanfState state; + + state.get = &StringGetChar; + state.unget = &StringUngetChar; + state.stream = (void *) &buf; + va_start(state.ap, fmt); + rv = DoScanf(&state, fmt); + va_end(state.ap); + return rv; +} diff --git a/nsprpub/pr/src/io/prsocket.c b/nsprpub/pr/src/io/prsocket.c new file mode 100644 index 00000000000..0503a300c5a --- /dev/null +++ b/nsprpub/pr/src/io/prsocket.c @@ -0,0 +1,1858 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +/************************************************************************/ + +/* These two functions are only used in assertions. */ +#if defined(DEBUG) + +PRBool IsValidNetAddr(const PRNetAddr *addr) +{ + if ((addr != NULL) +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + && (addr->raw.family != PR_AF_LOCAL) +#endif + && (addr->raw.family != PR_AF_INET6) + && (addr->raw.family != PR_AF_INET)) { + return PR_FALSE; + } + return PR_TRUE; +} + +static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len) +{ + /* + * The definition of the length of a Unix domain socket address + * is not uniform, so we don't check it. + */ + if ((addr != NULL) +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + && (addr->raw.family != AF_UNIX) +#endif + && (PR_NETADDR_SIZE(addr) != addr_len)) { +#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 + /* + * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 + * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id + * field and is 28 bytes. It is possible for socket functions + * to return an addr_len greater than sizeof(struct sockaddr_in6). + * We need to allow that. (Bugzilla bug #77264) + */ + if ((PR_AF_INET6 == addr->raw.family) + && (sizeof(addr->ipv6) == addr_len)) { + return PR_TRUE; + } +#endif + /* + * The accept(), getsockname(), etc. calls on some platforms + * do not set the actual socket address length on return. + * In this case, we verifiy addr_len is still the value we + * passed in (i.e., sizeof(PRNetAddr)). + */ +#if defined(QNX) + if (sizeof(PRNetAddr) == addr_len) { + return PR_TRUE; + } +#endif + return PR_FALSE; + } + return PR_TRUE; +} + +#endif /* DEBUG */ + +static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov, +PRInt32 iov_size, PRIntervalTime timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + int w = 0; + const PRIOVec *tmp_iov; +#define LOCAL_MAXIOV 8 + PRIOVec local_iov[LOCAL_MAXIOV]; + PRIOVec *iov_copy = NULL; + int tmp_out; + int index, iov_cnt; + int count=0, sz = 0; /* 'count' is the return value. */ + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + /* + * Assume the first writev will succeed. Copy iov's only on + * failure. + */ + tmp_iov = iov; + for (index = 0; index < iov_size; index++) + sz += iov[index].iov_len; + + iov_cnt = iov_size; + + while (sz > 0) { + + w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout); + if (w < 0) { + count = -1; + break; + } + count += w; + if (fd->secret->nonblocking) { + break; + } + sz -= w; + + if (sz > 0) { + /* find the next unwritten vector */ + for ( index = 0, tmp_out = count; + tmp_out >= iov[index].iov_len; + tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */ + + if (tmp_iov == iov) { + /* + * The first writev failed so we + * must copy iov's around. + * Avoid calloc/free if there + * are few enough iov's. + */ + if (iov_size - index <= LOCAL_MAXIOV) + iov_copy = local_iov; + else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) * + sizeof *iov_copy)) == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + tmp_iov = iov_copy; + } + + PR_ASSERT(tmp_iov == iov_copy); + + /* fill in the first partial read */ + iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]); + iov_copy[0].iov_len = iov[index].iov_len - tmp_out; + index++; + + /* copy the remaining vectors */ + for (iov_cnt=1; indexsecret->af = AF_INET; +#endif + } else + _PR_MD_CLOSE_SOCKET(osfd); + return(fd); +} + +PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PROsfd osfd) +{ +PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); + if (fd != NULL) { + _PR_MD_MAKE_NONBLOCK(fd); + _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); + } else + _PR_MD_CLOSE_SOCKET(osfd); + return(fd); +} + + +static const PRIOMethods* PR_GetSocketPollFdMethods(void); + +PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + fd = _PR_Getfd(); + + if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->secret->md.osfd = osfd; + fd->secret->inheritable = _PR_TRI_FALSE; + fd->secret->state = _PR_FILEDESC_OPEN; + fd->methods = PR_GetSocketPollFdMethods(); + } + + return fd; +} /* PR_CreateSocketPollFD */ + +PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd) +{ + if (NULL == fd) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + fd->secret->state = _PR_FILEDESC_CLOSED; + _PR_Putfd(fd); + return PR_SUCCESS; +} /* PR_DestroySocketPollFd */ + +static PRStatus PR_CALLBACK SocketConnect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRInt32 rv; /* Return value of _PR_MD_CONNECT */ + const PRNetAddr *addrp = addr; +#if defined(_PR_INET6) + PRNetAddr addrCopy; +#endif + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return PR_FAILURE; + } +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; + } +#endif + + rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout); + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv)); + if (rv == 0) + return PR_SUCCESS; + else + return PR_FAILURE; +} + +static PRStatus PR_CALLBACK SocketConnectContinue( + PRFileDesc *fd, PRInt16 out_flags) +{ + PROsfd osfd; + int err; + + if (out_flags & PR_POLL_NVAL) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) { + PR_ASSERT(out_flags == 0); + PR_SetError(PR_IN_PROGRESS_ERROR, 0); + return PR_FAILURE; + } + + osfd = fd->secret->md.osfd; + +#if defined(XP_UNIX) + + err = _MD_unix_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; + +#elif defined(WIN32) || defined(WIN16) + +#if defined(WIN32) + /* + * The sleep circumvents a bug in Win32 WinSock. + * See Microsoft Knowledge Base article ID: Q165989. + */ + Sleep(0); +#endif /* WIN32 */ + + if (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()); + return PR_FAILURE; + } + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + } else { + PR_SetError(PR_UNKNOWN_ERROR, 0); + } + return PR_FAILURE; + } + + PR_ASSERT(out_flags & PR_POLL_WRITE); + return PR_SUCCESS; + +#elif defined(XP_OS2) + + err = _MD_os2_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; + +#elif defined(XP_MAC) + + err = _MD_mac_get_nonblocking_connect_error(fd); + if (err == -1) + return PR_FAILURE; + else + return PR_SUCCESS; + +#elif defined(XP_BEOS) + +#ifdef BONE_VERSION /* bug 122364 */ + /* temporary workaround until getsockopt(SO_ERROR) works in BONE */ + if (out_flags & PR_POLL_EXCEPT) { + PR_SetError(PR_CONNECT_REFUSED_ERROR, 0); + return PR_FAILURE; + } + PR_ASSERT(out_flags & PR_POLL_WRITE); + return PR_SUCCESS; +#else + err = _MD_beos_get_nonblocking_connect_error(fd); + if( err != 0 ) { + _PR_MD_MAP_CONNECT_ERROR(err); + return PR_FAILURE; + } + else + return PR_SUCCESS; +#endif /* BONE_VERSION */ + +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +#endif +} + +PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd) +{ + /* Find the NSPR layer and invoke its connectcontinue method */ + PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + + if (NULL == bottom) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + return SocketConnectContinue(bottom, pd->out_flags); +} + +static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr, +PRIntervalTime timeout) +{ + PROsfd osfd; + PRFileDesc *fd2; + PRUint32 al; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#ifdef WINNT + PRNetAddr addrCopy; +#endif + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return 0; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return 0; + } + +#ifdef WINNT + if (addr == NULL) { + addr = &addrCopy; + } +#endif + al = sizeof(PRNetAddr); + osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout); + if (osfd == -1) + return 0; + + fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); + if (!fd2) { + _PR_MD_CLOSE_SOCKET(osfd); + return NULL; + } + + fd2->secret->nonblocking = fd->secret->nonblocking; + fd2->secret->inheritable = fd->secret->inheritable; +#ifdef WINNT + if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) { + /* + * The new socket has been associated with an I/O + * completion port. There is no going back. + */ + fd2->secret->md.io_model_committed = PR_TRUE; + } + PR_ASSERT(al == PR_NETADDR_SIZE(addr)); + fd2->secret->md.accepted_socket = PR_TRUE; + memcpy(&fd2->secret->md.peer_addr, addr, al); +#endif + + /* + * On some platforms, the new socket created by accept() + * inherits the nonblocking (or overlapped io) attribute + * of the listening socket. As an optimization, these + * platforms can skip the following _PR_MD_MAKE_NONBLOCK + * call. + * + * On Mac, we MUST make this call, because _PR_MD_MAKE_NONBLOCK + * (which maps to _MD_makenonblock, see macsockotpt.c) + * installs the async notifier routine needed to make blocking + * I/O work properly. + */ +#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT) + _PR_MD_MAKE_NONBLOCK(fd2); +#endif + +#ifdef _PR_INET6 + if (addr && (AF_INET6 == addr->raw.family)) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE); + + return fd2; +} + +#ifdef WINNT +PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr, +PRIntervalTime timeout) +{ + PROsfd osfd; + PRFileDesc *fd2; + PRIntn al; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRNetAddr addrCopy; + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return 0; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return 0; + } + + if (addr == NULL) { + addr = &addrCopy; + } + al = PR_NETADDR_SIZE(addr); + osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL); + if (osfd == -1) { + return 0; + } + + fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); + if (!fd2) { + _PR_MD_CLOSE_SOCKET(osfd); + } else { + fd2->secret->nonblocking = fd->secret->nonblocking; + fd2->secret->md.io_model_committed = PR_TRUE; + PR_ASSERT(al == PR_NETADDR_SIZE(addr)); + fd2->secret->md.accepted_socket = PR_TRUE; + memcpy(&fd2->secret->md.peer_addr, addr, al); +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif +#ifdef _PR_NEED_SECRET_AF + fd2->secret->af = fd->secret->af; +#endif + } + return fd2; +} +#endif /* WINNT */ + + +static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr) +{ + PRInt32 result; + const PRNetAddr *addrp = addr; +#if defined(_PR_INET6) + PRNetAddr addrCopy; +#endif + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + +#ifdef XP_UNIX + if (addr->raw.family == AF_UNIX) { + /* Disallow relative pathnames */ + if (addr->local.path[0] != '/') { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + } +#endif /* XP_UNIX */ + +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; + } +#endif + result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr)); + if (result < 0) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 result; + + result = _PR_MD_LISTEN(fd, backlog); + if (result < 0) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how) +{ + PRInt32 result; + + result = _PR_MD_SHUTDOWN(fd, how); + if (result < 0) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, +PRIntervalTime timeout) +{ + PRInt32 rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ((flags != 0) && (flags != PR_MSG_PEEK)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + PR_LOG(_pr_io_lm, PR_LOG_MAX, + ("recv: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d flags=%d", + fd, fd->secret->md.osfd, buf, amount, flags)); + +#ifdef _PR_HAVE_PEEK_BUFFER + if (fd->secret->peekBytes != 0) { + rv = (amount < fd->secret->peekBytes) ? + amount : fd->secret->peekBytes; + memcpy(buf, fd->secret->peekBuffer, rv); + if (flags == 0) { + /* consume the bytes in the peek buffer */ + fd->secret->peekBytes -= rv; + if (fd->secret->peekBytes != 0) { + memmove(fd->secret->peekBuffer, + fd->secret->peekBuffer + rv, + fd->secret->peekBytes); + } + } + return rv; + } + + /* allocate peek buffer, if necessary */ + if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { + PR_ASSERT(0 == fd->secret->peekBytes); + /* impose a max size on the peek buffer */ + if (amount > _PR_PEEK_BUFFER_MAX) { + amount = _PR_PEEK_BUFFER_MAX; + } + if (fd->secret->peekBufSize < amount) { + if (fd->secret->peekBuffer) { + PR_Free(fd->secret->peekBuffer); + } + fd->secret->peekBufSize = amount; + fd->secret->peekBuffer = PR_Malloc(amount); + if (NULL == fd->secret->peekBuffer) { + fd->secret->peekBufSize = 0; + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + } + } +#endif + + rv = _PR_MD_RECV(fd, buf, amount, flags, timeout); + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d", + rv, PR_GetError(), PR_GetOSError())); + +#ifdef _PR_HAVE_PEEK_BUFFER + if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { + if (rv > 0) { + memcpy(fd->secret->peekBuffer, buf, rv); + fd->secret->peekBytes = rv; + } + } +#endif + + return rv; +} + +static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); +} + +static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount, +PRIntn flags, PRIntervalTime timeout) +{ + PRInt32 temp, count; + 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 (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + count = 0; + while (amount > 0) { + PR_LOG(_pr_io_lm, PR_LOG_MAX, + ("send: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d", + fd, fd->secret->md.osfd, buf, amount)); + temp = _PR_MD_SEND(fd, buf, amount, flags, timeout); + if (temp < 0) { + count = -1; + break; + } + + count += temp; + if (fd->secret->nonblocking) { + break; + } + buf = (const void*) ((const char*)buf + temp); + + amount -= temp; + } + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count)); + return count; +} + +static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); +} + +static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd) +{ + 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; + } + + 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; + } + +#ifdef _PR_HAVE_PEEK_BUFFER + if (fd->secret->peekBuffer) { + PR_ASSERT(fd->secret->peekBufSize > 0); + PR_DELETE(fd->secret->peekBuffer); + fd->secret->peekBufSize = 0; + fd->secret->peekBytes = 0; + } +#endif + + PR_FreeFileDesc(fd); + return PR_SUCCESS; +} + +static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd) +{ + PRInt32 rv; +#ifdef _PR_HAVE_PEEK_BUFFER + if (fd->secret->peekBytes != 0) { + return fd->secret->peekBytes; + } +#endif + rv = _PR_MD_SOCKETAVAILABLE(fd); + return rv; +} + +static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd) +{ + PRInt64 rv; +#ifdef _PR_HAVE_PEEK_BUFFER + if (fd->secret->peekBytes != 0) { + LL_I2L(rv, fd->secret->peekBytes); + return rv; + } +#endif + LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd)); + return rv; +} + +static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd) +{ +#if defined(XP_MAC) +#pragma unused (fd) +#endif + + return PR_SUCCESS; +} + +static PRInt32 PR_CALLBACK SocketSendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRInt32 temp, count; + const PRNetAddr *addrp = addr; +#if defined(_PR_INET6) + PRNetAddr addrCopy; +#endif + 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 (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; + } +#endif + + count = 0; + while (amount > 0) { + temp = _PR_MD_SENDTO(fd, buf, amount, flags, + addrp, PR_NETADDR_SIZE(addr), timeout); + if (temp < 0) { + count = -1; + break; + } + count += temp; + if (fd->secret->nonblocking) { + break; + } + buf = (const void*) ((const char*)buf + temp); + amount -= temp; + } + return count; +} + +static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, +PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRInt32 rv; + PRUint32 al; + 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 (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + al = sizeof(PRNetAddr); + rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout); +#ifdef _PR_INET6 + if (addr && (AF_INET6 == addr->raw.family)) + addr->raw.family = PR_AF_INET6; +#endif + return rv; +} + +static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, +PRNetAddr **raddr, void *buf, PRInt32 amount, +PRIntervalTime timeout) +{ + PRInt32 rv; + 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 (_PR_IO_PENDING(me)) { + 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) + { + PROsfd newSock; + PRNetAddr *raddrCopy; + + if (raddr == NULL) { + raddr = &raddrCopy; + } + rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout); + if (rv < 0) { + rv = -1; + } else { + /* Successfully accepted and read; create the new PRFileDesc */ + *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); + if (*nd == 0) { + _PR_MD_CLOSE_SOCKET(newSock); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + rv = -1; + } else { + (*nd)->secret->md.io_model_committed = PR_TRUE; + (*nd)->secret->md.accepted_socket = PR_TRUE; + memcpy(&(*nd)->secret->md.peer_addr, *raddr, + PR_NETADDR_SIZE(*raddr)); +#ifdef _PR_INET6 + if (AF_INET6 == *raddr->raw.family) + *raddr->raw.family = PR_AF_INET6; +#endif + } + } + } +#else + rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); +#endif + return rv; +} + +#ifdef WINNT +PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, +PRNetAddr **raddr, void *buf, PRInt32 amount, +PRIntervalTime timeout) +{ + PRInt32 rv; + PROsfd newSock; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRNetAddr *raddrCopy; + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + *nd = NULL; + + if (raddr == NULL) { + raddr = &raddrCopy; + } + rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, + timeout, PR_TRUE, NULL, NULL); + if (rv < 0) { + rv = -1; + } else { + /* Successfully accepted and read; create the new PRFileDesc */ + *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); + if (*nd == 0) { + _PR_MD_CLOSE_SOCKET(newSock); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + rv = -1; + } else { + (*nd)->secret->md.io_model_committed = PR_TRUE; + (*nd)->secret->md.accepted_socket = PR_TRUE; + memcpy(&(*nd)->secret->md.peer_addr, *raddr, + PR_NETADDR_SIZE(*raddr)); +#ifdef _PR_INET6 + if (AF_INET6 == *raddr->raw.family) + *raddr->raw.family = PR_AF_INET6; +#endif +#ifdef _PR_NEED_SECRET_AF + (*nd)->secret->af = sd->secret->af; +#endif + } + } + return rv; +} + +PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback( +PRFileDesc *sd, PRFileDesc **nd, +PRNetAddr **raddr, void *buf, PRInt32 amount, +PRIntervalTime timeout, +_PR_AcceptTimeoutCallback callback, +void *callbackArg) +{ + PRInt32 rv; + PROsfd newSock; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRNetAddr *raddrCopy; + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + *nd = NULL; + + if (raddr == NULL) { + raddr = &raddrCopy; + } + rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, + timeout, PR_TRUE, callback, callbackArg); + if (rv < 0) { + rv = -1; + } else { + /* Successfully accepted and read; create the new PRFileDesc */ + *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); + if (*nd == 0) { + _PR_MD_CLOSE_SOCKET(newSock); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + rv = -1; + } else { + (*nd)->secret->md.io_model_committed = PR_TRUE; + (*nd)->secret->md.accepted_socket = PR_TRUE; + memcpy(&(*nd)->secret->md.peer_addr, *raddr, + PR_NETADDR_SIZE(*raddr)); +#ifdef _PR_INET6 + if (AF_INET6 == *raddr->raw.family) + *raddr->raw.family = PR_AF_INET6; +#endif +#ifdef _PR_NEED_SECRET_AF + (*nd)->secret->af = sd->secret->af; +#endif + } + } + return rv; +} +#endif /* WINNT */ + +#ifdef WINNT +PR_IMPLEMENT(void) +PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket) +{ + _PR_MD_UPDATE_ACCEPT_CONTEXT( + socket->secret->md.osfd, acceptSocket->secret->md.osfd); +} +#endif /* WINNT */ + +static PRInt32 PR_CALLBACK SocketSendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRInt32 rv; + 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 (_PR_IO_PENDING(me)) { + 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_SENDFILE(sd, sfd, flags, timeout); + if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) { + /* + * This should be kept the same as SocketClose, except + * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should + * not be called because the socket will be recycled. + */ + PR_FreeFileDesc(sd); + } +#else + rv = PR_EmulateSendFile(sd, sfd, flags, timeout); +#endif /* WINNT */ + + return rv; +} + +static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, +const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, +PRIntervalTime timeout) +{ + PRSendFileData sfd; + + sfd.fd = fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = headers; + sfd.hlen = hlen; + sfd.trailer = NULL; + sfd.tlen = 0; + + return(SocketSendFile(sd, &sfd, flags, timeout)); +} + +static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr) +{ + PRInt32 result; + PRUint32 addrlen; + + addrlen = sizeof(PRNetAddr); + result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen); + if (result < 0) { + return PR_FAILURE; + } +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE); + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr) +{ + PRInt32 result; + PRUint32 addrlen; + + addrlen = sizeof(PRNetAddr); + result = _PR_MD_GETPEERNAME(fd, addr, &addrlen); + if (result < 0) { + return PR_FAILURE; + } +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE); + return PR_SUCCESS; +} + +static PRInt16 PR_CALLBACK SocketPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ +#ifdef XP_MAC +#pragma unused( fd, in_flags ) +#endif + *out_flags = 0; + return in_flags; +} /* SocketPoll */ + +static PRIOMethods tcpMethods = { + PR_DESC_SOCKET_TCP, + SocketClose, + SocketRead, + SocketWrite, + SocketAvailable, + SocketAvailable64, + SocketSync, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + SocketWritev, + SocketConnect, + SocketAccept, + SocketBind, + SocketListen, + SocketShutdown, + SocketRecv, + SocketSend, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + SocketPoll, + SocketAcceptRead, + SocketTransmitFile, + SocketGetName, + SocketGetPeerName, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + _PR_SocketGetSocketOption, + _PR_SocketSetSocketOption, + SocketSendFile, + SocketConnectContinue, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods udpMethods = { + PR_DESC_SOCKET_UDP, + SocketClose, + SocketRead, + SocketWrite, + SocketAvailable, + SocketAvailable64, + SocketSync, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + SocketWritev, + SocketConnect, + (PRAcceptFN)_PR_InvalidDesc, + SocketBind, + SocketListen, + SocketShutdown, + SocketRecv, + SocketSend, + SocketRecvFrom, + SocketSendTo, + SocketPoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + SocketGetName, + SocketGetPeerName, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + _PR_SocketGetSocketOption, + _PR_SocketSetSocketOption, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + + +static PRIOMethods socketpollfdMethods = { + (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, + SocketPoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods() +{ + return &tcpMethods; +} + +PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods() +{ + return &udpMethods; +} + +static const PRIOMethods* PR_GetSocketPollFdMethods() +{ + return &socketpollfdMethods; +} /* PR_GetSocketPollFdMethods */ + +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) +PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd); + +#if defined(_PR_INET6_PROBE) + +extern PRBool _pr_ipv6_is_present(void); + +PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() +{ + PROsfd osfd; + + osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0); + if (osfd != -1) { + _PR_MD_CLOSE_SOCKET(osfd); + return PR_TRUE; + } + return PR_FALSE; +} +#endif /* _PR_INET6_PROBE */ + +#endif + +PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) +{ + PROsfd osfd; + PRFileDesc *fd; + PRInt32 tmp_domain = domain; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if (PR_AF_INET != domain + && PR_AF_INET6 != domain +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + && PR_AF_LOCAL != domain +#endif + ) { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return NULL; + } + +#if defined(_PR_INET6_PROBE) + if (PR_AF_INET6 == domain) + domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET; +#elif defined(_PR_INET6) + if (PR_AF_INET6 == domain) + domain = AF_INET6; +#else + if (PR_AF_INET6 == domain) + domain = AF_INET; +#endif /* _PR_INET6 */ + osfd = _PR_MD_SOCKET(domain, type, proto); + if (osfd == -1) { + return 0; + } + if (type == SOCK_STREAM) + fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); + else + fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); + /* + * Make the sockets non-blocking + */ + if (fd != NULL) { + _PR_MD_MAKE_NONBLOCK(fd); + _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); +#ifdef _PR_NEED_SECRET_AF + fd->secret->af = domain; +#endif +#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) + /* + * For platforms with no support for IPv6 + * create layered socket for IPv4-mapped IPv6 addresses + */ + if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) { + if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) { + PR_Close(fd); + fd = NULL; + } + } +#endif + } else + _PR_MD_CLOSE_SOCKET(osfd); + + return fd; +} + +PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void) +{ + PRInt32 domain = AF_INET; + + return PR_Socket(domain, SOCK_STREAM, 0); +} + +PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) +{ + PRInt32 domain = AF_INET; + + return PR_Socket(domain, SOCK_DGRAM, 0); +} + +PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af) +{ + return PR_Socket(af, SOCK_STREAM, 0); +} + +PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) +{ + return PR_Socket(af, SOCK_DGRAM, 0); +} + +PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[]) +{ +#ifdef XP_UNIX + PRInt32 rv, osfd[2]; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd); + if (rv == -1) { + return PR_FAILURE; + } + + f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); + if (!f[0]) { + _PR_MD_CLOSE_SOCKET(osfd[0]); + _PR_MD_CLOSE_SOCKET(osfd[1]); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + return PR_FAILURE; + } + f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); + if (!f[1]) { + PR_Close(f[0]); + _PR_MD_CLOSE_SOCKET(osfd[1]); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + return PR_FAILURE; + } + _PR_MD_MAKE_NONBLOCK(f[0]); + _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); + _PR_MD_MAKE_NONBLOCK(f[1]); + _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); + return PR_SUCCESS; +#elif defined(WINNT) + /* + * A socket pair is often used for interprocess communication, + * so we need to make sure neither socket is associated with + * the I/O completion port; otherwise it can't be used by a + * child process. + * + * The default implementation below cannot be used for NT + * because PR_Accept would have associated the I/O completion + * port with the listening and accepted sockets. + */ + SOCKET listenSock; + SOCKET osfd[2]; + struct sockaddr_in selfAddr, peerAddr; + int addrLen; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + osfd[0] = osfd[1] = INVALID_SOCKET; + listenSock = socket(AF_INET, SOCK_STREAM, 0); + if (listenSock == INVALID_SOCKET) { + goto failed; + } + selfAddr.sin_family = AF_INET; + selfAddr.sin_port = 0; + selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */ + addrLen = sizeof(selfAddr); + if (bind(listenSock, (struct sockaddr *) &selfAddr, + addrLen) == SOCKET_ERROR) { + goto failed; + } + if (getsockname(listenSock, (struct sockaddr *) &selfAddr, + &addrLen) == SOCKET_ERROR) { + goto failed; + } + if (listen(listenSock, 5) == SOCKET_ERROR) { + goto failed; + } + osfd[0] = socket(AF_INET, SOCK_STREAM, 0); + if (osfd[0] == INVALID_SOCKET) { + goto failed; + } + selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + /* + * Only a thread is used to do the connect and accept. + * I am relying on the fact that connect returns + * successfully as soon as the connect request is put + * into the listen queue (but before 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 (connect(osfd[0], (struct sockaddr *) &selfAddr, + addrLen) == SOCKET_ERROR) { + goto failed; + } + /* + * A malicious local process may connect to the listening + * socket, so we need to verify that the accepted connection + * is made from our own socket osfd[0]. + */ + if (getsockname(osfd[0], (struct sockaddr *) &selfAddr, + &addrLen) == SOCKET_ERROR) { + goto failed; + } + osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen); + if (osfd[1] == INVALID_SOCKET) { + goto failed; + } + if (peerAddr.sin_port != selfAddr.sin_port) { + /* the connection we accepted is not from osfd[0] */ + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + goto failed; + } + closesocket(listenSock); + + f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); + if (!f[0]) { + closesocket(osfd[0]); + closesocket(osfd[1]); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + return PR_FAILURE; + } + f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); + if (!f[1]) { + PR_Close(f[0]); + closesocket(osfd[1]); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + return PR_FAILURE; + } + _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); + _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); + return PR_SUCCESS; + +failed: + if (listenSock != INVALID_SOCKET) { + closesocket(listenSock); + } + if (osfd[0] != INVALID_SOCKET) { + closesocket(osfd[0]); + } + if (osfd[1] != INVALID_SOCKET) { + closesocket(osfd[1]); + } + return PR_FAILURE; +#else /* not Unix or NT */ + /* + * default implementation + */ + PRFileDesc *listenSock; + PRNetAddr selfAddr, peerAddr; + PRUint16 port; + + f[0] = f[1] = NULL; + listenSock = PR_NewTCPSocket(); + if (listenSock == NULL) { + goto failed; + } + PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */ + 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; + } +#ifdef _PR_CONNECT_DOES_NOT_BIND + /* + * If connect does not implicitly bind the socket (e.g., on + * BeOS), we have to bind the socket so that we can get its + * port with getsockname later. + */ + PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); + if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) { + goto failed; + } +#endif + PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr); + + /* + * 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; + } + /* + * A malicious local process may connect to the listening + * socket, so we need to verify that the accepted connection + * is made from our own socket f[0]. + */ + if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) { + goto failed; + } + f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT); + if (f[1] == NULL) { + goto failed; + } + if (peerAddr.inet.port != selfAddr.inet.port) { + /* the connection we accepted is not from f[0] */ + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + goto failed; + } + PR_Close(listenSock); + return PR_SUCCESS; + +failed: + if (listenSock) { + PR_Close(listenSock); + } + if (f[0]) { + PR_Close(f[0]); + } + if (f[1]) { + PR_Close(f[1]); + } + return PR_FAILURE; +#endif +} + +PR_IMPLEMENT(PROsfd) +PR_FileDesc2NativeHandle(PRFileDesc *fd) +{ + if (fd) { + fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER); + } + if (!fd) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + return fd->secret->md.osfd; +} + +PR_IMPLEMENT(void) +PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PROsfd handle) +{ + if (fd) + fd->secret->md.osfd = handle; +} + +/* +** Select compatibility +** +*/ + +PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set) +{ + memset(set, 0, sizeof(PR_fd_set)); +} + +PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set) +{ + PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC ); + + set->harray[set->hsize++] = fh; +} + +PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set) +{ + PRUint32 index, index2; + + for (index = 0; indexhsize; index++) + if (set->harray[index] == fh) { + for (index2=index; index2 < (set->hsize-1); index2++) { + set->harray[index2] = set->harray[index2+1]; + } + set->hsize--; + break; + } +} + +PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set) +{ + PRUint32 index; + for (index = 0; indexhsize; index++) + if (set->harray[index] == fh) { + return 1; + } + return 0; +} + +PR_IMPLEMENT(void) PR_FD_NSET(PROsfd fd, PR_fd_set *set) +{ + PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC ); + + set->narray[set->nsize++] = fd; +} + +PR_IMPLEMENT(void) PR_FD_NCLR(PROsfd fd, PR_fd_set *set) +{ + PRUint32 index, index2; + + for (index = 0; indexnsize; index++) + if (set->narray[index] == fd) { + for (index2=index; index2 < (set->nsize-1); index2++) { + set->narray[index2] = set->narray[index2+1]; + } + set->nsize--; + break; + } +} + +PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PROsfd fd, PR_fd_set *set) +{ + PRUint32 index; + for (index = 0; indexnsize; index++) + if (set->narray[index] == fd) { + return 1; + } + return 0; +} + + +#if !defined(NEED_SELECT) +#if !defined(XP_MAC) +#include "obsolete/probslet.h" +#else +#include "probslet.h" +#endif + +#define PD_INCR 20 + +static PRPollDesc *_pr_setfd( + PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc) +{ + PRUintn fsidx, pdidx; + PRPollDesc *poll = polldesc; + + if (NULL == set) return poll; + + /* First set the pr file handle osfds */ + for (fsidx = 0; fsidx < set->hsize; fsidx++) + { + for (pdidx = 0; 1; pdidx++) + { + if ((PRFileDesc*)-1 == poll[pdidx].fd) + { + /* our vector is full - extend and condition it */ + poll = (PRPollDesc*)PR_Realloc( + poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc)); + if (NULL == poll) goto out_of_memory; + memset( + poll + pdidx * sizeof(PRPollDesc), + 0, PD_INCR * sizeof(PRPollDesc)); + poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1; + } + if ((NULL == poll[pdidx].fd) + || (poll[pdidx].fd == set->harray[fsidx])) + { + /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */ + /* either empty or prevously defined */ + poll[pdidx].fd = set->harray[fsidx]; /* possibly redundant */ + poll[pdidx].in_flags |= flags; /* possibly redundant */ + break; + } + } + } + +#if 0 + /* Second set the native osfds */ + for (fsidx = 0; fsidx < set->nsize; fsidx++) + { + for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++) + { + if ((PRFileDesc*)-1 == poll[pdidx].fd) + { + /* our vector is full - extend and condition it */ + poll = PR_Realloc( + poll, (pdidx + PD_INCR) * sizeof(PRPollDesc)); + if (NULL == poll) goto out_of_memory; + memset( + poll + pdidx * sizeof(PRPollDesc), + 0, PD_INCR * sizeof(PRPollDesc)); + poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1; + } + if ((NULL == poll[pdidx].fd) + || (poll[pdidx].fd == set->narray[fsidx])) + { + /* either empty or prevously defined */ + poll[pdidx].fd = set->narray[fsidx]; + PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); + poll[pdidx].in_flags |= flags; + break; + } + } + } +#endif /* 0 */ + + return poll; + +out_of_memory: + if (NULL != polldesc) PR_DELETE(polldesc); + return NULL; +} /* _pr_setfd */ + +#endif /* !defined(NEED_SELECT) */ + +PR_IMPLEMENT(PRInt32) PR_Select( + PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, + PR_fd_set *pr_ex, PRIntervalTime timeout) +{ + +#if !defined(NEED_SELECT) + PRInt32 npds = 0; + /* + ** Find out how many fds are represented in the three lists. + ** Then allocate a polling descriptor for the logical union + ** (there can't be any overlapping) and call PR_Poll(). + */ + + PRPollDesc *copy, *poll; + + static PRBool warning = PR_TRUE; + if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()"); + + /* try to get an initial guesss at how much space we need */ + npds = 0; + if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0)) + npds = pr_rd->hsize + pr_rd->nsize; + if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0)) + npds = pr_wr->hsize + pr_wr->nsize; + if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0)) + npds = pr_ex->hsize + pr_ex->nsize; + + if (0 == npds) + { + PR_Sleep(timeout); + return 0; + } + + 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; + + poll = _pr_setfd(pr_rd, PR_POLL_READ, poll); + if (NULL == poll) goto out_of_memory; + poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll); + if (NULL == poll) goto out_of_memory; + poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll); + if (NULL == poll) goto out_of_memory; + unused = 0; + while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd) + { + ++unused; + } + + PR_ASSERT(unused > 0); + npds = PR_Poll(poll, unused, timeout); + + if (npds > 0) + { + /* Copy the results back into the fd sets */ + if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0; + if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0; + if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0; + for (copy = &poll[unused - 1]; copy >= poll; --copy) + { + if (copy->out_flags & PR_POLL_NVAL) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + npds = -1; + break; + } + if (copy->out_flags & PR_POLL_READ) + if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd; + if (copy->out_flags & PR_POLL_WRITE) + if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd; + if (copy->out_flags & PR_POLL_EXCEPT) + if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd; + } + } + PR_DELETE(poll); + + return npds; +out_of_memory: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + +#endif /* !defined(NEED_SELECT) */ + +} diff --git a/nsprpub/pr/src/io/prstdio.c b/nsprpub/pr/src/io/prstdio.c new file mode 100644 index 00000000000..b8a091f5afe --- /dev/null +++ b/nsprpub/pr/src/io/prstdio.c @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +/* +** fprintf to a PRFileDesc +*/ +PR_IMPLEMENT(PRUint32) PR_fprintf(PRFileDesc* fd, const char *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + va_start(ap, fmt); + rv = PR_vfprintf(fd, fmt, ap); + va_end(ap); + return rv; +} + +PR_IMPLEMENT(PRUint32) PR_vfprintf(PRFileDesc* fd, const char *fmt, va_list ap) +{ + /* XXX this could be better */ + PRUint32 rv, len; + char* msg = PR_vsmprintf(fmt, ap); + if (NULL == msg) { + return -1; + } + len = strlen(msg); +#ifdef XP_OS2 + /* + * OS/2 really needs a \r for every \n. + * In the future we should try to use scatter-gather instead of a + * succession of PR_Write. + */ + if (isatty(PR_FileDesc2NativeHandle(fd))) { + PRUint32 last = 0, idx; + PRInt32 tmp; + rv = 0; + for (idx = 0; idx < len+1; idx++) { + if ((idx - last > 0) && (('\n' == msg[idx]) || (idx == len))) { + tmp = PR_Write(fd, msg + last, idx - last); + if (tmp >= 0) { + rv += tmp; + } + last = idx; + } + /* + * if current character is \n, and + * previous character isn't \r, and + * next character isn't \r + */ + if (('\n' == msg[idx]) && + ((0 == idx) || ('\r' != msg[idx-1])) && + ('\r' != msg[idx+1])) { + /* add extra \r */ + tmp = PR_Write(fd, "\r", 1); + if (tmp >= 0) { + rv += tmp; + } + } + } + } else { + rv = PR_Write(fd, msg, len); + } +#else + rv = PR_Write(fd, msg, len); +#endif + PR_DELETE(msg); + return rv; +} diff --git a/nsprpub/pr/src/linking/.cvsignore b/nsprpub/pr/src/linking/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/linking/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/linking/Makefile.in b/nsprpub/pr/src/linking/Makefile.in new file mode 100644 index 00000000000..9b82aca205d --- /dev/null +++ b/nsprpub/pr/src/linking/Makefile.in @@ -0,0 +1,75 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +CSRCS = \ + prlink.c \ + $(NULL) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +# On Mac OS X use flat #includes. +ifeq ($(OS_TARGET),MacOSX) +INCLUDES += -I$(MACOS_SDK_DIR)/Developer/Headers/FlatCarbon +endif + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/pr/src/linking/prlink.c b/nsprpub/pr/src/linking/prlink.c new file mode 100644 index 00000000000..fbbd3be59f2 --- /dev/null +++ b/nsprpub/pr/src/linking/prlink.c @@ -0,0 +1,1980 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Steve Streeter (Hewlett-Packard Company) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +#ifdef XP_BEOS +#include +#endif + +#ifdef XP_MACOSX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifdef XP_UNIX +#ifdef USE_DLFCN +#include +/* Define these on systems that don't have them. */ +#ifndef RTLD_NOW +#define RTLD_NOW 0 +#endif +#ifndef RTLD_LAZY +#define RTLD_LAZY RTLD_NOW +#endif +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif +#ifndef RTLD_LOCAL +#define RTLD_LOCAL 0 +#endif +#ifdef AIX +#include +#endif +#ifdef OSF1 +#include +#include +#endif +#elif defined(USE_HPSHL) +#include +#elif defined(USE_MACH_DYLD) +#include +#endif +#endif /* XP_UNIX */ + +#define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY + +#ifdef VMS +/* These are all require for the PR_GetLibraryFilePathname implementation */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma __nostandard +#pragma __member_alignment __save +#pragma __nomember_alignment +#ifdef __INITIAL_POINTER_SIZE +#pragma __required_pointer_size __save +#pragma __required_pointer_size __short +#endif + +typedef struct _imcb { + struct _imcb *imcb$l_flink; + struct _imcb *imcb$l_blink; + unsigned short int imcb$w_size; + unsigned char imcb$b_type; + char imcb$b_resv_1; + unsigned char imcb$b_access_mode; + unsigned char imcb$b_act_code; + unsigned short int imcb$w_chan; + unsigned int imcb$l_flags; + char imcb$t_image_name [40]; + unsigned int imcb$l_symvec_size; + unsigned __int64 imcb$q_ident; + void *imcb$l_starting_address; + void *imcb$l_end_address; +} IMCB; + +#pragma __member_alignment __restore +#ifdef __INITIAL_POINTER_SIZE +#pragma __required_pointer_size __restore +#endif +#pragma __standard + +typedef struct { + short buflen; + short itmcode; + void *buffer; + void *retlen; +} ITMLST; + +typedef struct { + short cond; + short count; + int rest; +} IOSB; + +typedef unsigned long int ulong_t; + +struct _imcb *IAC$GL_IMAGE_LIST = NULL; + +#define MAX_DEVNAM 64 +#define MAX_FILNAM 255 +#endif /* VMS */ + +/* + * On these platforms, symbols have a leading '_'. + */ +#if defined(SUNOS4) || defined(DARWIN) || defined(NEXTSTEP) \ + || defined(WIN16) || defined(XP_OS2) \ + || ((defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__)) +#define NEED_LEADING_UNDERSCORE +#endif + +#define PR_LD_PATHW 0x8000 /* for PR_LibSpec_PathnameU */ + +/************************************************************************/ + +struct PRLibrary { + char* name; /* Our own copy of the name string */ + PRLibrary* next; + int refCount; + const PRStaticLinkTable* staticTable; + +#ifdef XP_PC +#ifdef XP_OS2 + HMODULE dlh; +#else + HINSTANCE dlh; +#endif +#endif + +#ifdef XP_MACOSX + CFragConnectionID connection; + CFBundleRef bundle; + Ptr main; + CFMutableDictionaryRef wrappers; + const struct mach_header* image; +#endif + +#ifdef XP_UNIX +#if defined(USE_HPSHL) + shl_t dlh; +#elif defined(USE_MACH_DYLD) + NSModule dlh; +#else + void* dlh; +#endif +#endif + +#ifdef XP_BEOS + void* dlh; + void* stub_dlh; +#endif +}; + +static PRLibrary *pr_loadmap; +static PRLibrary *pr_exe_loadmap; +static PRMonitor *pr_linker_lock; +static char* _pr_currentLibPath = NULL; + +static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags); + +#ifdef WIN95 +typedef HMODULE (WINAPI *LoadLibraryWFn)(LPCWSTR); +static HMODULE WINAPI EmulateLoadLibraryW(LPCWSTR); +static LoadLibraryWFn loadLibraryW = LoadLibraryW; +#endif + +#ifdef WIN32 +static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len); +#endif + +/************************************************************************/ + +#if !defined(USE_DLFCN) && !defined(HAVE_STRERROR) +static char* errStrBuf = NULL; +#define ERR_STR_BUF_LENGTH 20 +static char* errno_string(PRIntn oserr) +{ + if (errStrBuf == NULL) + errStrBuf = PR_MALLOC(ERR_STR_BUF_LENGTH); + PR_snprintf(errStrBuf, ERR_STR_BUF_LENGTH, "error %d", oserr); + return errStrBuf; +} +#endif + +static void DLLErrorInternal(PRIntn oserr) +/* +** This whole function, and most of the code in this file, are run +** with a big hairy lock wrapped around it. Not the best of situations, +** but will eventually come up with the right answer. +*/ +{ + const char *error = NULL; +#ifdef USE_DLFCN + error = dlerror(); /* $$$ That'll be wrong some of the time - AOF */ +#elif defined(HAVE_STRERROR) + error = strerror(oserr); /* this should be okay */ +#else + error = errno_string(oserr); +#endif + if (NULL != error) + PR_SetErrorText(strlen(error), error); +} /* DLLErrorInternal */ + +void _PR_InitLinker(void) +{ + PRLibrary *lm = NULL; +#if defined(XP_UNIX) + void *h; +#endif + +#ifdef WIN95 + if (!_pr_useUnicode) { + loadLibraryW = EmulateLoadLibraryW; + } +#endif + + if (!pr_linker_lock) { + pr_linker_lock = PR_NewNamedMonitor("linker-lock"); + } + PR_EnterMonitor(pr_linker_lock); + +#if defined(XP_PC) + lm = PR_NEWZAP(PRLibrary); + lm->name = strdup("Executable"); + /* + ** In WIN32, GetProcAddress(...) expects a module handle in order to + ** get exported symbols from the executable... + ** + ** However, in WIN16 this is accomplished by passing NULL to + ** GetProcAddress(...) + */ +#if defined(_WIN32) + lm->dlh = GetModuleHandle(NULL); +#else + lm->dlh = (HINSTANCE)NULL; +#endif /* ! _WIN32 */ + + lm->refCount = 1; + lm->staticTable = NULL; + 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 */ + } +#elif defined(USE_HPSHL) + h = NULL; + /* don't abort with this NULL */ +#elif defined(USE_MACH_DYLD) + h = NULL; /* XXXX toshok */ +#else +#error no dll strategy +#endif /* USE_DLFCN */ + + lm = PR_NEWZAP(PRLibrary); + if (lm) { + lm->name = strdup("a.out"); + lm->refCount = 1; + lm->dlh = h; + lm->staticTable = NULL; + } + pr_exe_loadmap = lm; + pr_loadmap = lm; +#endif /* HAVE_DLL */ +#endif /* XP_UNIX */ + + if (lm) { + PR_LOG(_pr_linker_lm, PR_LOG_MIN, + ("Loaded library %s (init)", lm->name)); + } + + PR_ExitMonitor(pr_linker_lock); +} + +#if defined(WIN16) +/* + * _PR_ShutdownLinker unloads all dlls loaded by the application via + * calls to PR_LoadLibrary + */ +void _PR_ShutdownLinker(void) +{ + PR_EnterMonitor(pr_linker_lock); + + while (pr_loadmap) { + if (pr_loadmap->refCount > 1) { +#ifdef DEBUG + 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_ExitMonitor(pr_linker_lock); + + PR_DestroyMonitor(pr_linker_lock); + pr_linker_lock = NULL; +} +#else +/* + * _PR_ShutdownLinker was originally only used on WIN16 (see above), + * but I think it should also be used on other platforms. However, + * I disagree with the original implementation's unloading the dlls + * for the application. Any dlls that still remain on the pr_loadmap + * list when NSPR shuts down are application programming errors. The + * only exception is pr_exe_loadmap, which was added to the list by + * NSPR and hence should be cleaned up by NSPR. + */ +void _PR_ShutdownLinker(void) +{ + /* FIXME: pr_exe_loadmap should be destroyed. */ + + PR_DestroyMonitor(pr_linker_lock); + pr_linker_lock = NULL; + + if (_pr_currentLibPath) { + free(_pr_currentLibPath); + _pr_currentLibPath = NULL; + } + +#if !defined(USE_DLFCN) && !defined(HAVE_STRERROR) + PR_DELETE(errStrBuf); +#endif +} +#endif + +/******************************************************************************/ + +PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path) +{ + PRStatus rv = PR_SUCCESS; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_EnterMonitor(pr_linker_lock); + if (_pr_currentLibPath) { + free(_pr_currentLibPath); + } + if (path) { + _pr_currentLibPath = strdup(path); + if (!_pr_currentLibPath) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + rv = PR_FAILURE; + } + } else { + _pr_currentLibPath = 0; + } + PR_ExitMonitor(pr_linker_lock); + return rv; +} + +/* +** Return the library path for finding shared libraries. +*/ +PR_IMPLEMENT(char *) +PR_GetLibraryPath(void) +{ + char *ev; + char *copy = NULL; /* a copy of _pr_currentLibPath */ + + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_EnterMonitor(pr_linker_lock); + if (_pr_currentLibPath != NULL) { + goto exit; + } + + /* initialize pr_currentLibPath */ + +#ifdef XP_PC + ev = getenv("LD_LIBRARY_PATH"); + if (!ev) { + ev = ".;\\lib"; + } + ev = strdup(ev); +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) +#if defined(USE_DLFCN) || defined(USE_MACH_DYLD) || defined(XP_BEOS) + { + char *p=NULL; + int len; + +#ifdef XP_BEOS + ev = getenv("LIBRARY_PATH"); + if (!ev) { + ev = "%A/lib:/boot/home/config/lib:/boot/beos/system/lib"; + } +#else + ev = getenv("LD_LIBRARY_PATH"); + if (!ev) { + ev = "/usr/lib:/lib"; + } +#endif + len = strlen(ev) + 1; /* +1 for the null */ + + p = (char*) malloc(len); + if (p) { + strcpy(p, ev); + } /* if (p) */ + ev = p; + PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev)); + + } +#else + /* AFAIK there isn't a library path with the HP SHL interface --Rob */ + ev = strdup(""); +#endif +#endif + + /* + * If ev is NULL, we have run out of memory + */ + _pr_currentLibPath = ev; + + exit: + if (_pr_currentLibPath) { + copy = strdup(_pr_currentLibPath); + } + PR_ExitMonitor(pr_linker_lock); + if (!copy) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return copy; +} + +/* +** Build library name from path, lib and extensions +*/ +PR_IMPLEMENT(char*) +PR_GetLibraryName(const char *path, const char *lib) +{ + char *fullname; + +#ifdef XP_PC + if (strstr(lib, PR_DLL_SUFFIX) == NULL) + { + if (path) { + fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX); + } else { + fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX); + } + } else { + if (path) { + fullname = PR_smprintf("%s\\%s", path, lib); + } else { + fullname = PR_smprintf("%s", lib); + } + } +#endif /* XP_PC */ +#if defined(XP_UNIX) || defined(XP_BEOS) + if (strstr(lib, PR_DLL_SUFFIX) == NULL) + { + if (path) { + fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX); + } else { + fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX); + } + } else { + if (path) { + fullname = PR_smprintf("%s/%s", path, lib); + } else { + fullname = PR_smprintf("%s", lib); + } + } +#endif /* XP_UNIX || XP_BEOS */ + return fullname; +} + +/* +** Free the memory allocated, for the caller, by PR_GetLibraryName +*/ +PR_IMPLEMENT(void) +PR_FreeLibraryName(char *mem) +{ + PR_smprintf_free(mem); +} + +static PRLibrary* +pr_UnlockedFindLibrary(const char *name) +{ + PRLibrary* lm = pr_loadmap; + 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; +#ifdef WIN32 + /* Windows DLL names are case insensitive... */ + if (strcmpi(np, cp) == 0) +#elif defined(XP_OS2) + if (stricmp(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; + } + return NULL; +} + +PR_IMPLEMENT(PRLibrary*) +PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags) +{ + if (flags == 0) { + flags = _PR_DEFAULT_LD_FLAGS; + } + switch (libSpec.type) { + case PR_LibSpec_Pathname: + return pr_LoadLibraryByPathname(libSpec.value.pathname, flags); +#ifdef WIN32 + case PR_LibSpec_PathnameU: + /* + * cast to |char *| and set PR_LD_PATHW flag so that + * it can be cast back to PRUnichar* in the callee. + */ + return pr_LoadLibraryByPathname((const char*) + libSpec.value.pathname_u, + flags | PR_LD_PATHW); +#endif + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } +} + +PR_IMPLEMENT(PRLibrary*) +PR_LoadLibrary(const char *name) +{ + PRLibSpec libSpec; + + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = name; + return PR_LoadLibraryWithFlags(libSpec, 0); +} + +#if defined(USE_MACH_DYLD) +static NSModule +pr_LoadMachDyldModule(const char *name) +{ + NSObjectFileImage ofi; + NSModule h = NULL; + if (NSCreateObjectFileImageFromFile(name, &ofi) + == NSObjectFileImageSuccess) { + h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE + | NSLINKMODULE_OPTION_RETURN_ON_ERROR); + /* + * TODO: If NSLinkModule fails, use NSLinkEditError to retrieve + * error information. + */ + if (NSDestroyObjectFileImage(ofi) == FALSE) { + if (h) { + (void)NSUnLinkModule(h, NSUNLINKMODULE_OPTION_NONE); + h = NULL; + } + } + } + return h; +} +#endif + +#ifdef XP_MACOSX + +/* +** macLibraryLoadProc is a function definition for a Mac shared library +** loading method. The "name" param is the same full or partial pathname +** that was passed to pr_LoadLibraryByPathName. The function must fill +** in the fields of "lm" which apply to its library type. Returns +** PR_SUCCESS if successful. +*/ + +typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm); + +#ifdef __ppc__ + +/* +** CFM and its TVectors only exist on PowerPC. Other OS X architectures +** only use Mach-O as a native binary format. +*/ + +static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp) +{ + static uint32 glue[6] = { 0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420 }; + uint32* newGlue = NULL; + + if (tvp != NULL) { + CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII); + if (nameRef) { + CFMutableDataRef glueData = (CFMutableDataRef) CFDictionaryGetValue(dict, nameRef); + if (glueData == NULL) { + glueData = CFDataCreateMutable(NULL, sizeof(glue)); + if (glueData != NULL) { + newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); + memcpy(newGlue, glue, sizeof(glue)); + newGlue[0] |= ((UInt32)tvp >> 16); + newGlue[1] |= ((UInt32)tvp & 0xFFFF); + MakeDataExecutable(newGlue, sizeof(glue)); + CFDictionaryAddValue(dict, nameRef, glueData); + CFRelease(glueData); + + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: created wrapper for CFM function %s().", name)); + } + } else { + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: found wrapper for CFM function %s().", name)); + + newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); + } + CFRelease(nameRef); + } + } + + return newGlue; +} + +static PRStatus +pr_LoadViaCFM(const char *name, PRLibrary *lm) +{ + OSErr err; + Str255 errName; + FSRef ref; + FSSpec fileSpec; + Boolean tempUnusedBool; + + /* + * Make an FSSpec from the path name and call GetDiskFragment. + */ + + /* Use direct conversion of POSIX path to FSRef to FSSpec. */ + err = FSPathMakeRef((const UInt8*)name, &ref, NULL); + if (err != noErr) + return PR_FAILURE; + err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, + &fileSpec, NULL); + if (err != noErr) + return PR_FAILURE; + + /* Resolve an alias if this was one */ + err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool, + &tempUnusedBool); + if (err != noErr) + return PR_FAILURE; + + /* Finally, try to load the library */ + err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, + kLoadCFrag, &lm->connection, &lm->main, errName); + + if (err == noErr && lm->connection) { + /* + * if we're a mach-o binary, need to wrap all CFM function + * pointers. need a hash-table of already seen function + * pointers, etc. + */ + lm->wrappers = CFDictionaryCreateMutable(NULL, 16, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (lm->wrappers) { + lm->main = TV2FP(lm->wrappers, "main", lm->main); + } else + err = memFullErr; + } + return (err == noErr) ? PR_SUCCESS : PR_FAILURE; +} +#endif /* __ppc__ */ + +/* +** Creates a CFBundleRef if the pathname refers to a Mac OS X bundle +** directory. The caller is responsible for calling CFRelease() to +** deallocate. +*/ + +static PRStatus +pr_LoadCFBundle(const char *name, PRLibrary *lm) +{ + CFURLRef bundleURL; + CFBundleRef bundle = NULL; + char pathBuf[PATH_MAX]; + const char *resolvedPath; + CFStringRef pathRef; + + /* Takes care of relative paths and symlinks */ + resolvedPath = realpath(name, pathBuf); + if (!resolvedPath) + return PR_FAILURE; + + pathRef = CFStringCreateWithCString(NULL, pathBuf, kCFStringEncodingUTF8); + if (pathRef) { + bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef, + kCFURLPOSIXPathStyle, true); + if (bundleURL) { + bundle = CFBundleCreate(NULL, bundleURL); + CFRelease(bundleURL); + } + CFRelease(pathRef); + } + + lm->bundle = bundle; + return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE; +} + +static PRStatus +pr_LoadViaDyld(const char *name, PRLibrary *lm) +{ + lm->dlh = pr_LoadMachDyldModule(name); + if (lm->dlh == NULL) { + lm->image = NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR + | NSADDIMAGE_OPTION_WITH_SEARCHING); + if (lm->image == NULL) { + NSLinkEditErrors linkEditError; + int errorNum; + const char *errorString; + const char *fileName; + NSLinkEditError(&linkEditError, &errorNum, &fileName, &errorString); + PR_LOG(_pr_linker_lm, PR_LOG_MIN, + ("LoadMachDyldModule error %d:%d for file %s:\n%s", + linkEditError, errorNum, fileName, errorString)); + } + } + return (lm->dlh != NULL || lm->image != NULL) ? PR_SUCCESS : PR_FAILURE; +} + +#endif /* XP_MACOSX */ + +#ifdef WIN95 +static HMODULE WINAPI +EmulateLoadLibraryW(LPCWSTR lpLibFileName) +{ + HMODULE h; + char nameA[MAX_PATH]; + + if (!WideCharToMultiByte(CP_ACP, 0, lpLibFileName, -1, + nameA, sizeof nameA, NULL, NULL)) { + return NULL; + } + /* Perhaps it's better to add a check for characters + * not representable in CP_ACP. + */ + h = LoadLibraryA(nameA); + return h; +} +#endif /* WIN95 */ + +/* +** Dynamically load a library. Only load libraries once, so scan the load +** map first. +*/ +static PRLibrary* +pr_LoadLibraryByPathname(const char *name, PRIntn flags) +{ + PRLibrary *lm; + PRLibrary* result = NULL; + PRInt32 oserr; +#ifdef WIN32 + char utf8name_stack[MAX_PATH]; + char *utf8name_malloc = NULL; + char *utf8name = utf8name_stack; + PRUnichar wname_stack[MAX_PATH]; + PRUnichar *wname_malloc = NULL; + PRUnichar *wname = wname_stack; + int len; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* See if library is already loaded */ + PR_EnterMonitor(pr_linker_lock); + +#ifdef WIN32 + if (flags & PR_LD_PATHW) { + /* cast back what's cast to |char *| for the argument passing. */ + wname = (LPWSTR) name; + } else { + int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); + if (wlen > MAX_PATH) + wname = wname_malloc = PR_Malloc(wlen * sizeof(PRUnichar)); + if (wname == NULL || + !MultiByteToWideChar(CP_ACP, 0, name, -1, wname, wlen)) { + oserr = _MD_ERRNO(); + goto unlock; + } + } + len = pr_ConvertUTF16toUTF8(wname, NULL, 0); + if (len > MAX_PATH) + utf8name = utf8name_malloc = PR_Malloc(len); + if (utf8name == NULL || + !pr_ConvertUTF16toUTF8(wname, utf8name, len)) { + oserr = _MD_ERRNO(); + goto unlock; + } + /* the list of loaded library names are always kept in UTF-8 + * on Win32 platforms */ + result = pr_UnlockedFindLibrary(utf8name); +#else + result = pr_UnlockedFindLibrary(name); +#endif + + if (result != NULL) goto unlock; + + lm = PR_NEWZAP(PRLibrary); + if (lm == NULL) { + oserr = _MD_ERRNO(); + goto unlock; + } + lm->staticTable = NULL; + +#ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */ + { + HMODULE h; + UCHAR pszError[_MAX_PATH]; + ULONG ulRc = NO_ERROR; + + ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); + if (ulRc != NO_ERROR) { + oserr = ulRc; + 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; + +#ifdef WIN32 +#ifdef WIN95 + if (flags & PR_LD_PATHW) + h = loadLibraryW(wname); + else + h = LoadLibraryA(name); +#else + if (flags & PR_LD_PATHW) + h = LoadLibraryW(wname); + else + h = LoadLibraryA(name); +#endif /* WIN95 */ +#else + h = LoadLibrary(name); +#endif + if (h < (HINSTANCE)HINSTANCE_ERROR) { + oserr = _MD_ERRNO(); + PR_DELETE(lm); + goto unlock; + } +#ifdef WIN32 + lm->name = strdup(utf8name); +#else + lm->name = strdup(name); +#endif + lm->dlh = h; + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif /* WIN32 || WIN16 */ + +#ifdef XP_MACOSX + { + int i; + PRStatus status; + + static const macLibraryLoadProc loadProcs[] = { +#ifdef __ppc__ + pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM +#else /* __ppc__ */ + pr_LoadViaDyld, pr_LoadCFBundle +#endif /* __ppc__ */ + }; + + for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) { + if ((status = loadProcs[i](name, lm)) == PR_SUCCESS) + break; + } + if (status != PR_SUCCESS) { + oserr = cfragNoLibraryErr; + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif + +#if defined(XP_UNIX) && !defined(XP_MACOSX) +#ifdef HAVE_DLL + { +#if defined(USE_DLFCN) +#ifdef NTO + /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */ + int dl_flags = RTLD_GROUP; +#elif defined(AIX) + /* AIX needs RTLD_MEMBER to load an archive member. (bug 228899) */ + int dl_flags = RTLD_MEMBER; +#else + int dl_flags = 0; +#endif + void *h; + + if (flags & PR_LD_LAZY) { + dl_flags |= RTLD_LAZY; + } + if (flags & PR_LD_NOW) { + dl_flags |= RTLD_NOW; + } + if (flags & PR_LD_GLOBAL) { + dl_flags |= RTLD_GLOBAL; + } + if (flags & PR_LD_LOCAL) { + dl_flags |= RTLD_LOCAL; + } + h = dlopen(name, dl_flags); +#elif defined(USE_HPSHL) + int shl_flags = 0; + shl_t h; + + /* + * Use the DYNAMIC_PATH flag only if 'name' is a plain file + * name (containing no directory) to match the behavior of + * dlopen(). + */ + if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) { + shl_flags |= DYNAMIC_PATH; + } + if (flags & PR_LD_LAZY) { + shl_flags |= BIND_DEFERRED; + } + if (flags & PR_LD_NOW) { + shl_flags |= BIND_IMMEDIATE; + } + /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */ + h = shl_load(name, shl_flags, 0L); +#elif defined(USE_MACH_DYLD) + NSModule h = pr_LoadMachDyldModule(name); +#else +#error Configuration error +#endif + if (!h) { + oserr = _MD_ERRNO(); + 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; + +#ifdef XP_BEOS + { + image_info info; + int32 cookie = 0; + image_id imageid = B_ERROR; + image_id stubid = B_ERROR; + PRLibrary *p; + + for (p = pr_loadmap; p != NULL; p = p->next) { + /* hopefully, our caller will always use the same string + to refer to the same library */ + if (strcmp(name, p->name) == 0) { + /* we've already loaded this library */ + imageid = info.id; + lm->refCount++; + break; + } + } + + if(imageid == B_ERROR) { + /* it appears the library isn't yet loaded - load it now */ + char stubName [B_PATH_NAME_LENGTH + 1]; + + /* the following is a work-around to a "bug" in the beos - + the beos system loader allows only 32M (system-wide) + to be used by code loaded as "add-ons" (code loaded + through the 'load_add_on()' system call, which includes + mozilla components), but allows 256M to be used by + shared libraries. + + unfortunately, mozilla is too large to fit into the + "add-on" space, so we must trick the loader into + loading some of the components as shared libraries. this + is accomplished by creating a "stub" add-on (an empty + shared object), and linking it with the component + (the actual .so file generated by the build process, + without any modifications). when this stub is loaded + by load_add_on(), the loader will automatically load the + component into the shared library space. + */ + + strcpy(stubName, name); + strcat(stubName, ".stub"); + + /* first, attempt to load the stub (thereby loading the + component as a shared library */ + if ((stubid = load_add_on(stubName)) > B_ERROR) { + /* the stub was loaded successfully. */ + imageid = B_FILE_NOT_FOUND; + + cookie = 0; + while (get_next_image_info(0, &cookie, &info) == B_OK) { + const char *endOfSystemName = strrchr(info.name, '/'); + const char *endOfPassedName = strrchr(name, '/'); + if( 0 == endOfSystemName ) + endOfSystemName = info.name; + else + endOfSystemName++; + if( 0 == endOfPassedName ) + endOfPassedName = name; + else + endOfPassedName++; + if (strcmp(endOfSystemName, endOfPassedName) == 0) { + /* this is the actual component - remember it */ + imageid = info.id; + break; + } + } + + } else { + /* we failed to load the "stub" - try to load the + component directly as an add-on */ + stubid = B_ERROR; + imageid = load_add_on(name); + } + } + + if (imageid <= B_ERROR) { + oserr = imageid; + PR_DELETE( lm ); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = (void*)imageid; + lm->stub_dlh = (void*)stubid; + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif + + result = lm; /* success */ + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name)); + + unlock: + if (result == NULL) { + PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr); + DLLErrorInternal(oserr); /* sets error text */ + } +#ifdef WIN32 + if (utf8name_malloc) + PR_Free(utf8name_malloc); + if (wname_malloc) + PR_Free(wname_malloc); +#endif + PR_ExitMonitor(pr_linker_lock); + return result; +} + +#ifdef WIN32 +#ifdef WIN95 +/* + * CP_UTF8 is not supported by WideCharToMultiByte on Windows 95 so that + * we have to emulate it + */ +static PRStatus +pr_ConvertSingleCharToUTF8(PRUint32 usv, PRUint16 offset, int bufLen, + int *utf8Len, char * *buf) +{ + char* p = *buf; + PR_ASSERT(!bufLen || *buf); + if (!bufLen) { + *utf8Len += offset; + return PR_SUCCESS; + } + + if (*utf8Len + offset >= bufLen) + return PR_FAILURE; + + *utf8Len += offset; + if (offset == 1) { + *p++ = (char) usv; + } else if (offset == 2) { + *p++ = (char)0xc0 | (usv >> 6); + *p++ = (char)0x80 | (usv & 0x003f); + } else if (offset == 3) { + *p++ = (char)0xe0 | (usv >> 12); + *p++ = (char)0x80 | ((usv >> 6) & 0x003f); + *p++ = (char)0x80 | (usv & 0x003f); + } else { /* offset = 4 */ + *p++ = (char)0xf0 | (usv >> 18); + *p++ = (char)0x80 | ((usv >> 12) & 0x003f); + *p++ = (char)0x80 | ((usv >> 6) & 0x003f); + *p++ = (char)0x80 | (usv & 0x003f); + } + + *buf = p; + return PR_SUCCESS; +} + +static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len) +{ + LPCWSTR pw = wname; + LPSTR p = name; + int utf8Len = 0; + PRBool highSurrogate = PR_FALSE; + + utf8Len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len, + NULL, NULL); + /* + * Windows 95 and NT 3.51 don't support CP_UTF8. + * WideCharToMultiByte(CP_UTF8, ...) fails with the error code + * ERROR_INVALID_PARAMETER on Windows 95 and NT 3.51. + */ + if (utf8Len || GetLastError() != ERROR_INVALID_PARAMETER) + return utf8Len; + + if (!wname || len < 0 || (len > 0 && !name)) { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + while (*pw) { + PRStatus status = PR_SUCCESS; + if (highSurrogate) { + if (*pw >= (PRUnichar) 0xDC00 && *pw < (PRUnichar) 0xE000) { + /* found a matching low surrogate */ + /* convert a surrogate pair to UCS4 */ + PRUint32 usv = ((*(pw-1) - (PRUnichar)0xD800) << 10) + + (*pw - (PRUnichar)0xDC00) + (PRUint32)0x10000; + if (pr_ConvertSingleCharToUTF8(usv, 4, len, &utf8Len, &p) == + PR_FAILURE) + return 0; + highSurrogate = PR_FALSE; + ++pw; + continue; + } else { + /* + * silently ignore a lone high surrogate + * as is done by WideCharToMultiByte by default + */ + highSurrogate = PR_FALSE; + } + } + if (*pw <= 0x7f) + status = pr_ConvertSingleCharToUTF8(*pw, 1, len, &utf8Len, &p); + else if (*pw <= 0x07ff) + status = pr_ConvertSingleCharToUTF8(*pw, 2, len, &utf8Len, &p); + else if (*pw < (PRUnichar) 0xD800 || *pw >= (PRUnichar) 0xE000) + status = pr_ConvertSingleCharToUTF8(*pw, 3, len, &utf8Len, &p); + else if (*pw < (PRUnichar) 0xDC00) + highSurrogate = PR_TRUE; + /* else */ + /* silently ignore a lone low surrogate as is done by + * WideCharToMultiByte by default */ + + if (status == PR_FAILURE) { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + ++pw; + } + + /* if we're concerned with a lone high surrogate, + * we have to take care of it here, but we just drop it + */ + if (len > 0) + *p = '\0'; + return utf8Len + 1; +} +#else +static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len) +{ + return WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len, NULL, NULL); +} +#endif /* WIN95 */ +#endif /* WIN32 */ + +/* +** Unload a shared library which was loaded via PR_LoadLibrary +*/ +PR_IMPLEMENT(PRStatus) +PR_UnloadLibrary(PRLibrary *lib) +{ + int result = 0; + PRStatus status = PR_SUCCESS; + + if ((lib == 0) || (lib->refCount <= 0)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + 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; + } + +#ifdef XP_BEOS + if(((image_id)lib->stub_dlh) == B_ERROR) + unload_add_on( (image_id) lib->dlh ); + else + unload_add_on( (image_id) lib->stub_dlh); +#endif + +#ifdef XP_UNIX +#ifdef HAVE_DLL +#ifdef USE_DLFCN + result = dlclose(lib->dlh); +#elif defined(USE_HPSHL) + result = shl_unload(lib->dlh); +#elif defined(USE_MACH_DYLD) + if (lib->dlh) + result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1; +#else +#error Configuration error +#endif +#endif /* HAVE_DLL */ +#endif /* XP_UNIX */ +#ifdef XP_PC + if (lib->dlh) { + FreeLibrary((HINSTANCE)(lib->dlh)); + lib->dlh = (HINSTANCE)NULL; + } +#endif /* XP_PC */ + +#ifdef XP_MACOSX + /* Close the connection */ + if (lib->connection) + CloseConnection(&(lib->connection)); + if (lib->bundle) + CFRelease(lib->bundle); + if (lib->wrappers) + CFRelease(lib->wrappers); + /* No way to unload an image (lib->image) */ +#endif + + /* unlink from library search list */ + if (pr_loadmap == lib) + 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; + } + /* + * fail (the library is not on the _pr_loadmap list), + * but don't wipe out an error from dlclose/shl_unload. + */ + PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent"); + if (result == 0) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + status = PR_FAILURE; + } + } + /* + * We free the PRLibrary structure whether dlclose/shl_unload + * succeeds or not. + */ + + freeLib: + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name)); + free(lib->name); + lib->name = NULL; + PR_DELETE(lib); + if (result != 0) { + PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + status = PR_FAILURE; + } + +done: + PR_ExitMonitor(pr_linker_lock); + return status; +} + +static void* +pr_FindSymbolInLib(PRLibrary *lm, const char *name) +{ + void *f = NULL; +#ifdef XP_OS2 + int rc; +#endif + + if (lm->staticTable != NULL) { + 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!! + */ +#if !defined(WIN16) && !defined(XP_BEOS) + PR_SetError(PR_FIND_SYMBOL_ERROR, 0); + return (void*)NULL; +#endif + } + +#ifdef XP_OS2 + rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); +#if defined(NEED_LEADING_UNDERSCORE) + /* + * Older plugins (not built using GCC) will have symbols that are not + * underscore prefixed. We check for that here. + */ + if (rc != NO_ERROR) { + name++; + DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); + } +#endif +#endif /* XP_OS2 */ + +#if defined(WIN32) || defined(WIN16) + f = GetProcAddress(lm->dlh, name); +#endif /* WIN32 || WIN16 */ + +#ifdef XP_MACOSX +/* add this offset to skip the leading underscore in name */ +#define SYM_OFFSET 1 + if (lm->bundle) { + CFStringRef nameRef = CFStringCreateWithCString(NULL, name + SYM_OFFSET, kCFStringEncodingASCII); + if (nameRef) { + f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef); + CFRelease(nameRef); + } + } + if (lm->connection) { + Ptr symAddr; + CFragSymbolClass symClass; + Str255 pName; + + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET)); + + c2pstrcpy(pName, name + SYM_OFFSET); + + f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; + +#ifdef __ppc__ + /* callers expect mach-o function pointers, so must wrap tvectors with glue. */ + if (f && symClass == kTVectorCFragSymbol) { + f = TV2FP(lm->wrappers, name + SYM_OFFSET, f); + } +#endif /* __ppc__ */ + + if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main; + } + if (lm->image) { + NSSymbol symbol; + symbol = NSLookupSymbolInImage(lm->image, name, + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND + | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); + if (symbol != NULL) + f = NSAddressOfSymbol(symbol); + else + f = NULL; + } +#undef SYM_OFFSET +#endif /* XP_MACOSX */ + +#ifdef XP_BEOS + if( B_NO_ERROR != get_image_symbol( (image_id)lm->dlh, name, B_SYMBOL_TYPE_TEXT, &f ) ) { + f = NULL; + } +#endif + +#ifdef XP_UNIX +#ifdef HAVE_DLL +#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_MACH_DYLD) + if (lm->dlh) { + NSSymbol symbol; + symbol = NSLookupSymbolInModule(lm->dlh, name); + if (symbol != NULL) + f = NSAddressOfSymbol(symbol); + else + f = NULL; + } +#endif +#endif /* HAVE_DLL */ +#endif /* XP_UNIX */ + if (f == NULL) { + PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + } + return f; +} + +/* +** Called by class loader to resolve missing native's +*/ +PR_IMPLEMENT(void*) +PR_FindSymbol(PRLibrary *lib, const char *raw_name) +{ + void *f = NULL; +#if defined(NEED_LEADING_UNDERSCORE) + char *name; +#else + const char *name; +#endif + /* + ** Mangle the raw symbol name in any way that is platform specific. + */ +#if defined(NEED_LEADING_UNDERSCORE) + /* Need a leading _ */ + name = PR_smprintf("_%s", raw_name); +#elif defined(AIX) + /* + ** AIX with the normal linker put's a "." in front of the symbol + ** name. When use "svcc" and "svld" then the "." disappears. Go + ** figure. + */ + name = raw_name; +#else + name = raw_name; +#endif + + PR_EnterMonitor(pr_linker_lock); + PR_ASSERT(lib != NULL); + f = pr_FindSymbolInLib(lib, name); + +#if defined(NEED_LEADING_UNDERSCORE) + PR_smprintf_free(name); +#endif + + PR_ExitMonitor(pr_linker_lock); + return f; +} + +/* +** Return the address of the function 'raw_name' in the library 'lib' +*/ +PR_IMPLEMENT(PRFuncPtr) +PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name) +{ + return ((PRFuncPtr) PR_FindSymbol(lib, raw_name)); +} + +PR_IMPLEMENT(void*) +PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) +{ + void *f = NULL; +#if defined(NEED_LEADING_UNDERSCORE) + char *name; +#else + const char *name; +#endif + PRLibrary* lm; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + /* + ** Mangle the raw symbol name in any way that is platform specific. + */ +#if defined(NEED_LEADING_UNDERSCORE) + /* Need a leading _ */ + name = PR_smprintf("_%s", raw_name); +#elif defined(AIX) + /* + ** AIX with the normal linker put's a "." in front of the symbol + ** name. When use "svcc" and "svld" then the "." disappears. Go + ** figure. + */ + name = 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(NEED_LEADING_UNDERSCORE) + PR_smprintf_free(name); +#endif + + PR_ExitMonitor(pr_linker_lock); + return f; +} + +PR_IMPLEMENT(PRFuncPtr) +PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) +{ + return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib)); +} + +/* +** Add a static library to the list of loaded libraries. If LoadLibrary +** is called with the name then we will pretend it was already loaded +*/ +PR_IMPLEMENT(PRLibrary*) +PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt) +{ + PRLibrary *lm=NULL; + PRLibrary* result = NULL; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* See if library is already loaded */ + PR_EnterMonitor(pr_linker_lock); + + /* If the lbrary is already loaded, then add the static table information... */ + result = pr_UnlockedFindLibrary(name); + if (result != NULL) { + PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) ); + result->staticTable = slt; + goto unlock; + } + + /* Add library to list...Mark it static */ + lm = PR_NEWZAP(PRLibrary); + if (lm == NULL) goto unlock; + + lm->name = strdup(name); + lm->refCount = 1; + lm->dlh = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0; + lm->staticTable = slt; + lm->next = pr_loadmap; + pr_loadmap = lm; + + result = lm; /* success */ + PR_ASSERT(lm->refCount == 1); + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name)); + unlock: + PR_ExitMonitor(pr_linker_lock); + return result; +} + +PR_IMPLEMENT(char *) +PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr) +{ +#if defined(USE_DLFCN) && (defined(SOLARIS) || defined(FREEBSD) \ + || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__)) + Dl_info dli; + char *result; + + if (dladdr((void *)addr, &dli) == 0) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + result = PR_Malloc(strlen(dli.dli_fname)+1); + if (result != NULL) { + strcpy(result, dli.dli_fname); + } + return result; +#elif defined(USE_MACH_DYLD) + char *result; + const char *image_name; + int i, count = _dyld_image_count(); + + for (i = 0; i < count; i++) { + image_name = _dyld_get_image_name(i); + if (strstr(image_name, name) != NULL) { + result = PR_Malloc(strlen(image_name)+1); + if (result != NULL) { + strcpy(result, image_name); + } + return result; + } + } + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + return NULL; +#elif defined(AIX) + char *result; +#define LD_INFO_INCREMENT 64 + struct ld_info *info; + unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info); + struct ld_info *infop; + int loadflags = L_GETINFO | L_IGNOREUNLOAD; + + for (;;) { + info = PR_Malloc(info_length); + if (info == NULL) { + return NULL; + } + /* If buffer is too small, loadquery fails with ENOMEM. */ + if (loadquery(loadflags, info, info_length) != -1) { + break; + } + /* + * Calling loadquery when compiled for 64-bit with the + * L_IGNOREUNLOAD flag can cause an invalid argument error + * on AIX 5.1. Detect this error the first time that + * loadquery is called, and try calling it again without + * this flag set. + */ + if (errno == EINVAL && (loadflags & L_IGNOREUNLOAD)) { + loadflags &= ~L_IGNOREUNLOAD; + if (loadquery(loadflags, info, info_length) != -1) { + break; + } + } + PR_Free(info); + if (errno != ENOMEM) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + return NULL; + } + /* retry with a larger buffer */ + info_length += LD_INFO_INCREMENT * sizeof(struct ld_info); + } + + for (infop = info; + ; + infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) { + unsigned long start = (unsigned long)infop->ldinfo_dataorg; + unsigned long end = start + infop->ldinfo_datasize; + if (start <= (unsigned long)addr && end > (unsigned long)addr) { + result = PR_Malloc(strlen(infop->ldinfo_filename)+1); + if (result != NULL) { + strcpy(result, infop->ldinfo_filename); + } + break; + } + if (!infop->ldinfo_next) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + result = NULL; + break; + } + } + PR_Free(info); + return result; +#elif defined(OSF1) + /* Contributed by Steve Streeter of HP */ + ldr_process_t process, ldr_my_process(); + ldr_module_t mod_id; + ldr_module_info_t info; + ldr_region_t regno; + ldr_region_info_t reginfo; + size_t retsize; + int rv; + char *result; + + /* Get process for which dynamic modules will be listed */ + + process = ldr_my_process(); + + /* Attach to process */ + + rv = ldr_xattach(process); + if (rv) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + return NULL; + } + + /* Print information for list of modules */ + + mod_id = LDR_NULL_MODULE; + + for (;;) { + + /* Get information for the next module in the module list. */ + + ldr_next_module(process, &mod_id); + if (ldr_inq_module(process, mod_id, &info, sizeof(info), + &retsize) != 0) { + /* No more modules */ + break; + } + if (retsize < sizeof(info)) { + continue; + } + + /* + * Get information for each region in the module and check if any + * contain the address of this function. + */ + + for (regno = 0; ; regno++) { + if (ldr_inq_region(process, mod_id, regno, ®info, + sizeof(reginfo), &retsize) != 0) { + /* No more regions */ + break; + } + if (((unsigned long)reginfo.lri_mapaddr <= + (unsigned long)addr) && + (((unsigned long)reginfo.lri_mapaddr + reginfo.lri_size) > + (unsigned long)addr)) { + /* Found it. */ + result = PR_Malloc(strlen(info.lmi_name)+1); + if (result != NULL) { + strcpy(result, info.lmi_name); + } + return result; + } + } + } + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + return NULL; +#elif defined(VMS) + /* Contributed by Colin Blake of HP */ + struct _imcb *icb; + ulong_t status; + char device_name[MAX_DEVNAM]; + int device_name_len; + $DESCRIPTOR (device_name_desc, device_name); + struct fibdef fib; + struct dsc$descriptor_s fib_desc = + { sizeof(struct fibdef), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (char *)&fib } ; + IOSB iosb; + ITMLST devlst[2] = { + {MAX_DEVNAM, DVI$_ALLDEVNAM, device_name, &device_name_len}, + {0,0,0,0}}; + short file_name_len; + char file_name[MAX_FILNAM+1]; + char *result = NULL; + struct dsc$descriptor_s file_name_desc = + { MAX_FILNAM, DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) &file_name[0] } ; + + /* + ** The address for the process image list could change in future versions + ** of the operating system. 7FFD0688 is valid for V7.2 and V7.3 releases, + ** so we use that for the default, but allow an environment variable + ** (logical name) to override. + */ + if (IAC$GL_IMAGE_LIST == NULL) { + char *p = getenv("MOZILLA_IAC_GL_IMAGE_LIST"); + if (p) + IAC$GL_IMAGE_LIST = (struct _imcb *) strtol(p,NULL,0); + else + IAC$GL_IMAGE_LIST = (struct _imcb *) 0x7FFD0688; + } + + for (icb = IAC$GL_IMAGE_LIST->imcb$l_flink; + icb != IAC$GL_IMAGE_LIST; + icb = icb->imcb$l_flink) { + if (((void *)addr >= icb->imcb$l_starting_address) && + ((void *)addr <= icb->imcb$l_end_address)) { + /* + ** This is the correct image. + ** Get the device name. + */ + status = sys$getdviw(0,icb->imcb$w_chan,0,&devlst,0,0,0,0); + if ($VMS_STATUS_SUCCESS(status)) + device_name_desc.dsc$w_length = device_name_len; + + /* + ** Get the FID. + */ + memset(&fib,0,sizeof(struct fibdef)); + status = sys$qiow(0,icb->imcb$w_chan,IO$_ACCESS,&iosb, + 0,0,&fib_desc,0,0,0,0,0); + + /* + ** If we got the FID, now look up its name (if for some reason + ** we didn't get the device name, this call will fail). + */ + if (($VMS_STATUS_SUCCESS(status)) && ($VMS_STATUS_SUCCESS(iosb.cond))) { + status = lib$fid_to_name ( + &device_name_desc, + &fib.fib$w_fid, + &file_name_desc, + &file_name_len, + 0, 0); + + /* + ** If we succeeded then remove the version number and + ** return a copy of the UNIX format version of the file name. + */ + if ($VMS_STATUS_SUCCESS(status)) { + char *p, *result; + file_name[file_name_len] = 0; + p = strrchr(file_name,';'); + if (p) *p = 0; + p = decc$translate_vms(&file_name[0]); + result = PR_Malloc(strlen(p)+1); + if (result != NULL) { + strcpy(result, p); + } + return result; + } + } + } + } + + /* Didn't find it */ + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + return NULL; + +#elif defined(HPUX) && defined(USE_HPSHL) + int index; + struct shl_descriptor desc; + char *result; + + for (index = 0; shl_get_r(index, &desc) == 0; index++) { + if (strstr(desc.filename, name) != NULL) { + result = PR_Malloc(strlen(desc.filename)+1); + if (result != NULL) { + strcpy(result, desc.filename); + } + return result; + } + } + /* + * Since the index value of a library is decremented if + * a library preceding it in the shared library search + * list was unloaded, it is possible that we missed some + * libraries as we went up the list. So we should go + * down the list to be sure that we not miss anything. + */ + for (index--; index >= 0; index--) { + if ((shl_get_r(index, &desc) == 0) + && (strstr(desc.filename, name) != NULL)) { + result = PR_Malloc(strlen(desc.filename)+1); + if (result != NULL) { + strcpy(result, desc.filename); + } + return result; + } + } + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + return NULL; +#elif defined(HPUX) && defined(USE_DLFCN) + struct load_module_desc desc; + char *result; + const char *module_name; + + if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0); + if (module_name == NULL) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + result = PR_Malloc(strlen(module_name)+1); + if (result != NULL) { + strcpy(result, module_name); + } + return result; +#elif defined(WIN32) + HMODULE handle; + char module_name[MAX_PATH]; + char *result; + + handle = GetModuleHandle(name); + if (handle == NULL) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + if (GetModuleFileName(handle, module_name, sizeof module_name) == 0) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + return NULL; + } + result = PR_Malloc(strlen(module_name)+1); + if (result != NULL) { + strcpy(result, module_name); + } + return result; +#elif defined(XP_OS2) + HMODULE module = NULL; + char module_name[_MAX_PATH]; + char *result; + APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr); + if ((NO_ERROR != ulrc) || (NULL == module) ) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + ulrc = DosQueryModuleName(module, sizeof module_name, module_name); + if (NO_ERROR != ulrc) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + return NULL; + } + result = PR_Malloc(strlen(module_name)+1); + if (result != NULL) { + strcpy(result, module_name); + } + return result; +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +#endif +} diff --git a/nsprpub/pr/src/malloc/.cvsignore b/nsprpub/pr/src/malloc/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/malloc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/malloc/Makefile.in b/nsprpub/pr/src/malloc/Makefile.in new file mode 100644 index 00000000000..981ec4625f5 --- /dev/null +++ b/nsprpub/pr/src/malloc/Makefile.in @@ -0,0 +1,67 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +CSRCS = prmalloc.c prmem.c + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/pr/src/malloc/prmalloc.c b/nsprpub/pr/src/malloc/prmalloc.c new file mode 100644 index 00000000000..10e9cf78b75 --- /dev/null +++ b/nsprpub/pr/src/malloc/prmalloc.c @@ -0,0 +1,1174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/* +** We override malloc etc. on any platform which has preemption + +** nspr20 user level threads. When we're debugging, we can make our +** version of malloc fail occasionally. +*/ +#ifdef _PR_OVERRIDE_MALLOC + +/* +** Thread safe version of malloc, calloc, realloc, free +*/ +#include + +#ifdef DEBUG +#define SANITY +#define EXTRA_SANITY +#else +#undef SANITY +#undef EXTRA_SANITY +#endif + +/* Forward decls */ +void *_PR_UnlockedMalloc(size_t size); +void _PR_UnlockedFree(void *ptr); +void *_PR_UnlockedRealloc(void *ptr, size_t size); +void *_PR_UnlockedCalloc(size_t n, size_t elsize); + +/************************************************************************/ + +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + */ + +/* + * Defining SANITY will enable some checks which will tell you if the users + * program did botch something + */ + +/* + * Defining EXTRA_SANITY will enable some checks which are mostly related + * to internal conditions in malloc.c + */ + +/* + * Very verbose progress on stdout... + */ +#if 0 +# define TRACE(foo) printf foo +static int malloc_event; +#else +# define TRACE(foo) +#endif + +/* XXX Pick a number, any number */ +# define malloc_pagesize 4096UL +# define malloc_pageshift 12UL + +#ifdef XP_UNIX +#include +#include +#include +#include +#include +#include +#include +#endif + +/* + * This structure describes a page's worth of chunks. + */ + +struct pginfo { + struct pginfo *next; /* next on the free list */ + char *page; /* Pointer to the page */ + u_short size; /* size of this page's chunks */ + u_short shift; /* How far to shift for this size chunks */ + u_short free; /* How many free chunks */ + u_short total; /* How many chunk */ + u_long bits[1]; /* Which chunks are free */ +}; + +struct pgfree { + struct pgfree *next; /* next run of free pages */ + struct pgfree *prev; /* prev run of free pages */ + char *page; /* pointer to free pages */ + char *end; /* pointer to end of free pages */ + u_long size; /* number of bytes free */ +}; + +/* + * How many bits per u_long in the bitmap. + * Change only if not 8 bits/byte + */ +#define MALLOC_BITS (8*sizeof(u_long)) + +/* + * Magic values to put in the page_directory + */ +#define MALLOC_NOT_MINE ((struct pginfo*) 0) +#define MALLOC_FREE ((struct pginfo*) 1) +#define MALLOC_FIRST ((struct pginfo*) 2) +#define MALLOC_FOLLOW ((struct pginfo*) 3) +#define MALLOC_MAGIC ((struct pginfo*) 4) + +/* + * Set to one when malloc_init has been called + */ +static unsigned initialized; + +/* + * The size of a page. + * Must be a integral multiplum of the granularity of mmap(2). + * Your toes will curl if it isn't a power of two + */ +#define malloc_pagemask ((malloc_pagesize)-1) + +/* + * The size of the largest chunk. + * Half a page. + */ +#define malloc_maxsize ((malloc_pagesize)>>1) + +/* + * malloc_pagesize == 1 << malloc_pageshift + */ +#ifndef malloc_pageshift +static unsigned malloc_pageshift; +#endif /* malloc_pageshift */ + +/* + * The smallest allocation we bother about. + * Must be power of two + */ +#ifndef malloc_minsize +static unsigned malloc_minsize; +#endif /* malloc_minsize */ + +/* + * The largest chunk we care about. + * Must be smaller than pagesize + * Must be power of two + */ +#ifndef malloc_maxsize +static unsigned malloc_maxsize; +#endif /* malloc_maxsize */ + +#ifndef malloc_cache +static unsigned malloc_cache; +#endif /* malloc_cache */ + +/* + * The offset from pagenumber to index into the page directory + */ +static u_long malloc_origo; + +/* + * The last index in the page directory we care about + */ +static u_long last_index; + +/* + * Pointer to page directory. + * Allocated "as if with" malloc + */ +static struct pginfo **page_dir; + +/* + * How many slots in the page directory + */ +static unsigned malloc_ninfo; + +/* + * Free pages line up here + */ +static struct pgfree free_list; + +/* + * Abort() if we fail to get VM ? + */ +static int malloc_abort; + +#ifdef SANITY +/* + * Are we trying to die ? + */ +static int suicide; +#endif + +/* + * dump statistics + */ +static int malloc_stats; + +/* + * always realloc ? + */ +static int malloc_realloc; + +/* + * my last break. + */ +static void *malloc_brk; + +/* + * one location cache for free-list holders + */ +static struct pgfree *px; + +static int set_pgdir(void *ptr, struct pginfo *info); +static int extend_page_directory(u_long index); + +#ifdef SANITY +void +malloc_dump(FILE *fd) +{ + struct pginfo **pd; + struct pgfree *pf; + int j; + + pd = page_dir; + + /* print out all the pages */ + for(j=0;j<=last_index;j++) { + fprintf(fd,"%08lx %5d ",(j+malloc_origo) << malloc_pageshift,j); + if (pd[j] == MALLOC_NOT_MINE) { + for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) + ; + j--; + fprintf(fd,".. %5d not mine\n", j); + } else if (pd[j] == MALLOC_FREE) { + for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) + ; + j--; + fprintf(fd,".. %5d free\n", j); + } else if (pd[j] == MALLOC_FIRST) { + for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) + ; + j--; + fprintf(fd,".. %5d in use\n", j); + } else if (pd[j] < MALLOC_MAGIC) { + fprintf(fd,"(%p)\n", pd[j]); + } else { + fprintf(fd,"%p %d (of %d) x %d @ %p --> %p\n", + pd[j],pd[j]->free, pd[j]->total, + pd[j]->size, pd[j]->page, pd[j]->next); + } + } + + for(pf=free_list.next; pf; pf=pf->next) { + fprintf(fd,"Free: @%p [%p...%p[ %ld ->%p <-%p\n", + pf,pf->page,pf->end,pf->size,pf->prev,pf->next); + if (pf == pf->next) { + fprintf(fd,"Free_list loops.\n"); + break; + } + } + + /* print out various info */ + fprintf(fd,"Minsize\t%d\n",malloc_minsize); + fprintf(fd,"Maxsize\t%ld\n",malloc_maxsize); + fprintf(fd,"Pagesize\t%ld\n",malloc_pagesize); + fprintf(fd,"Pageshift\t%ld\n",malloc_pageshift); + fprintf(fd,"FirstPage\t%ld\n",malloc_origo); + fprintf(fd,"LastPage\t%ld %lx\n",last_index+malloc_pageshift, + (last_index + malloc_pageshift) << malloc_pageshift); + fprintf(fd,"Break\t%ld\n",(u_long)sbrk(0) >> malloc_pageshift); +} + +static void wrterror(char *fmt, ...) +{ + char *q = "malloc() error: "; + char buf[100]; + va_list ap; + + suicide = 1; + + va_start(ap, fmt); + PR_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + fputs(q, stderr); + fputs(buf, stderr); + + malloc_dump(stderr); + PR_Abort(); +} + +static void wrtwarning(char *fmt, ...) +{ + char *q = "malloc() warning: "; + char buf[100]; + va_list ap; + + va_start(ap, fmt); + PR_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + fputs(q, stderr); + fputs(buf, stderr); +} +#endif /* SANITY */ + + +/* + * Allocate a number of pages from the OS + */ +static caddr_t +map_pages(int pages, int update) +{ + caddr_t result,tail; + + result = ((caddr_t)sbrk(0)) + malloc_pagemask - 1; + result = (caddr_t) ((u_long)result & ~malloc_pagemask); + tail = result + (pages << malloc_pageshift); + if (!brk(tail)) { + last_index = ((u_long)tail >> malloc_pageshift) - malloc_origo -1; + malloc_brk = tail; + TRACE(("%6d S %p .. %p\n",malloc_event++, result, tail)); + if (!update || last_index < malloc_ninfo || + extend_page_directory(last_index)) + return result; + } + TRACE(("%6d s %d %p %d\n",malloc_event++,pages,sbrk(0),errno)); +#ifdef EXTRA_SANITY + wrterror("map_pages fails\n"); +#endif + return 0; +} + +#define set_bit(_pi,_bit) \ + (_pi)->bits[(_bit)/MALLOC_BITS] |= 1L<<((_bit)%MALLOC_BITS) + +#define clr_bit(_pi,_bit) \ + (_pi)->bits[(_bit)/MALLOC_BITS] &= ~(1L<<((_bit)%MALLOC_BITS)); + +#define tst_bit(_pi,_bit) \ + ((_pi)->bits[(_bit)/MALLOC_BITS] & (1L<<((_bit)%MALLOC_BITS))) + +/* + * Extend page directory + */ +static int +extend_page_directory(u_long index) +{ + struct pginfo **young, **old; + int i; + + TRACE(("%6d E %lu\n",malloc_event++,index)); + + /* Make it this many pages */ + i = index * sizeof *page_dir; + i /= malloc_pagesize; + i += 2; + + /* Get new pages, if you used this much mem you don't care :-) */ + young = (struct pginfo**) map_pages(i,0); + if (!young) + return 0; + + /* Copy the old stuff */ + memset(young, 0, i * malloc_pagesize); + memcpy(young, page_dir, + malloc_ninfo * sizeof *page_dir); + + /* register the new size */ + malloc_ninfo = i * malloc_pagesize / sizeof *page_dir; + + /* swap the pointers */ + old = page_dir; + page_dir = young; + + /* Mark the pages */ + index = ((u_long)young >> malloc_pageshift) - malloc_origo; + page_dir[index] = MALLOC_FIRST; + while (--i) { + page_dir[++index] = MALLOC_FOLLOW; + } + + /* Now free the old stuff */ + _PR_UnlockedFree(old); + return 1; +} + +/* + * Set entry in page directory. + * Extend page directory if need be. + */ +static int +set_pgdir(void *ptr, struct pginfo *info) +{ + u_long index = ((u_long)ptr >> malloc_pageshift) - malloc_origo; + + if (index >= malloc_ninfo && !extend_page_directory(index)) + return 0; + page_dir[index] = info; + return 1; +} + +/* + * Initialize the world + */ +static void +malloc_init (void) +{ + int i; + char *p; + + TRACE(("%6d I\n",malloc_event++)); +#ifdef DEBUG + for (p=getenv("MALLOC_OPTIONS"); p && *p; p++) { + switch (*p) { + case 'a': malloc_abort = 0; break; + case 'A': malloc_abort = 1; break; + case 'd': malloc_stats = 0; break; + case 'D': malloc_stats = 1; break; + case 'r': malloc_realloc = 0; break; + case 'R': malloc_realloc = 1; break; + default: + wrtwarning("Unknown chars in MALLOC_OPTIONS\n"); + break; + } + } +#endif + +#ifndef malloc_pagesize + /* determine our pagesize */ + malloc_pagesize = getpagesize(); +#endif /* malloc_pagesize */ + +#ifndef malloc_pageshift + /* determine how much we shift by to get there */ + for (i = malloc_pagesize; i > 1; i >>= 1) + malloc_pageshift++; +#endif /* malloc_pageshift */ + +#ifndef malloc_cache + malloc_cache = 50 << malloc_pageshift; +#endif /* malloc_cache */ + +#ifndef malloc_minsize + /* + * find the smallest size allocation we will bother about. + * this is determined as the smallest allocation that can hold + * it's own pginfo; + */ + i = 2; + for(;;) { + int j; + + /* Figure out the size of the bits */ + j = malloc_pagesize/i; + j /= 8; + if (j < sizeof(u_long)) + j = sizeof (u_long); + if (sizeof(struct pginfo) + j - sizeof (u_long) <= i) + break; + i += i; + } + malloc_minsize = i; +#endif /* malloc_minsize */ + + + /* Allocate one page for the page directory */ + page_dir = (struct pginfo **) map_pages(1,0); +#ifdef SANITY + if (!page_dir) + wrterror("fatal: my first mmap failed. (check limits ?)\n"); +#endif + + /* + * We need a maximum of malloc_pageshift buckets, steal these from the + * front of the page_directory; + */ + malloc_origo = (u_long) page_dir >> malloc_pageshift; + malloc_origo -= malloc_pageshift; + + /* Clear it */ + memset(page_dir,0,malloc_pagesize); + + /* Find out how much it tells us */ + malloc_ninfo = malloc_pagesize / sizeof *page_dir; + + /* Plug the page directory into itself */ + i = set_pgdir(page_dir,MALLOC_FIRST); +#ifdef SANITY + if (!i) + wrterror("fatal: couldn't set myself in the page directory\n"); +#endif + + /* Been here, done that */ + initialized++; +} + +/* + * Allocate a number of complete pages + */ +static void *malloc_pages(size_t size) +{ + void *p,*delay_free = 0; + int i; + struct pgfree *pf; + u_long index; + + /* How many pages ? */ + size += (malloc_pagesize-1); + size &= ~malloc_pagemask; + + p = 0; + /* Look for free pages before asking for more */ + for(pf = free_list.next; pf; pf = pf->next) { +#ifdef EXTRA_SANITY + if (pf->page == pf->end) + wrterror("zero entry on free_list\n"); + if (pf->page > pf->end) { + TRACE(("%6d !s %p %p %p <%d>\n",malloc_event++, + pf,pf->page,pf->end,__LINE__)); + wrterror("sick entry on free_list\n"); + } + if ((void*)pf->page >= (void*)sbrk(0)) + wrterror("entry on free_list past brk\n"); + if (page_dir[((u_long)pf->page >> malloc_pageshift) - malloc_origo] + != MALLOC_FREE) { + TRACE(("%6d !f %p %p %p <%d>\n",malloc_event++, + pf,pf->page,pf->end,__LINE__)); + wrterror("non-free first page on free-list\n"); + } + if (page_dir[((u_long)pf->end >> malloc_pageshift) - 1 - malloc_origo] + != MALLOC_FREE) + wrterror("non-free last page on free-list\n"); +#endif /* EXTRA_SANITY */ + if (pf->size < size) + continue; + else if (pf->size == size) { + p = pf->page; + if (pf->next) + pf->next->prev = pf->prev; + pf->prev->next = pf->next; + delay_free = pf; + break; + } else { + p = pf->page; + pf->page += size; + pf->size -= size; + break; + } + } +#ifdef EXTRA_SANITY + if (p && page_dir[((u_long)p >> malloc_pageshift) - malloc_origo] + != MALLOC_FREE) { + wrterror("allocated non-free page on free-list\n"); + } +#endif /* EXTRA_SANITY */ + + size >>= malloc_pageshift; + + /* Map new pages */ + if (!p) + p = map_pages(size,1); + + if (p) { + /* Mark the pages in the directory */ + index = ((u_long)p >> malloc_pageshift) - malloc_origo; + page_dir[index] = MALLOC_FIRST; + for (i=1;i> bits)+MALLOC_BITS-1) / MALLOC_BITS); + if ((1<<(bits)) <= l+l) { + bp = (struct pginfo *)pp; + } else { + bp = (struct pginfo *)_PR_UnlockedMalloc(l); + } + if (!bp) + return 0; + bp->size = (1<shift = bits; + bp->total = bp->free = malloc_pagesize >> bits; + bp->next = page_dir[bits]; + bp->page = (char*)pp; + i = set_pgdir(pp,bp); + if (!i) + return 0; + + /* We can safely assume that there is nobody in this chain */ + page_dir[bits] = bp; + + /* set all valid bits in the bits */ + k = bp->total; + i = 0; +/* + for(;k-i >= MALLOC_BITS; i += MALLOC_BITS) + bp->bits[i / MALLOC_BITS] = ~0; +*/ + for(; i < k; i++) + set_bit(bp,i); + + if (bp != pp) + return 1; + + /* We may have used the first ones already */ + for(i=0;l > 0;i++) { + clr_bit(bp,i); + bp->free--; + bp->total--; + l -= (1 << bits); + } + return 1; +} + +/* + * Allocate a fragment + */ +static void *malloc_bytes(size_t size) +{ + size_t s; + int j; + struct pginfo *bp; + int k; + u_long *lp, bf; + + /* Don't bother with anything less than this */ + if (size < malloc_minsize) { + size = malloc_minsize; + } + + /* Find the right bucket */ + j = 1; + s = size - 1; + while (s >>= 1) { + j++; + } + + /* If it's empty, make a page more of that size chunks */ + if (!page_dir[j] && !malloc_make_chunks(j)) + return 0; + + /* Find first word of bitmap which isn't empty */ + bp = page_dir[j]; + for (lp = bp->bits; !*lp; lp++) + ; + + /* Find that bit */ + bf = *lp; + k = 0; + while ((bf & 1) == 0) { + bf >>= 1; + k++; + } + + *lp ^= 1L<free--; + if (!bp->free) { + page_dir[j] = bp->next; + bp->next = 0; + } + k += (lp - bp->bits)*MALLOC_BITS; + return bp->page + (k << bp->shift); +} + +void *_PR_UnlockedMalloc(size_t size) +{ + void *result; + + /* Round up to a multiple of 8 bytes */ + if (size & 7) { + size = size + 8 - (size & 7); + } + + if (!initialized) + malloc_init(); + +#ifdef SANITY + if (suicide) + PR_Abort(); +#endif + + if (size <= malloc_maxsize) + result = malloc_bytes(size); + else + result = malloc_pages(size); +#ifdef SANITY + if (malloc_abort && !result) + wrterror("malloc() returns NULL\n"); +#endif + TRACE(("%6d M %p %d\n",malloc_event++,result,size)); + + return result; +} + +void *_PR_UnlockedMemalign(size_t alignment, size_t size) +{ + void *result; + + /* + * alignment has to be a power of 2 + */ + + if ((size <= alignment) && (alignment <= malloc_maxsize)) + size = alignment; + else + size += alignment - 1; + + /* Round up to a multiple of 8 bytes */ + if (size & 7) { + size = size + 8 - (size & 7); + } + + if (!initialized) + malloc_init(); + +#ifdef SANITY + if (suicide) + abort(); +#endif + + if (size <= malloc_maxsize) + result = malloc_bytes(size); + else + result = malloc_pages(size); +#ifdef SANITY + if (malloc_abort && !result) + wrterror("malloc() returns NULL\n"); +#endif + TRACE(("%6d A %p %d\n",malloc_event++,result,size)); + + if ((u_long)result & (alignment - 1)) + return ((void *)(((u_long)result + alignment) & ~(alignment - 1))); + else + return result; +} + +void *_PR_UnlockedCalloc(size_t n, size_t nelem) +{ + void *p; + + /* Compute total size and then round up to a double word amount */ + n *= nelem; + if (n & 7) { + n = n + 8 - (n & 7); + } + + /* Get the memory */ + p = _PR_UnlockedMalloc(n); + if (p) { + /* Zero it */ + memset(p, 0, n); + } + return p; +} + +/* + * Change an allocation's size + */ +void *_PR_UnlockedRealloc(void *ptr, size_t size) +{ + void *p; + u_long osize,page,index,tmp_index; + struct pginfo **mp; + + if (!initialized) + malloc_init(); + +#ifdef SANITY + if (suicide) + PR_Abort(); +#endif + + /* used as free() */ + TRACE(("%6d R %p %d\n",malloc_event++, ptr, size)); + if (ptr && !size) { + _PR_UnlockedFree(ptr); + return _PR_UnlockedMalloc (1); + } + + /* used as malloc() */ + if (!ptr) { + p = _PR_UnlockedMalloc(size); + return p; + } + + /* Find the page directory entry for the page in question */ + page = (u_long)ptr >> malloc_pageshift; + index = page - malloc_origo; + + /* + * check if memory was allocated by memalign + */ + tmp_index = index; + while (page_dir[tmp_index] == MALLOC_FOLLOW) + tmp_index--; + if (tmp_index != index) { + /* + * memalign-allocated memory + */ + index = tmp_index; + page = index + malloc_origo; + ptr = (void *) (page << malloc_pageshift); + } + TRACE(("%6d R2 %p %d\n",malloc_event++, ptr, size)); + + /* make sure it makes sense in some fashion */ + if (index < malloc_pageshift || index > last_index) { +#ifdef SANITY + wrtwarning("junk pointer passed to realloc()\n"); +#endif + return 0; + } + + /* find the size of that allocation, and see if we need to relocate */ + mp = &page_dir[index]; + if (*mp == MALLOC_FIRST) { + osize = malloc_pagesize; + while (mp[1] == MALLOC_FOLLOW) { + osize += malloc_pagesize; + mp++; + } + if (!malloc_realloc && + size < osize && + size > malloc_maxsize && + size > (osize - malloc_pagesize)) { + return ptr; + } + } else if (*mp >= MALLOC_MAGIC) { + osize = (*mp)->size; + if (!malloc_realloc && + size < osize && + (size > (*mp)->size/2 || (*mp)->size == malloc_minsize)) { + return ptr; + } + } else { +#ifdef SANITY + wrterror("realloc() of wrong page.\n"); +#endif + } + + /* try to reallocate */ + p = _PR_UnlockedMalloc(size); + + if (p) { + /* copy the lesser of the two sizes */ + if (osize < size) + memcpy(p,ptr,osize); + else + memcpy(p,ptr,size); + _PR_UnlockedFree(ptr); + } +#ifdef DEBUG + else if (malloc_abort) + wrterror("realloc() returns NULL\n"); +#endif + + return p; +} + +/* + * Free a sequence of pages + */ + +static void +free_pages(char *ptr, u_long page, int index, struct pginfo *info) +{ + int i; + struct pgfree *pf,*pt; + u_long l; + char *tail; + + TRACE(("%6d FP %p %d\n",malloc_event++, ptr, page)); + /* Is it free already ? */ + if (info == MALLOC_FREE) { +#ifdef SANITY + wrtwarning("freeing free page at %p.\n", ptr); +#endif + return; + } + +#ifdef SANITY + /* Is it not the right place to begin ? */ + if (info != MALLOC_FIRST) + wrterror("freeing wrong page.\n"); + + /* Is this really a pointer to a page ? */ + if ((u_long)ptr & malloc_pagemask) + wrterror("freeing messed up page pointer.\n"); +#endif + + /* Count how many pages it is anyway */ + page_dir[index] = MALLOC_FREE; + for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++) + page_dir[index + i] = MALLOC_FREE; + + l = i << malloc_pageshift; + + tail = ptr+l; + + /* add to free-list */ + if (!px) + px = (struct pgfree*)_PR_UnlockedMalloc(sizeof *pt); + /* XXX check success */ + px->page = ptr; + px->end = tail; + px->size = l; + if (!free_list.next) { + px->next = free_list.next; + px->prev = &free_list; + free_list.next = px; + pf = px; + px = 0; + } else { + tail = ptr+l; + for(pf = free_list.next; pf->next && pf->end < ptr; pf = pf->next) + ; + for(; pf; pf = pf->next) { + if (pf->end == ptr ) { + /* append to entry */ + pf->end += l; + pf->size += l; + if (pf->next && pf->end == pf->next->page ) { + pt = pf->next; + pf->end = pt->end; + pf->size += pt->size; + pf->next = pt->next; + if (pf->next) + pf->next->prev = pf; + _PR_UnlockedFree(pt); + } + } else if (pf->page == tail) { + /* prepend to entry */ + pf->size += l; + pf->page = ptr; + } else if (pf->page > ptr) { + px->next = pf; + px->prev = pf->prev; + pf->prev = px; + px->prev->next = px; + pf = px; + px = 0; + } else if (!pf->next) { + px->next = 0; + px->prev = pf; + pf->next = px; + pf = px; + px = 0; + } else { + continue; + } + break; + } + } + if (!pf->next && + pf->size > malloc_cache && + pf->end == malloc_brk && + malloc_brk == (void*)sbrk(0)) { + pf->end = pf->page + malloc_cache; + pf->size = malloc_cache; + TRACE(("%6d U %p %d\n",malloc_event++,pf->end,pf->end - pf->page)); + brk(pf->end); + malloc_brk = pf->end; + /* Find the page directory entry for the page in question */ + page = (u_long)pf->end >> malloc_pageshift; + index = page - malloc_origo; + /* Now update the directory */ + for(i=index;i <= last_index;) + page_dir[i++] = MALLOC_NOT_MINE; + last_index = index - 1; + } +} + +/* + * Free a chunk, and possibly the page it's on, if the page becomes empty. + */ + +static void +free_bytes(void *ptr, u_long page, int index, struct pginfo *info) +{ + int i; + struct pginfo **mp; + void *vp; + + /* Make sure that pointer is multiplum of chunk-size */ +#ifdef SANITY + if ((u_long)ptr & (info->size - 1)) + wrterror("freeing messed up chunk pointer\n"); +#endif + + /* Find the chunk number on the page */ + i = ((u_long)ptr & malloc_pagemask) >> info->shift; + + /* See if it's free already */ + if (tst_bit(info,i)) { +#ifdef SANITY + wrtwarning("freeing free chunk at %p\n", ptr); +#endif + return; + } + + /* Mark it free */ + set_bit(info,i); + info->free++; + + /* If the page was full before, we need to put it on the queue now */ + if (info->free == 1) { + mp = page_dir + info->shift; + while (*mp && (*mp)->next && (*mp)->next->page < info->page) + mp = &(*mp)->next; + info->next = *mp; + *mp = info; + return; + } + + /* If this page isn't empty, don't do anything. */ + if (info->free != info->total) + return; + + /* We may want to keep at least one page of each size chunks around. */ + mp = page_dir + info->shift; + if (0 && (*mp == info) && !info->next) + return; + + /* Find & remove this page in the queue */ + while (*mp != info) { + mp = &((*mp)->next); +#ifdef EXTRA_SANITY + if (!*mp) { + TRACE(("%6d !q %p\n",malloc_event++,info)); + wrterror("Not on queue\n"); + } +#endif + } + *mp = info->next; + + /* Free the page & the info structure if need be */ + set_pgdir(info->page,MALLOC_FIRST); + if((void*)info->page == (void*)info) { + _PR_UnlockedFree(info->page); + } else { + vp = info->page; + _PR_UnlockedFree(info); + _PR_UnlockedFree(vp); + } +} + +void _PR_UnlockedFree(void *ptr) +{ + u_long page; + struct pginfo *info; + int index, tmp_index; + + TRACE(("%6d F %p\n",malloc_event++,ptr)); + /* This is legal */ + if (!ptr) + return; + +#ifdef SANITY + /* There wouldn't be anything to free */ + if (!initialized) { + wrtwarning("free() called before malloc() ever got called\n"); + return; + } +#endif + +#ifdef SANITY + if (suicide) + PR_Abort(); +#endif + + /* Find the page directory entry for the page in question */ + page = (u_long)ptr >> malloc_pageshift; + index = page - malloc_origo; + + /* + * check if memory was allocated by memalign + */ + tmp_index = index; + while (page_dir[tmp_index] == MALLOC_FOLLOW) + tmp_index--; + if (tmp_index != index) { + /* + * memalign-allocated memory + */ + index = tmp_index; + page = index + malloc_origo; + ptr = (void *) (page << malloc_pageshift); + } + /* make sure it makes sense in some fashion */ + if (index < malloc_pageshift) { +#ifdef SANITY + wrtwarning("junk pointer %p (low) passed to free()\n", ptr); +#endif + return; + } + if (index > last_index) { +#ifdef SANITY + wrtwarning("junk pointer %p (high) passed to free()\n", ptr); +#endif + return; + } + + /* handle as page-allocation or chunk allocation */ + info = page_dir[index]; + if (info < MALLOC_MAGIC) + free_pages((char*)ptr, page, index, info); + else + free_bytes(ptr,page,index,info); + return; +} +#endif /* _PR_OVERRIDE_MALLOC */ diff --git a/nsprpub/pr/src/malloc/prmem.c b/nsprpub/pr/src/malloc/prmem.c new file mode 100644 index 00000000000..73fa59bcb73 --- /dev/null +++ b/nsprpub/pr/src/malloc/prmem.c @@ -0,0 +1,726 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Thread safe versions of malloc, free, realloc, calloc and cfree. +*/ + +#include "primpl.h" + +#ifdef _PR_ZONE_ALLOCATOR + +/* +** The zone allocator code must use native mutexes and cannot +** use PRLocks because PR_NewLock calls PR_Calloc, resulting +** in cyclic dependency of initialization. +*/ + +#include + +union memBlkHdrUn; + +typedef struct MemoryZoneStr { + union memBlkHdrUn *head; /* free list */ + pthread_mutex_t lock; + size_t blockSize; /* size of blocks on this free list */ + PRUint32 locked; /* current state of lock */ + PRUint32 contention; /* counter: had to wait for lock */ + PRUint32 hits; /* allocated from free list */ + PRUint32 misses; /* had to call malloc */ + PRUint32 elements; /* on free list */ +} MemoryZone; + +typedef union memBlkHdrUn { + unsigned char filler[48]; /* fix the size of this beast */ + struct memBlkHdrStr { + union memBlkHdrUn *next; + MemoryZone *zone; + size_t blockSize; + size_t requestedSize; + PRUint32 magic; + } s; +} MemBlockHdr; + +#define MEM_ZONES 7 +#define THREAD_POOLS 11 /* prime number for modulus */ +#define ZONE_MAGIC 0x0BADC0DE + +static MemoryZone zones[MEM_ZONES][THREAD_POOLS]; + +static PRBool use_zone_allocator = PR_FALSE; + +static void pr_ZoneFree(void *ptr); + +void +_PR_DestroyZones(void) +{ + int i, j; + + if (!use_zone_allocator) + return; + + for (j = 0; j < THREAD_POOLS; j++) { + for (i = 0; i < MEM_ZONES; i++) { + MemoryZone *mz = &zones[i][j]; + pthread_mutex_destroy(&mz->lock); + while (mz->head) { + MemBlockHdr *hdr = mz->head; + mz->head = hdr->s.next; /* unlink it */ + free(hdr); + mz->elements--; + } + } + } + use_zone_allocator = PR_FALSE; +} + +/* +** pr_FindSymbolInProg +** +** Find the specified data symbol in the program and return +** its address. +*/ + +#ifdef HAVE_DLL + +#ifdef USE_DLFCN + +#include + +static void * +pr_FindSymbolInProg(const char *name) +{ + void *h; + void *sym; + + h = dlopen(0, RTLD_LAZY); + if (h == NULL) + return NULL; + sym = dlsym(h, name); + (void)dlclose(h); + return sym; +} + +#elif defined(USE_HPSHL) + +#include + +static void * +pr_FindSymbolInProg(const char *name) +{ + shl_t h = NULL; + void *sym; + + if (shl_findsym(&h, name, TYPE_DATA, &sym) == -1) + return NULL; + return sym; +} + +#elif defined(USE_MACH_DYLD) + +static void * +pr_FindSymbolInProg(const char *name) +{ + /* FIXME: not implemented */ + return NULL; +} + +#else + +#error "The zone allocator is not supported on this platform" + +#endif + +#else /* !defined(HAVE_DLL) */ + +static void * +pr_FindSymbolInProg(const char *name) +{ + /* can't be implemented */ + return NULL; +} + +#endif /* HAVE_DLL */ + +void +_PR_InitZones(void) +{ + int i, j; + char *envp; + PRBool *sym; + + if ((sym = (PRBool *)pr_FindSymbolInProg("nspr_use_zone_allocator")) != NULL) { + use_zone_allocator = *sym; + } else if ((envp = getenv("NSPR_USE_ZONE_ALLOCATOR")) != NULL) { + use_zone_allocator = (atoi(envp) == 1); + } + + if (!use_zone_allocator) + return; + + for (j = 0; j < THREAD_POOLS; j++) { + for (i = 0; i < MEM_ZONES; i++) { + MemoryZone *mz = &zones[i][j]; + int rv = pthread_mutex_init(&mz->lock, NULL); + PR_ASSERT(0 == rv); + if (rv != 0) { + goto loser; + } + mz->blockSize = 16 << ( 2 * i); + } + } + return; + +loser: + _PR_DestroyZones(); + return; +} + +PR_IMPLEMENT(void) +PR_FPrintZoneStats(PRFileDesc *debug_out) +{ + int i, j; + + for (j = 0; j < THREAD_POOLS; j++) { + for (i = 0; i < MEM_ZONES; i++) { + MemoryZone *mz = &zones[i][j]; + MemoryZone zone = *mz; + if (zone.elements || zone.misses || zone.hits) { + PR_fprintf(debug_out, +"pool: %d, zone: %d, size: %d, free: %d, hit: %d, miss: %d, contend: %d\n", + j, i, zone.blockSize, zone.elements, + zone.hits, zone.misses, zone.contention); + } + } + } +} + +static void * +pr_ZoneMalloc(PRUint32 size) +{ + void *rv; + unsigned int zone; + size_t blockSize; + MemBlockHdr *mb, *mt; + MemoryZone *mz; + + /* Always allocate a non-zero amount of bytes */ + if (size < 1) { + size = 1; + } + for (zone = 0, blockSize = 16; zone < MEM_ZONES; ++zone, blockSize <<= 2) { + if (size <= blockSize) { + break; + } + } + if (zone < MEM_ZONES) { + pthread_t me = pthread_self(); + unsigned int pool = (PRUptrdiff)me % THREAD_POOLS; + PRUint32 wasLocked; + mz = &zones[zone][pool]; + wasLocked = mz->locked; + pthread_mutex_lock(&mz->lock); + mz->locked = 1; + if (wasLocked) + mz->contention++; + if (mz->head) { + mb = mz->head; + PR_ASSERT(mb->s.magic == ZONE_MAGIC); + PR_ASSERT(mb->s.zone == mz); + PR_ASSERT(mb->s.blockSize == blockSize); + PR_ASSERT(mz->blockSize == blockSize); + + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + PR_ASSERT(mt->s.magic == ZONE_MAGIC); + PR_ASSERT(mt->s.zone == mz); + PR_ASSERT(mt->s.blockSize == blockSize); + + mz->hits++; + mz->elements--; + mz->head = mb->s.next; /* take off free list */ + mz->locked = 0; + pthread_mutex_unlock(&mz->lock); + + mt->s.next = mb->s.next = NULL; + mt->s.requestedSize = mb->s.requestedSize = size; + + rv = (void *)(mb + 1); + return rv; + } + + mz->misses++; + mz->locked = 0; + pthread_mutex_unlock(&mz->lock); + + mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb)); + if (!mb) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + mb->s.next = NULL; + mb->s.zone = mz; + mb->s.magic = ZONE_MAGIC; + mb->s.blockSize = blockSize; + mb->s.requestedSize = size; + + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + memcpy(mt, mb, sizeof *mb); + + rv = (void *)(mb + 1); + return rv; + } + + /* size was too big. Create a block with no zone */ + blockSize = (size & 15) ? size + 16 - (size & 15) : size; + mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb)); + if (!mb) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + mb->s.next = NULL; + mb->s.zone = NULL; + mb->s.magic = ZONE_MAGIC; + mb->s.blockSize = blockSize; + mb->s.requestedSize = size; + + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + memcpy(mt, mb, sizeof *mb); + + rv = (void *)(mb + 1); + return rv; +} + + +static void * +pr_ZoneCalloc(PRUint32 nelem, PRUint32 elsize) +{ + PRUint32 size = nelem * elsize; + void *p = pr_ZoneMalloc(size); + if (p) { + memset(p, 0, size); + } + return p; +} + +static void * +pr_ZoneRealloc(void *oldptr, PRUint32 bytes) +{ + void *rv; + MemBlockHdr *mb; + int ours; + MemBlockHdr phony; + + if (!oldptr) + return pr_ZoneMalloc(bytes); + mb = (MemBlockHdr *)((char *)oldptr - (sizeof *mb)); + if (mb->s.magic != ZONE_MAGIC) { + /* Maybe this just came from ordinary malloc */ +#ifdef DEBUG + fprintf(stderr, + "Warning: reallocing memory block %p from ordinary malloc\n", + oldptr); +#endif + /* + * We are going to realloc oldptr. If realloc succeeds, the + * original value of oldptr will point to freed memory. So this + * function must not fail after a successfull realloc call. We + * must perform any operation that may fail before the realloc + * call. + */ + rv = pr_ZoneMalloc(bytes); /* this may fail */ + if (!rv) { + return rv; + } + + /* We don't know how big it is. But we can fix that. */ + oldptr = realloc(oldptr, bytes); + /* + * If realloc returns NULL, this function loses the original + * value of oldptr. This isn't a leak because the caller of + * this function still has the original value of oldptr. + */ + if (!oldptr) { + if (bytes) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + pr_ZoneFree(rv); + return oldptr; + } + } + phony.s.requestedSize = bytes; + mb = &phony; + ours = 0; + } else { + size_t blockSize = mb->s.blockSize; + MemBlockHdr *mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + + PR_ASSERT(mt->s.magic == ZONE_MAGIC); + PR_ASSERT(mt->s.zone == mb->s.zone); + PR_ASSERT(mt->s.blockSize == blockSize); + + if (bytes <= blockSize) { + /* The block is already big enough. */ + mt->s.requestedSize = mb->s.requestedSize = bytes; + return oldptr; + } + ours = 1; + rv = pr_ZoneMalloc(bytes); + if (!rv) { + return rv; + } + } + + if (oldptr && mb->s.requestedSize) + memcpy(rv, oldptr, mb->s.requestedSize); + if (ours) + pr_ZoneFree(oldptr); + else if (oldptr) + free(oldptr); + return rv; +} + +static void +pr_ZoneFree(void *ptr) +{ + MemBlockHdr *mb, *mt; + MemoryZone *mz; + size_t blockSize; + PRUint32 wasLocked; + + if (!ptr) + return; + + mb = (MemBlockHdr *)((char *)ptr - (sizeof *mb)); + + if (mb->s.magic != ZONE_MAGIC) { + /* maybe this came from ordinary malloc */ +#ifdef DEBUG + fprintf(stderr, + "Warning: freeing memory block %p from ordinary malloc\n", ptr); +#endif + free(ptr); + return; + } + + blockSize = mb->s.blockSize; + mz = mb->s.zone; + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + PR_ASSERT(mt->s.magic == ZONE_MAGIC); + PR_ASSERT(mt->s.zone == mz); + PR_ASSERT(mt->s.blockSize == blockSize); + if (!mz) { + PR_ASSERT(blockSize > 65536); + /* This block was not in any zone. Just free it. */ + free(mb); + return; + } + PR_ASSERT(mz->blockSize == blockSize); + wasLocked = mz->locked; + pthread_mutex_lock(&mz->lock); + mz->locked = 1; + if (wasLocked) + mz->contention++; + mt->s.next = mb->s.next = mz->head; /* put on head of list */ + mz->head = mb; + mz->elements++; + mz->locked = 0; + pthread_mutex_unlock(&mz->lock); +} + +PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + return use_zone_allocator ? pr_ZoneMalloc(size) : malloc(size); +} + +PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + return use_zone_allocator ? + pr_ZoneCalloc(nelem, elsize) : calloc(nelem, elsize); +} + +PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + return use_zone_allocator ? pr_ZoneRealloc(ptr, size) : realloc(ptr, size); +} + +PR_IMPLEMENT(void) PR_Free(void *ptr) +{ + if (use_zone_allocator) + pr_ZoneFree(ptr); + else + free(ptr); +} + +#else /* !defined(_PR_ZONE_ALLOCATOR) */ + +/* +** The PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free functions simply +** call their libc equivalents now. This may seem redundant, but it +** ensures that we are calling into the same runtime library. On +** Win32, it is possible to have multiple runtime libraries (e.g., +** objects compiled with /MD and /MDd) in the same process, and +** they maintain separate heaps, which cannot be mixed. +*/ +PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size) +{ +#if defined (WIN16) + return PR_MD_malloc( (size_t) size); +#else + return malloc(size); +#endif +} + +PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize) +{ +#if defined (WIN16) + return PR_MD_calloc( (size_t)nelem, (size_t)elsize ); + +#else + return calloc(nelem, elsize); +#endif +} + +PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size) +{ +#if defined (WIN16) + return PR_MD_realloc( ptr, (size_t) size); +#else + return realloc(ptr, size); +#endif +} + +PR_IMPLEMENT(void) PR_Free(void *ptr) +{ +#if defined (WIN16) + PR_MD_free( ptr ); +#else + free(ptr); +#endif +} + +#endif /* _PR_ZONE_ALLOCATOR */ + +/* +** Complexity alert! +** +** If malloc/calloc/free (etc.) were implemented to use pr lock's then +** the entry points could block when called if some other thread had the +** lock. +** +** Most of the time this isn't a problem. However, in the case that we +** are using the thread safe malloc code after PR_Init but before +** PR_AttachThread has been called (on a native thread that nspr has yet +** to be told about) we could get royally screwed if the lock was busy +** and we tried to context switch the thread away. In this scenario +** PR_CURRENT_THREAD() == NULL +** +** To avoid this unfortunate case, we use the low level locking +** facilities for malloc protection instead of the slightly higher level +** locking. This makes malloc somewhat faster so maybe it's a good thing +** anyway. +*/ +#ifdef _PR_OVERRIDE_MALLOC + +/* Imports */ +extern void *_PR_UnlockedMalloc(size_t size); +extern void *_PR_UnlockedMemalign(size_t alignment, size_t size); +extern void _PR_UnlockedFree(void *ptr); +extern void *_PR_UnlockedRealloc(void *ptr, size_t size); +extern void *_PR_UnlockedCalloc(size_t n, size_t elsize); + +static PRBool _PR_malloc_initialised = PR_FALSE; + +#ifdef _PR_PTHREADS +static pthread_mutex_t _PR_MD_malloc_crustylock; + +#define _PR_Lock_Malloc() { \ + if(PR_TRUE == _PR_malloc_initialised) { \ + PRStatus rv; \ + rv = pthread_mutex_lock(&_PR_MD_malloc_crustylock); \ + PR_ASSERT(0 == rv); \ + } + +#define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \ + PRStatus rv; \ + rv = pthread_mutex_unlock(&_PR_MD_malloc_crustylock); \ + PR_ASSERT(0 == rv); \ + } \ + } +#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) { \ + if (_PR_MD_CURRENT_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _PR_MD_CURRENT_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_CURRENT_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _PR_MD_CURRENT_THREAD())) \ + _PR_INTSON(_is); \ + } \ + } +#endif /* IRIX */ +#endif /* _PR_PTHREADS */ + +PR_IMPLEMENT(PRStatus) _PR_MallocInit(void) +{ + PRStatus rv = PR_SUCCESS; + + if( PR_TRUE == _PR_malloc_initialised ) return PR_SUCCESS; + +#ifdef _PR_PTHREADS + { + int status; + pthread_mutexattr_t mattr; + + status = _PT_PTHREAD_MUTEXATTR_INIT(&mattr); + PR_ASSERT(0 == status); + status = _PT_PTHREAD_MUTEX_INIT(_PR_MD_malloc_crustylock, mattr); + PR_ASSERT(0 == status); + status = _PT_PTHREAD_MUTEXATTR_DESTROY(&mattr); + PR_ASSERT(0 == status); + } +#else /* _PR_PTHREADS */ + _MD_NEW_LOCK(&_PR_MD_malloc_crustylock); +#endif /* _PR_PTHREADS */ + + if( PR_SUCCESS == rv ) + { + _PR_malloc_initialised = PR_TRUE; + } + + return rv; +} + +void *malloc(size_t size) +{ + void *p; + _PR_Lock_Malloc(); + p = _PR_UnlockedMalloc(size); + _PR_Unlock_Malloc(); + return p; +} + +#if defined(IRIX) +void *memalign(size_t alignment, size_t size) +{ + void *p; + _PR_Lock_Malloc(); + p = _PR_UnlockedMemalign(alignment, size); + _PR_Unlock_Malloc(); + return p; +} + +void *valloc(size_t size) +{ + return(memalign(sysconf(_SC_PAGESIZE),size)); +} +#endif /* IRIX */ + +void free(void *ptr) +{ + _PR_Lock_Malloc(); + _PR_UnlockedFree(ptr); + _PR_Unlock_Malloc(); +} + +void *realloc(void *ptr, size_t size) +{ + void *p; + _PR_Lock_Malloc(); + p = _PR_UnlockedRealloc(ptr, size); + _PR_Unlock_Malloc(); + return p; +} + +void *calloc(size_t n, size_t elsize) +{ + void *p; + _PR_Lock_Malloc(); + p = _PR_UnlockedCalloc(n, elsize); + _PR_Unlock_Malloc(); + return p; +} + +void cfree(void *p) +{ + _PR_Lock_Malloc(); + _PR_UnlockedFree(p); + _PR_Unlock_Malloc(); +} + +void _PR_InitMem(void) +{ + PRStatus rv; + rv = _PR_MallocInit(); + PR_ASSERT(PR_SUCCESS == rv); +} + +#endif /* _PR_OVERRIDE_MALLOC */ diff --git a/nsprpub/pr/src/md/.cvsignore b/nsprpub/pr/src/md/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/md/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/md/Makefile.in b/nsprpub/pr/src/md/Makefile.in new file mode 100644 index 00000000000..2b8d47789c4 --- /dev/null +++ b/nsprpub/pr/src/md/Makefile.in @@ -0,0 +1,64 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = $(PR_MD_ARCH_DIR) + +CSRCS = \ + prosdep.c \ + $(NULL) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/pr/src/md/beos/.cvsignore b/nsprpub/pr/src/md/beos/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/md/beos/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/md/beos/Makefile.in b/nsprpub/pr/src/md/beos/Makefile.in new file mode 100644 index 00000000000..fca5cf2c265 --- /dev/null +++ b/nsprpub/pr/src/md/beos/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +include $(srcdir)/bsrcs.mk +CSRCS += $(MDCSRCS) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/pr/src/md/beos/bcpu.c b/nsprpub/pr/src/md/beos/bcpu.c new file mode 100644 index 00000000000..548df8c2823 --- /dev/null +++ b/nsprpub/pr/src/md/beos/bcpu.c @@ -0,0 +1,55 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +PR_EXTERN(void) _PR_MD_INIT_CPUS(); +PR_EXTERN(void) _PR_MD_WAKEUP_CPUS(); +PR_EXTERN(void) _PR_MD_START_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_STOP_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_DISABLE_CLOCK_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_BLOCK_CLOCK_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_CLOCK_INTERRUPT(void); +PR_EXTERN(void) _PR_MD_INIT_STACK(PRThreadStack *ts, PRIntn redzone); +PR_EXTERN(void) _PR_MD_CLEAR_STACK(PRThreadStack* ts); +PR_EXTERN(PRInt32) _PR_MD_GET_INTSOFF(void); +PR_EXTERN(void) _PR_MD_SET_INTSOFF(PRInt32 _val); +PR_EXTERN(_PRCPU*) _PR_MD_CURRENT_CPU(void); +PR_EXTERN(void) _PR_MD_SET_CURRENT_CPU(_PRCPU *cpu); +PR_EXTERN(void) _PR_MD_INIT_RUNNING_CPU(_PRCPU *cpu); +PR_EXTERN(PRInt32) _PR_MD_PAUSE_CPU(PRIntervalTime timeout); diff --git a/nsprpub/pr/src/md/beos/beos.c b/nsprpub/pr/src/md/beos/beos.c new file mode 100644 index 00000000000..dba9ae24d19 --- /dev/null +++ b/nsprpub/pr/src/md/beos/beos.c @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or + * PRInt32* pointer to a _PRSockLen_t* pointer. + */ +#define _PRSockLen_t int + +/* +** Global lock variable used to bracket calls into rusty libraries that +** aren't thread safe (like libc, libX, etc). +*/ +static PRLock *_pr_rename_lock = NULL; +static PRMonitor *_pr_Xfe_mon = NULL; + +/* + * Variables used by the GC code, initialized in _MD_InitSegs(). + * _pr_zero_fd should be a static variable. Unfortunately, there is + * still some Unix-specific code left in function PR_GrowSegment() + * in file memory/prseg.c that references it, so it needs + * to be a global variable for now. + */ +PRInt32 _pr_zero_fd = -1; +static PRLock *_pr_md_lock = NULL; + +sigset_t timer_set; + +void _PR_UnixInit() +{ + struct sigaction sigact; + int rv; + + sigemptyset(&timer_set); + + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + rv = sigaction(SIGPIPE, &sigact, 0); + PR_ASSERT(0 == rv); + + _pr_rename_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_rename_lock); + _pr_Xfe_mon = PR_NewMonitor(); + PR_ASSERT(NULL != _pr_Xfe_mon); +} + +/* + *----------------------------------------------------------------------- + * + * PR_Now -- + * + * Returns the current time in microseconds since the epoch. + * The epoch is midnight January 1, 1970 GMT. + * The implementation is machine dependent. This is the Unix + * implementation. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRTime) +PR_Now(void) +{ + 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; +} + +PRIntervalTime +_PR_UNIX_GetInterval() +{ + 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; +} /* _PR_SUNOS_GetInterval */ + +PRIntervalTime _PR_UNIX_TicksPerSecond() +{ + return 1000; /* this needs some work :) */ +} + +/************************************************************************/ + +/* +** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread +** safe. Unfortunately, neither is mozilla. To make these programs work +** in a pre-emptive threaded environment, we need to use a lock. +*/ + +void PR_XLock() +{ + PR_EnterMonitor(_pr_Xfe_mon); +} + +void PR_XUnlock() +{ + PR_ExitMonitor(_pr_Xfe_mon); +} + +PRBool PR_XIsLocked() +{ + return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE; +} + +void PR_XWait(int ms) +{ + PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms)); +} + +void PR_XNotify(void) +{ + PR_Notify(_pr_Xfe_mon); +} + +void PR_XNotifyAll(void) +{ + PR_NotifyAll(_pr_Xfe_mon); +} + +#if !defined(BEOS) +#ifdef HAVE_BSD_FLOCK + +#include + +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; +} + +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; +} + +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; +} +#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; +} + +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; +} + +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; +} +#endif + +PR_IMPLEMENT(PRStatus) + _MD_GETHOSTNAME (char *name, PRUint32 namelen) +{ + PRIntn rv; + + rv = gethostname(name, namelen); + if (0 == rv) { + return PR_SUCCESS; + } + _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +#endif diff --git a/nsprpub/pr/src/md/beos/beos_errors.c b/nsprpub/pr/src/md/beos/beos_errors.c new file mode 100644 index 00000000000..bfb44eb7e35 --- /dev/null +++ b/nsprpub/pr/src/md/beos/beos_errors.c @@ -0,0 +1,1526 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prtypes.h" +#include "md/_unix_errors.h" +#include "prerror.h" +#include + +void _MD_unix_map_opendir_error(int err) +{ + switch (err) { + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_closedir_error(int err) +{ + switch (err) { + case EINVAL: + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_readdir_error(int err) +{ + + switch (err) { + case 0: + case ENOENT: + PR_SetError(PR_NO_MORE_FILES_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef IRIX +#ifdef IRIX5_3 +#else + case EDIRCORRUPTED: + PR_SetError(PR_DIRECTORY_CORRUPTED_ERROR, err); + break; +#endif +#endif +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_IO_ERROR, err); + break; +#ifdef EBADMSG + case EBADMSG: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EDEADLK: + PR_SetError(PR_DEADLOCK_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + case ENXIO: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_unlink_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EPERM: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_stat_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_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: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_fstat_error(int err) +{ + 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: +#endif + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_rename_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif + case EEXIST: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_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 EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + case EXDEV: + PR_SetError(PR_NOT_SAME_DEVICE_ERROR, err); + break; + case EMLINK: + PR_SetError(PR_MAX_DIRECTORY_ENTRIES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_access_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_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 ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_mkdir_error(int err) +{ + switch (err) { + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case EMLINK: + PR_SetError(PR_MAX_DIRECTORY_ENTRIES_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_rmdir_error(int err) +{ + + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_read_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef EBADMSG + case EBADMSG: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EDEADLK: + PR_SetError(PR_DEADLOCK_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_METHOD_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ENXIO: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_write_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EDEADLK: + PR_SetError(PR_DEADLOCK_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EFBIG: + PR_SetError(PR_FILE_TOO_BIG_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ENXIO: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case ERANGE: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_lseek_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ESPIPE: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_fsync_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: +#endif + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_close_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: +#endif + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socket_error(int err) +{ + switch (err) { + case EPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socketavailable_error(int err) +{ + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); +} + +void _MD_unix_map_recv_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_recvfrom_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_send_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EMSGSIZE: +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif /* !defined(SCO) */ + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_sendto_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EMSGSIZE: +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif /* !defined(SCO) */ + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_writev_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + 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; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_accept_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EOPNOTSUPP: +#endif + case ENODEV: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif +#ifdef EPROTO + case EPROTO: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_connect_error(int err) +{ + switch (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 EALREADY: + PR_SetError(PR_ALREADY_INITIATED_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_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; + /* + * UNIX domain sockets are not supported in NSPR + */ + case EACCES: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_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: +#if defined(UNIXWARE) || defined(SNI) || defined(NEC) + /* + * On some platforms, if we connect to a port on + * the local host (the loopback address) that no + * process is listening on, we get EIO instead + * of ECONNREFUSED. + */ + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); +#else + PR_SetError(PR_IO_ERROR, err); +#endif + break; + case ELOOP: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ENXIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EPROTOTYPE: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_bind_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case EADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_SOCKET_ADDRESS_IS_BOUND_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + /* + * UNIX domain sockets are not supported in NSPR + */ + case EIO: + case EISDIR: + case ELOOP: + case ENOENT: + case ENOTDIR: + case EROFS: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_listen_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EOPNOTSUPP: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_shutdown_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socketpair_error(int err) +{ + switch (err) { + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EAFNOSUPPORT: + case EPROTONOSUPPORT: +#if !defined(BEOS) + case EOPNOTSUPP: +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getsockname_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getpeername_error(int err) +{ + + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getsockopt_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_setsockopt_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_open_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 EBUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_FILE_EXISTS_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 EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ENODEV: + case ENOENT: + case ENXIO: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EPERM: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_mmap_error(int err) +{ + + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EAGAIN: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_gethostname_error(int err) +{ + switch (err) { + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_select_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_poll_error(int err) +{ + PRErrorCode prerror; + switch (err) { + case EAGAIN: + prerror = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + case EFAULT: + prerror = PR_ACCESS_FAULT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, err); +} + +void _MD_unix_map_flock_error(int err) +{ + switch (err) { + case EBADF: + case EINVAL: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EWOULDBLOCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_lockf_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EACCES: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case EDEADLK: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +#ifdef HPUX11 +void _MD_hpux_map_sendfile_error(int oserror) +{ + PRErrorCode prerror; + + switch (oserror) { + case ENOTSOCK: + prerror = PR_NOT_SOCKET_ERROR; + break; + case EFAULT: + prerror = PR_ACCESS_FAULT_ERROR; + break; + case ENOBUFS: + prerror = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + case ENOTCONN: + prerror = PR_NOT_CONNECTED_ERROR; + break; + case EPIPE: + prerror = PR_CONNECT_RESET_ERROR; + break; + case ENOMEM: + prerror = PR_OUT_OF_MEMORY_ERROR; + break; + case EOPNOTSUPP: + prerror = PR_NOT_TCP_SOCKET_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, oserror); +} +#endif /* HPUX11 */ diff --git a/nsprpub/pr/src/md/beos/bfile.c b/nsprpub/pr/src/md/beos/bfile.c new file mode 100644 index 00000000000..4ab02d06700 --- /dev/null +++ b/nsprpub/pr/src/md/beos/bfile.c @@ -0,0 +1,905 @@ +/* -*- Mode: C++; tab-width: 8; c-basic-offset: 8 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/* +** Global lock variable used to bracket calls into rusty libraries that +** aren't thread safe (like libc, libX, etc). +*/ +static PRLock *_pr_rename_lock = NULL; + +void +_MD_InitIO (void) +{ +} + +PRStatus +_MD_open_dir (_MDDir *md,const char *name) +{ +int err; + + md->d = opendir(name); + if (!md->d) { + err = _MD_ERRNO(); + _PR_MD_MAP_OPENDIR_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +char* +_MD_read_dir (_MDDir *md, PRIntn flags) +{ +struct dirent *de; +int err; + + for (;;) { + /* + * XXX: readdir() is not MT-safe + */ + _MD_ERRNO() = 0; + de = readdir(md->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[1] == '.')) + continue; + + break; + } + return de->d_name; +} + + +PRInt32 +_MD_close_dir (_MDDir *md) +{ +int rv = 0, err; + + if (md->d) { + rv = closedir(md->d); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_CLOSEDIR_ERROR(err); + } + } + return(rv); +} + +void +_MD_make_nonblock (PRFileDesc *fd) +{ + int blocking = 1; + setsockopt(fd->secret->md.osfd, SOL_SOCKET, SO_NONBLOCK, &blocking, sizeof(blocking)); + +} + +PRStatus +_MD_set_fd_inheritable (PRFileDesc *fd, PRBool inheritable) +{ + int rv; + + rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC); + if (-1 == rv) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void +_MD_init_fd_inheritable (PRFileDesc *fd, PRBool imported) +{ + if (imported) { + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + if (flags == -1) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return; + } + fd->secret->inheritable = (flags & FD_CLOEXEC) ? + _PR_TRI_TRUE : _PR_TRI_FALSE; + } +} + +void +_MD_query_fd_inheritable (PRFileDesc *fd) +{ + int flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + PR_ASSERT(-1 != flags); + fd->secret->inheritable = (flags & FD_CLOEXEC) ? + _PR_TRI_FALSE : _PR_TRI_TRUE; +} + +PRInt32 +_MD_open (const char *name, PRIntn flags, PRIntn mode) +{ + 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_EXCL) + osflags |= O_EXCL; + if (flags & PR_APPEND) + osflags |= O_APPEND; + if (flags & PR_TRUNCATE) + osflags |= O_TRUNC; + if (flags & PR_SYNC) { +/* Ummmm. BeOS doesn't appear to + support sync in any way shape or + form. */ + return PR_NOT_IMPLEMENTED_ERROR; + } + + /* + ** 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) + { + osflags |= O_CREAT ; + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + } + + rv = open(name, osflags, mode); + + 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; +} + +PRInt32 +_MD_close_file (PRInt32 osfd) +{ +PRInt32 rv, err; + + rv = close(osfd); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_CLOSE_ERROR(err); + } + return(rv); +} + +PRInt32 +_MD_read (PRFileDesc *fd, void *buf, PRInt32 amount) +{ + PRInt32 rv, err; + PRInt32 osfd = fd->secret->md.osfd; + + rv = read( osfd, buf, amount ); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_READ_ERROR(err); + } + return(rv); +} + +PRInt32 +_MD_write (PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + PRInt32 rv, err; + PRInt32 osfd = fd->secret->md.osfd; + + rv = write( osfd, buf, amount ); + + if( rv < 0 ) { + + err = _MD_ERRNO(); + _PR_MD_MAP_WRITE_ERROR(err); + } + return( rv ); +} + +#ifndef BONE_VERSION /* Writev moves to bnet.c with BONE */ +PRInt32 +_MD_writev (PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} +#endif + +PRInt32 +_MD_lseek (PRFileDesc *fd, PRInt32 offset, int whence) +{ +PRInt32 rv, err; + + rv = lseek (fd->secret->md.osfd, offset, whence); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_LSEEK_ERROR(err); + } + return( rv ); +} + +PRInt64 +_MD_lseek64 (PRFileDesc *fd, PRInt64 offset, int whence) +{ +PRInt32 rv, err; + +/* According to the BeOS headers, lseek accepts a + * variable of type off_t for the offset, and off_t + * is defined to be a 64-bit value. So no special + * cracking needs to be done on "offset". + */ + + rv = lseek (fd->secret->md.osfd, offset, whence); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_LSEEK_ERROR(err); + } + return( rv ); +} + +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); +} + +PRInt32 +_MD_delete (const char *name) +{ +PRInt32 rv, err; + + rv = unlink(name); + 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; +PRInt32 rv, err; +PRInt64 s, s2us; + + 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; + + /* Must truncate file size for the 32 bit + version */ + info->size = (sb.st_size & 0xffffffff); + 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) +{ +struct stat sb; +PRInt32 rv, err; +PRInt64 s, s2us; + + 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; + + /* For the 64 bit version we can use + * the native st_size without modification + */ + 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_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; + /* Use lower 32 bits of file size */ + info->size = ( sb.st_size & 0xffffffff); + 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) +{ + 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_rename (const char *from, const char *to) +{ + PRInt32 rv = -1, err; + + /* + ** This is trying to enforce the semantics of WINDOZE' rename + ** operation. That means one is not allowed to rename over top + ** of an existing file. Holding a lock across these two function + ** and the open function is known to be a bad idea, but .... + */ + if (NULL != _pr_rename_lock) + PR_Lock(_pr_rename_lock); + if (0 == access(to, F_OK)) + PR_SetError(PR_FILE_EXISTS_ERROR, 0); + else + { + 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; +} + +PRInt32 +_MD_access (const char *name, PRIntn how) +{ +PRInt32 rv, err; +int checkFlags; +struct stat buf; + + switch (how) { + case PR_ACCESS_WRITE_OK: + checkFlags = S_IWUSR | S_IWGRP | S_IWOTH; + break; + + case PR_ACCESS_READ_OK: + checkFlags = S_IRUSR | S_IRGRP | S_IROTH; + break; + + case PR_ACCESS_EXISTS: + /* we don't need to examine st_mode. */ + break; + + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + rv = stat(name, &buf); + if (rv == 0 && how != PR_ACCESS_EXISTS && (!(buf.st_mode & checkFlags))) { + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); + return -1; + } + + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_STAT_ERROR(err); + } + + return(rv); +} + +PRInt32 +_MD_stat (const char *name, struct stat *buf) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +PRInt32 +_MD_mkdir (const char *name, PRIntn mode) +{ + status_t rv; + int err; + + /* + ** This lock is used to enforce rename semantics as described + ** in PR_Rename. Look there for more fun details. + */ + 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); + } + if (NULL !=_pr_rename_lock) + PR_Unlock(_pr_rename_lock); + 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; +} + +PRInt32 +_MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRInt32 rv = 0; + PRThread *me = _PR_MD_CURRENT_THREAD(); + /* + * 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; + + if (_PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + if (0 == npds) { + PR_Sleep(timeout); + return rv; + } + + 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 */ + } + } + } + else + { + pd->out_flags = 0; + } + } + + 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 = PR_IntervalToMicroseconds( remaining % 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; + +/* Workaround for nonblocking connects under net_server */ +#ifndef BONE_VERSION + if (out_flags) + { + /* check if it is a pending connect */ + int i = 0, j = 0; + PR_Lock( _connectLock ); + for( i = 0; i < connectCount; i++ ) + { + if(connectList[i].osfd == osfd) + { + int connectError; + int connectResult; + + connectResult = connect(connectList[i].osfd, + &connectList[i].addr, + connectList[i].addrlen); + connectError = errno; + + if(connectResult < 0 ) + { + if(connectError == EINTR || connectError == EWOULDBLOCK || + connectError == EINPROGRESS || connectError == EALREADY) + { + break; + } + } + + if(i == (connectCount - 1)) + { + connectList[i].osfd = -1; + } else { + for(j = i; j < connectCount; j++ ) + { + memcpy( &connectList[j], &connectList[j+1], + sizeof(connectList[j])); + } + } + connectCount--; + + bottom->secret->md.connectReturnValue = connectResult; + bottom->secret->md.connectReturnError = connectError; + bottom->secret->md.connectValueValid = PR_TRUE; + break; + } + } + PR_Unlock( _connectLock ); + } +#endif + } + 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; +} /* _MD_pr_poll */ + +/* + * File locking. + */ + +PRStatus +_MD_lockfile (PRInt32 osfd) +{ + PRInt32 rv; + struct flock linfo; + + linfo.l_type = + linfo.l_whence = SEEK_SET; + linfo.l_start = 0; + linfo.l_len = 0; + + rv = fcntl(osfd, F_SETLKW, &linfo); + if (rv == 0) + return PR_SUCCESS; + + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PRStatus +_MD_tlockfile (PRInt32 osfd) +{ + PRInt32 rv; + struct flock linfo; + + linfo.l_type = + linfo.l_whence = SEEK_SET; + linfo.l_start = 0; + linfo.l_len = 0; + + rv = fcntl(osfd, F_SETLK, &linfo); + if (rv == 0) + return PR_SUCCESS; + + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PRStatus +_MD_unlockfile (PRInt32 osfd) +{ + PRInt32 rv; + struct flock linfo; + + linfo.l_type = + linfo.l_whence = SEEK_SET; + linfo.l_start = 0; + linfo.l_len = 0; + + rv = fcntl(osfd, F_UNLCK, &linfo); + + if (rv == 0) + return PR_SUCCESS; + + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + diff --git a/nsprpub/pr/src/md/beos/bmemory.c b/nsprpub/pr/src/md/beos/bmemory.c new file mode 100644 index 00000000000..17c73325af7 --- /dev/null +++ b/nsprpub/pr/src/md/beos/bmemory.c @@ -0,0 +1,42 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +PR_EXTERN(void) _PR_MD_INIT_SEGS(void); +PR_EXTERN(PRStatus) _PR_MD_ALLOC_SEGMENT(PRSegment *seg, PRUint32 size, void *vaddr); +PR_EXTERN(void) _PR_MD_FREE_SEGMENT(PRSegment *seg); diff --git a/nsprpub/pr/src/md/beos/bmisc.c b/nsprpub/pr/src/md/beos/bmisc.c new file mode 100644 index 00000000000..429cd7be235 --- /dev/null +++ b/nsprpub/pr/src/md/beos/bmisc.c @@ -0,0 +1,123 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +PRLock *_connectLock = NULL; + +#ifndef BONE_VERSION +/* Workaround for nonblocking connects under net_server */ +PRUint32 connectCount = 0; +ConnectListNode connectList[64]; +#endif + +void +_MD_cleanup_before_exit (void) +{ +} + +void +_MD_exit (PRIntn status) +{ + exit(status); +} + +void +_MD_early_init (void) +{ +} + +static PRLock *monitor = NULL; + +void +_MD_final_init (void) +{ + _connectLock = PR_NewLock(); + PR_ASSERT(NULL != _connectLock); +#ifndef BONE_VERSION + /* Workaround for nonblocking connects under net_server */ + connectCount = 0; +#endif +} + +void +_MD_AtomicInit (void) +{ + if (monitor == NULL) { + monitor = PR_NewLock(); + } +} + +/* +** This is exceedingly messy. atomic_add returns the last value, NSPR expects the new value. +** We just add or subtract 1 from the result. The actual memory update is atomic. +*/ + +PRInt32 +_MD_AtomicAdd( PRInt32 *ptr, PRInt32 val ) +{ + return( ( atomic_add( (long *)ptr, val ) ) + val ); +} + +PRInt32 +_MD_AtomicIncrement( PRInt32 *val ) +{ + return( ( atomic_add( (long *)val, 1 ) ) + 1 ); +} + +PRInt32 +_MD_AtomicDecrement( PRInt32 *val ) +{ + return( ( atomic_add( (long *)val, -1 ) ) - 1 ); +} + +PRInt32 +_MD_AtomicSet( PRInt32 *val, PRInt32 newval ) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(monitor); + rv = *val; + *val = newval; + PR_Unlock(monitor); + return rv; +} diff --git a/nsprpub/pr/src/md/beos/bmmap.c b/nsprpub/pr/src/md/beos/bmmap.c new file mode 100644 index 00000000000..9edd0673976 --- /dev/null +++ b/nsprpub/pr/src/md/beos/bmmap.c @@ -0,0 +1,73 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +PR_EXTERN(PRStatus) +_PR_MD_CREATE_FILE_MAP(PRFileMap *fmap, PRInt64 size) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +} + +PR_EXTERN(PRInt32) +_PR_MD_GET_MEM_MAP_ALIGNMENT(void) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return -1; +} + +PR_EXTERN(void *) +_PR_MD_MEM_MAP(PRFileMap *fmap, PRInt64 offset, PRUint32 len) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return 0; +} + +PR_EXTERN(PRStatus) +_PR_MD_MEM_UNMAP(void *addr, PRUint32 size) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +} + +PR_EXTERN(PRStatus) +_PR_MD_CLOSE_FILE_MAP(PRFileMap *fmap) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +} diff --git a/nsprpub/pr/src/md/beos/bnet.c b/nsprpub/pr/src/md/beos/bnet.c new file mode 100644 index 00000000000..9b10509e06f --- /dev/null +++ b/nsprpub/pr/src/md/beos/bnet.c @@ -0,0 +1,929 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or + * PRInt32* pointer to a _PRSockLen_t* pointer. + */ +#define _PRSockLen_t int + + +/* +** Global lock variable used to bracket calls into rusty libraries that +** aren't thread safe (like libc, libX, etc). +*/ +static PRLock *_pr_rename_lock = NULL; +static PRMonitor *_pr_Xfe_mon = NULL; + +#define READ_FD 1 +#define WRITE_FD 2 + +/* +** This is a support routine to handle "deferred" i/o on sockets. +** It uses "select", so it is subject to all of the BeOS limitations +** (only READ notification, only sockets) +*/ + +/* + * socket_io_wait -- + * + * wait for socket i/o, periodically checking for interrupt + * + */ + +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 epoch, now, elapsed, remaining; + PRBool wait_for_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) { +#ifdef BONE_VERSION + _PR_MD_MAP_SELECT_ERROR(syserror); +#else + if (syserror == EBADF) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); + } else { + PR_SetError(PR_UNKNOWN_ERROR, syserror); + } +#endif + 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. + */ + wait_for_remaining = PR_TRUE; + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + wait_for_remaining = PR_FALSE; + 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) { +#ifdef BONE_VERSION + _PR_MD_MAP_SELECT_ERROR(syserror); +#else + if (syserror == EBADF) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); + } else { + PR_SetError(PR_UNKNOWN_ERROR, syserror); + } +#endif + 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) { + if (wait_for_remaining) { + now += remaining; + } else { + 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 +_MD_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + +#ifndef BONE_VERSION + if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_READ) { + _PR_MD_MAP_RECV_ERROR(EPIPE); + return -1; + } +#endif + +#ifdef BONE_VERSION + /* + ** Gah, stupid hack. If reading a zero amount, instantly return success. + ** BONE beta 6 returns EINVAL for reads of zero bytes, which parts of + ** mozilla use to check for socket availability. + */ + + if( 0 == amount ) return(0); +#endif + + while ((rv = recv(osfd, buf, amount, flags)) == -1) { + err = _MD_ERRNO(); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + /* If socket was supposed to be blocking, + wait a while for the condition to be + satisfied. */ + 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); +} + +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 ((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) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +PRInt32 +_MD_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRInt32 flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + +#ifndef BONE_VERSION + if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_WRITE) + { + _PR_MD_MAP_SEND_ERROR(EPIPE); + return -1; + } +#endif + + while ((rv = send(osfd, buf, amount, flags)) == -1) { + err = _MD_ERRNO(); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + +#ifndef BONE_VERSION + if( _PR_PENDING_INTERRUPT(me)) { + + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + /* in UNIX implementations, you could do a socket_io_wait here. + * but since BeOS doesn't yet support WRITE notification in select, + * you're spanked. + */ + snooze( 10000L ); + continue; +#else /* BONE_VERSION */ + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + goto done; +#endif + + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { + continue; + + } else { + break; + } + } + +#ifdef BONE_VERSION + /* + * 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 (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; + } + } +#endif /* BONE_VERSION */ + + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } + +#ifdef BONE_VERSION +done: +#endif + 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(); +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; + + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) &addrCopy, addrlen)) == -1) { +#else + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) { +#endif + err = _MD_ERRNO(); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + +#ifdef BONE_VERSION + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + goto done; +#endif + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { + continue; + + } else { + break; + } + } + + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } + +#ifdef BONE_VERSION +done: +#endif + return(rv); +} + +#ifdef BONE_VERSION + +PRInt32 _MD_writev( + PRFileDesc *fd, const 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; indexsecret->nonblocking) { + break; + } + 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 (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; + } + } + + + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } +done: + return(rv); +} + +#endif /* BONE_VERSION */ + +PRInt32 +_MD_accept (PRFileDesc *fd, PRNetAddr *addr, 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 it's SUPPOSED to be a blocking thread, wait + * a while to see if the triggering condition gets + * satisfied. + */ + /* Assume that we're always using a native thread */ + 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); + } else if (addr != NULL) { + /* bug 134099 */ + err = getpeername(rv, (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); + } +done: +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv != -1) { + /* Mask off the first byte of struct sockaddr (the length field) */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +PRInt32 +_MD_connect (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 osfd = fd->secret->md.osfd; + +#ifndef BONE_VERSION + fd->secret->md.connectValueValid = PR_FALSE; +#endif +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; +#endif + + /* (Copied from unix.c) + * We initiate the connection setup by making a nonblocking connect() + * call. If the connect() call fails, there are two cases we handle + * specially: + * 1. The connect() call was interrupted by a signal. In this case + * we simply retry connect(). + * 2. The NSPR socket is nonblocking and connect() fails with + * EINPROGRESS. We first wait until the socket becomes writable. + * Then we try to find out whether the connection setup succeeded + * or failed. + */ + +retry: +#ifdef _PR_HAVE_SOCKADDR_LEN + if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) { +#else + if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { +#endif + err = _MD_ERRNO(); +#ifndef BONE_VERSION + fd->secret->md.connectReturnValue = rv; + fd->secret->md.connectReturnError = err; + fd->secret->md.connectValueValid = PR_TRUE; +#endif + if( err == EINTR ) { + + if( _PR_PENDING_INTERRUPT(me)) { + + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } +#ifndef BONE_VERSION + snooze( 100000L ); +#endif + goto retry; + } + +#ifndef BONE_VERSION + if(!fd->secret->nonblocking && ((err == EINPROGRESS) || (err==EAGAIN) || (err==EALREADY))) { + + /* + ** There's no timeout on this connect, but that's not + ** a big deal, since the connect times out anyways + ** after 30 seconds. Just sleep for 1/10th of a second + ** and retry until we go through or die. + */ + + if( _PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + goto retry; + } + + if( fd->secret->nonblocking && ((err == EAGAIN) || (err == EINPROGRESS))) { + PR_Lock(_connectLock); + if (connectCount < sizeof(connectList)/sizeof(connectList[0])) { + connectList[connectCount].osfd = osfd; + memcpy(&connectList[connectCount].addr, addr, addrlen); + connectList[connectCount].addrlen = addrlen; + connectList[connectCount].timeout = timeout; + connectCount++; + PR_Unlock(_connectLock); + _PR_MD_MAP_CONNECT_ERROR(err); + } else { + PR_Unlock(_connectLock); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } + return rv; + } +#else /* BONE_VERSION */ + if(!fd->secret->nonblocking && (err == EINTR)) { + + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv == -1) { + return -1; + } + + PR_ASSERT(rv == 1); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + err = _MD_beos_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; + } + return 0; + } +#endif + + _PR_MD_MAP_CONNECT_ERROR(err); + } + + return rv; +} + +PRInt32 +_MD_bind (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv, err; +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; + rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen); +#else + rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); +#endif + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_BIND_ERROR(err); + } + + return(rv); +} + +PRInt32 +_MD_listen (PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv, err; + +#ifndef BONE_VERSION + /* Bug workaround! Setting listen to 0 on Be accepts no connections. + ** On most UN*Xes this sets the default. + */ + + if( backlog == 0 ) backlog = 5; +#endif + + 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; + +#ifndef BONE_VERSION + if (how == PR_SHUTDOWN_SEND) + fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_WRITE; + else if (how == PR_SHUTDOWN_RCV) + fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_READ; + else if (how == PR_SHUTDOWN_BOTH) { + fd->secret->md.sock_state = (BE_SOCK_SHUTDOWN_WRITE | BE_SOCK_SHUTDOWN_READ); + } + + return 0; +#else /* BONE_VERSION */ + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SHUTDOWN_ERROR(err); + } + return(rv); +#endif +} + +PRInt32 +_MD_socketpair (int af, int type, int flags, PRInt32 *osfd) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +PRInt32 +_MD_close_socket (PRInt32 osfd) +{ +#ifdef BONE_VERSION + close( osfd ); +#else + closesocket( osfd ); +#endif +} + +PRStatus +_MD_getsockname (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getsockname(fd->secret->md.osfd, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv == 0) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETSOCKNAME_ERROR(err); + } + + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_MD_getpeername (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getpeername(fd->secret->md.osfd, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); + +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv == 0) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETPEERNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_MD_getsockopt (PRFileDesc *fd, PRInt32 level, + 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; +} + +PRStatus +_MD_setsockopt (PRFileDesc *fd, PRInt32 level, + 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; +} + +PRInt32 +_MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +#ifndef BONE_VERSION +PRInt32 +_MD_socket (int af, int type, int flags) +{ + PRInt32 osfd, err; + + osfd = socket( af, type, 0 ); + + if( -1 == osfd ) { + + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKET_ERROR( err ); + } + + return( osfd ); +} +#else +PRInt32 +_MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) +{ + PRInt32 osfd, err; + + osfd = socket(domain, type, proto); + + if (osfd == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKET_ERROR(err); + } + + return(osfd); +} +#endif + +PRInt32 +_MD_socketavailable (PRFileDesc *fd) +{ +#ifdef BONE_VERSION + PRInt32 result; + + if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) { + _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO()); + return -1; + } + return result; +#else + return PR_NOT_IMPLEMENTED_ERROR; +#endif +} + +PRInt32 +_MD_get_socket_error (void) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +PRStatus +_MD_gethostname (char *name, PRUint32 namelen) +{ + PRInt32 rv, err; + + rv = gethostname(name, namelen); + if (rv == 0) + { + err = _MD_ERRNO(); + _PR_MD_MAP_GETHOSTNAME_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#ifndef BONE_VERSION +PRInt32 +_MD_beos_get_nonblocking_connect_error(PRFileDesc *fd) +{ + int rv; + int flags = 0; + + rv = recv(fd->secret->md.osfd, NULL, 0, flags); + PR_ASSERT(-1 == rv || 0 == rv); + if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) { + return errno; + } + return 0; /* no error */ +} +#else +PRInt32 +_MD_beos_get_nonblocking_connect_error(int osfd) +{ + return PR_NOT_IMPLEMENTED_ERROR; + // int err; + // _PRSockLen_t optlen = sizeof(err); + // if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) { + // return errno; + // } else { + // return err; + // } +} +#endif /* BONE_VERSION */ diff --git a/nsprpub/pr/src/md/beos/bproc.c b/nsprpub/pr/src/md/beos/bproc.c new file mode 100644 index 00000000000..dd24871b59b --- /dev/null +++ b/nsprpub/pr/src/md/beos/bproc.c @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 8; c-basic-offset: 8 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include +#include + +#define _PR_SIGNALED_EXITSTATUS 256 + +PRProcess* +_MD_create_process (const char *path, char *const *argv, + char *const *envp, const PRProcessAttr *attr) +{ + PRProcess *process; + int nEnv, idx; + char *const *childEnvp; + char **newEnvp = NULL; + int flags; + PRBool found = PR_FALSE; + + process = PR_NEW(PRProcess); + if (!process) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + childEnvp = envp; + if (attr && attr->fdInheritBuffer) { + if (NULL == childEnvp) { + childEnvp = environ; + } + for (nEnv = 0; childEnvp[nEnv]; nEnv++) { + } + newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *)); + if (NULL == newEnvp) { + PR_DELETE(process); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + for (idx = 0; idx < nEnv; idx++) { + newEnvp[idx] = childEnvp[idx]; + if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) { + newEnvp[idx] = attr->fdInheritBuffer; + found = PR_TRUE; + } + } + if (!found) { + newEnvp[idx++] = attr->fdInheritBuffer; + } + newEnvp[idx] = NULL; + childEnvp = newEnvp; + } + + process->md.pid = fork(); + + if ((pid_t) -1 == process->md.pid) { + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + return NULL; + } else if (0 == process->md.pid) { /* the child process */ + /* + * If the child process needs to exit, it must call _exit(). + * Do not call exit(), because exit() will flush and close + * the standard I/O file descriptors, and hence corrupt + * the parent process's standard I/O data structures. + */ + + if (attr) { + /* the osfd's to redirect stdin, stdout, and stderr to */ + int in_osfd = -1, out_osfd = -1, err_osfd = -1; + + if (attr->stdinFd + && attr->stdinFd->secret->md.osfd != 0) { + in_osfd = attr->stdinFd->secret->md.osfd; + if (dup2(in_osfd, 0) != 0) { + _exit(1); /* failed */ + } + flags = fcntl(0, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(0, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (attr->stdoutFd + && attr->stdoutFd->secret->md.osfd != 1) { + out_osfd = attr->stdoutFd->secret->md.osfd; + if (dup2(out_osfd, 1) != 1) { + _exit(1); /* failed */ + } + flags = fcntl(1, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(1, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (attr->stderrFd + && attr->stderrFd->secret->md.osfd != 2) { + err_osfd = attr->stderrFd->secret->md.osfd; + if (dup2(err_osfd, 2) != 2) { + _exit(1); /* failed */ + } + flags = fcntl(2, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(2, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (in_osfd != -1) { + close(in_osfd); + } + if (out_osfd != -1 && out_osfd != in_osfd) { + close(out_osfd); + } + if (err_osfd != -1 && err_osfd != in_osfd + && err_osfd != out_osfd) { + close(err_osfd); + } + if (attr->currentDirectory) { + if (chdir(attr->currentDirectory) < 0) { + _exit(1); /* failed */ + } + } + } + + if (childEnvp) { + (void)execve(path, argv, childEnvp); + } else { + /* Inherit the environment of the parent. */ + (void)execv(path, argv); + } + /* Whoops! It returned. That's a bad sign. */ + _exit(1); + } + + if (newEnvp) { + PR_DELETE(newEnvp); + } + + return process; +} + +PRStatus +_MD_detach_process (PRProcess *process) +{ + /* If we kept a process table like unix does, + * we'd remove the entry here. + * Since we dont', just delete the process variable + */ + PR_DELETE(process); + return PR_SUCCESS; +} + +PRStatus +_MD_wait_process (PRProcess *process, PRInt32 *exitCode) +{ + PRStatus retVal = PR_SUCCESS; + int ret, status; + + /* Ignore interruptions */ + do { + ret = waitpid(process->md.pid, &status, 0); + } while (ret == -1 && errno == EINTR); + + /* + * waitpid() cannot return 0 because we did not invoke it + * with the WNOHANG option. + */ + PR_ASSERT(0 != ret); + + if (ret < 0) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + + /* If child process exited normally, return child exit code */ + if (WIFEXITED(status)) { + *exitCode = WEXITSTATUS(status); + } else { + PR_ASSERT(WIFSIGNALED(status)); + *exitCode = _PR_SIGNALED_EXITSTATUS; + } + + PR_DELETE(process); + return PR_SUCCESS; +} + +PRStatus +_MD_kill_process (PRProcess *process) +{ + PRErrorCode prerror; + PRInt32 oserror; + + if (kill(process->md.pid, SIGKILL) == 0) { + return PR_SUCCESS; + } + oserror = errno; + switch (oserror) { + case EPERM: + prerror = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case ESRCH: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, oserror); + return PR_FAILURE; +} diff --git a/nsprpub/pr/src/md/beos/brng.c b/nsprpub/pr/src/md/beos/brng.c new file mode 100644 index 00000000000..2d1b85169c4 --- /dev/null +++ b/nsprpub/pr/src/md/beos/brng.c @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "primpl.h" + +extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) +{ + struct timeval tv; + int n = 0; + int s; + + GETTIMEOFDAY(&tv); + + if ( size > 0 ) { + s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec)); + size -= s; + n += s; + } + if ( size > 0 ) { + s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec)); + size -= s; + n += s; + } + + return n; +} /* end _PR_MD_GetRandomNoise() */ diff --git a/nsprpub/pr/src/md/beos/bseg.c b/nsprpub/pr/src/md/beos/bseg.c new file mode 100644 index 00000000000..b6b3b67bef2 --- /dev/null +++ b/nsprpub/pr/src/md/beos/bseg.c @@ -0,0 +1,54 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +PR_IMPLEMENT(void) + _MD_init_segs (void) +{ +} + +PR_IMPLEMENT(PRStatus) + _MD_alloc_segment (PRSegment *seg, PRUint32 size, void *vaddr) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +PR_IMPLEMENT(void) + _MD_free_segment (PRSegment *seg) +{ +} diff --git a/nsprpub/pr/src/md/beos/bsrcs.mk b/nsprpub/pr/src/md/beos/bsrcs.mk new file mode 100644 index 00000000000..c6eb6fe19bf --- /dev/null +++ b/nsprpub/pr/src/md/beos/bsrcs.mk @@ -0,0 +1,54 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +# this file lists the source files to be compiled (used in Makefile) and +# then enumerated as object files (in objs.mk) for inclusion in the NSPR +# shared library + +MDCSRCS = \ + beos.c \ + beos_errors.c \ + bfile.c \ + bmisc.c \ + bnet.c \ + bproc.c \ + brng.c \ + bseg.c \ + btime.c \ + bmmap.c \ + $(NULL) diff --git a/nsprpub/pr/src/md/beos/btime.c b/nsprpub/pr/src/md/beos/btime.c new file mode 100644 index 00000000000..aaaa9d27627 --- /dev/null +++ b/nsprpub/pr/src/md/beos/btime.c @@ -0,0 +1,75 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include + +static bigtime_t start; + +PRTime +_MD_now (void) +{ + return (PRTime)real_time_clock_usecs(); +} + +void +_MD_interval_init (void) +{ + /* grab the base interval time */ + start = real_time_clock_usecs(); +} + +PRIntervalTime +_MD_get_interval (void) +{ + return( (PRIntervalTime) real_time_clock_usecs() / 10 ); + +#if 0 + /* return the number of tens of microseconds that have elapsed since + we were initialized */ + bigtime_t now = real_time_clock_usecs(); + now -= start; + now /= 10; + return (PRIntervalTime)now; +#endif +} + +PRIntervalTime +_MD_interval_per_sec (void) +{ + return 100000L; +} diff --git a/nsprpub/pr/src/md/beos/objs.mk b/nsprpub/pr/src/md/beos/objs.mk new file mode 100644 index 00000000000..163c5d9c735 --- /dev/null +++ b/nsprpub/pr/src/md/beos/objs.mk @@ -0,0 +1,43 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# This makefile appends to the variable OBJS the platform-dependent +# object modules that will be part of the nspr20 library. + +include $(srcdir)/md/beos/bsrcs.mk + +OBJS += $(MDCSRCS:%.c=md/beos/$(OBJDIR)/%.$(OBJ_SUFFIX)) diff --git a/nsprpub/pr/src/md/mac/MANIFEST b/nsprpub/pr/src/md/mac/MANIFEST new file mode 100644 index 00000000000..c51cbd5a020 --- /dev/null +++ b/nsprpub/pr/src/md/mac/MANIFEST @@ -0,0 +1,7 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +MacErrorHandling.h +macsocket.h +prcpucfg.h diff --git a/nsprpub/pr/src/md/mac/MacErrorHandling.h b/nsprpub/pr/src/md/mac/MacErrorHandling.h new file mode 100644 index 00000000000..b0e03900052 --- /dev/null +++ b/nsprpub/pr/src/md/mac/MacErrorHandling.h @@ -0,0 +1,668 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/********************************************************************* + +FILENAME + Exceptions.h + +DESCRIPTION + A collection of routines and macros to handle assertions and + exceptions. + +COPYRIGHT + Copyright © Apple Computer, Inc. 1989-1991 + All rights reserved. + +ROUTINES + EXTERNALS + dprintf + check_dprintf + checkpos_dprintf + +MACROS + EXTERNALS + check + ncheck + check_action + ncheck_action + require + nrequire + require_action + nrequire_action + resume + +MODIFICATION HISTORY + Nov 12 95 BKJ Moved to MetroWerks environment & the NSPR + +NOTE + To keep code size down, use these routines and macros with the C + compiler option -b2 or -b3. This will eliminate duplicate strings + within a procedure. + +*********************************************************************/ + +#ifndef __MACERRORHANDLING__ +#define __MACERRORHANDLING__ + +/********************************************************************* + +INCLUDES + +*********************************************************************/ + +#include + +/**/ +/********************************************************************* + +CONSTANTS AND CONTROL + +*********************************************************************/ + +/* + These defines are used to control the amount of information + displayed when an assertion fails. DEBUGOFF and WARN will run + silently. MIN will simply break into the debugger. ON will break + and display the assertion that failed and the exception (for + require statements). FULL will also display the source file name + and line number. SYM does a SysBreak and is usefull when using a + symbolic debugger like SourceBug or SADE. They should be set into + DEBUGLEVEL. The default LEVEL is OFF. +*/ + +#define DEBUGOFF 0 +#define DEBUGWARN 1 +#define DEBUGMIN 2 +#define DEBUGON 3 +#define DEBUGFULL 4 +#define DEBUGSYM 6 + +#ifndef DEBUGLEVEL +#define DEBUGLEVEL DEBUGOFF +#endif DEBUGLEVEL + +/* + resumeLabel is used to control the insertion of labels for use with + the resume macro. If you do not use the resume macro and you wish + to have multible exceptions per label then you can add the + following define to you source code. + +*/ +#define resumeLabel(exception) // Multiple exceptions per label +// #define resumeLabel(exception) resume_ ## exception: // Single exception per label + + +/* + traceon and debugon are used to test for options +*/ + +#define traceon ((DEBUGLEVEL > DEBUGWARN) && defined(TRACEON)) +#define debugon (DEBUGLEVEL > DEBUGWARN) + +/* + Add some macros for DEBUGMIN and DEBUGSYM to keep the size down. +*/ + +#define __DEBUGSMALL ((DEBUGLEVEL == DEBUGMIN) || \ + (DEBUGLEVEL == DEBUGSYM)) + +#if DEBUGLEVEL == DEBUGMIN +#define __DebuggerBreak Debugger() +#elif DEBUGLEVEL == DEBUGSYM +#define __DebuggerBreak SysBreak() +#endif + + +/**/ +/********************************************************************* + +MACRO + check(assertion) + +DESCRIPTION + If debugging is on then check will test assertion and if it fails + break into the debugger. Otherwise check does nothing. + +*********************************************************************/ + +#if __DEBUGSMALL + +#define check(assertion) \ + do { \ + if (assertion) ; \ + else __DebuggerBreak; \ + } while (false) + +#elif DEBUGLEVEL == DEBUGON + +#define check(assertion) \ + do { \ + if (assertion) ; \ + else { \ + dprintf(notrace, "Assertion \"%s\" Failed", #assertion); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGFULL + +#define check(assertion) \ + do { \ + if (assertion) ; \ + else { \ + dprintf(notrace, "Assertion \"%s\" Failed\n" \ + "File: %s\n" \ + "Line: %d", \ + #assertion, __FILE__, __LINE__); \ + } \ + } while (false) + +#else + +#define check(assertion) + +#endif + +/**/ +/********************************************************************* + +MACRO + ncheck(assertion) + +DESCRIPTION + If debugging is on then ncheck will test !assertion and if it fails + break into the debugger. Otherwise ncheck does nothing. + +*********************************************************************/ + +#if __DEBUGSMALL + +#define ncheck(assertion) \ + do { \ + if (assertion) __DebuggerBreak; \ + } while (false) + +#elif DEBUGLEVEL == DEBUGON + +#define ncheck(assertion) \ + do { \ + void* __privateAssertion = (void*)(assertion); \ + \ + if (__privateAssertion) { \ + dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed", \ + #assertion, __privateAssertion); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGFULL + +#define ncheck(assertion) \ + do { \ + void* __privateAssertion = (void*)(assertion); \ + \ + if (__privateAssertion) { \ + dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ + "File: %s\n" \ + "Line: %d", \ + #assertion, __privateAssertion, __FILE__, __LINE__); \ + } \ + } while (false) + +#else + +#define ncheck(assertion) + +#endif + +/**/ +/********************************************************************* + +MACRO + check_action(assertion, action) + +DESCRIPTION + If debugging is on then check_action will test assertion and if it + fails break into the debugger then execute action. Otherwise + check_action does nothing. + +*********************************************************************/ + +#if __DEBUGSMALL + +#define check_action(assertion, action) \ + do { \ + if (assertion) ; \ + else { \ + __DebuggerBreak; \ + { action } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGON + +#define check_action(assertion, action) \ + do { \ + if (assertion) ; \ + else { \ + dprintf(notrace, "Assertion \"%s\" Failed", #assertion); \ + { action } \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGFULL + +#define check_action(assertion, action) \ + do { \ + if (assertion) ; \ + else { \ + dprintf(notrace, "Assertion \"%s\" Failed\n" \ + "File: %s\n" \ + "Line: %d", \ + #assertion, __FILE__, __LINE__); \ + { action } \ + } \ + } while (false) + +#else + +#define check_action(assertion, action) + +#endif + +/**/ +/************************************************************************************** + +MACRO + ncheck_action(assertion, action) + +DESCRIPTION + If debugging is on then ncheck_action will test !assertion and if + it fails break into the debugger then execute action. Otherwise + ncheck_action does nothing. + +*********************************************************************/ + +#if __DEBUGSMALL + +#define ncheck_action(assertion, action) \ + do { \ + if (assertion) { \ + __DebuggerBreak; \ + { action } \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGON + +#define ncheck_action(assertion, action) \ + do { \ + void* __privateAssertion = (void*)(assertion); \ + \ + if (__privateAssertion) { \ + dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed", \ + #assertion, __privateAssertion); \ + { action } \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGFULL + +#define ncheck_action(assertion, action) \ + do { \ + void* __privateAssertion = (void*)(assertion); \ + \ + if (__privateAssertion) { \ + dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ + "File: %s\n" \ + "Line: %d", \ + #assertion, __privateAssertion, __FILE__, __LINE__); \ + { action } \ + } \ + } while (false) + +#else + +#define ncheck_action(assertion, action) + +#endif + +/**/ +/********************************************************************* + +MACRO + require(assertion, exception) + +DESCRIPTION + require will test assertion and if it fails: + break into the debugger if debugging is on. + goto exception. + +*********************************************************************/ + +#if __DEBUGSMALL + +#define require(assertion, exception) \ + do { \ + if (assertion) ; \ + else { \ + __DebuggerBreak; \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGON + +#define require(assertion, exception) \ + do { \ + if (assertion) ; \ + else { \ + dprintf(notrace, "Assertion \"%s\" Failed\n" \ + "Exception \"%s\" Raised", \ + #assertion, #exception); \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGFULL + +#define require(assertion, exception) \ + do { \ + if (assertion) ; \ + else { \ + dprintf(notrace, "Assertion \"%s\" Failed\n" \ + "Exception \"%s\" Raised\n" \ + "File: %s\n" \ + "Line: %d", \ + #assertion, #exception, __FILE__, __LINE__); \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#else + +#define require(assertion, exception) \ + do { \ + if (assertion) ; \ + else { \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#endif + +/**/ +/********************************************************************* + +MACRO + nrequire(assertion, exception) + +DESCRIPTION + nrequire will test !assertion and if it fails: + break into the debugger if debugging is on. + goto exception. + +*********************************************************************/ + +#if __DEBUGSMALL + +#define nrequire(assertion, exception) \ + do { \ + if (assertion) { \ + DebugStr(); \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGON + +#define nrequire(assertion, exception) \ + do { \ + void* __privateAssertion = (void*)(assertion); \ + \ + if (__privateAssertion) { \ + dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ + "Exception \"%s\" Raised", \ + #assertion, __privateAssertion, #exception); \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGFULL + +#define nrequire(assertion, exception) \ + do { \ + void* __privateAssertion = (void*)(assertion); \ + \ + if (__privateAssertion) { \ + dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ + "Exception \"%s\" Raised\n" \ + "File: %s\n" \ + "Line: %d", \ + #assertion, __privateAssertion, #exception, __FILE__, \ + __LINE__); \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#else + +#define nrequire(assertion, exception) \ + do { \ + if (assertion) { \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#endif + +/**/ +/********************************************************************* + +MACRO + require_action(assertion, exception, action) + +DESCRIPTION + require_action will test assertion and if it fails: + break into the debugger if debugging is on. + execute action. + goto exception. + +*********************************************************************/ + +#if __DEBUGSMALL + +#define require_action(assertion, exception, action) \ + do { \ + if (assertion) ; \ + else { \ + __DebuggerBreak; \ + { action } \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGON + +#define require_action(assertion, exception, action) \ + do { \ + if (assertion) ; \ + else { \ + dprintf(notrace, "Assertion \"%s\" Failed\n" \ + "Exception \"%s\" Raised", \ + #assertion, #exception); \ + { action } \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGFULL + +#define require_action(assertion, exception, action) \ + do { \ + if (assertion) ; \ + else { \ + dprintf(notrace, "Assertion \"%s\" Failed\n" \ + "Exception \"%s\" Raised\n" \ + "File: %s\n" \ + "Line: %d", \ + #assertion, #exception, __FILE__, __LINE__); \ + { action } \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#else + +#define require_action(assertion, exception, action) \ + do { \ + if (assertion) ; \ + else { \ + { action } \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#endif + +/**/ +/********************************************************************* + +MACRO + nrequire_action(assertion, exception, action) + +DESCRIPTION + nrequire_action will test !assertion and if it fails: + break into the debugger if debugging is on. + execute action. + goto exception. + +*********************************************************************/ + +#if __DEBUGSMALL + +#define nrequire_action(assertion, exception, action) \ + do { \ + if (assertion) { \ + __DebuggerBreak; \ + { action } \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGON + +#define nrequire_action(assertion, exception, action) \ + do { \ + void* __privateAssertion = (void*)(assertion); \ + \ + if (__privateAssertion) { \ + dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ + "Exception \"%s\" Raised", \ + #assertion, __privateAssertion, #exception); \ + { action } \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#elif DEBUGLEVEL == DEBUGFULL + +#define nrequire_action(assertion, exception, action) \ + do { \ + void* __privateAssertion = (void*)(assertion); \ + \ + if (__privateAssertion) { \ + dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ + "Exception \"%s\" Raised\n" \ + "File: %s\n" \ + "Line: %d", \ + #assertion, __privateAssertion, #exception, __FILE__, \ + __LINE__); \ + { action } \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#else + +#define nrequire_action(assertion, exception, action) \ + do { \ + if (assertion) { \ + { action } \ + goto exception; \ + resumeLabel(exception); \ + } \ + } while (false) + +#endif + +/**/ +/********************************************************************* + +MACRO + resume(exception) + +DESCRIPTION + resume will resume execution after the n/require/_action statement + specified by exception. Resume lables must be on (the default) in + order to use resume. If an action form of require was used then the + action will not be re-executed. + +*********************************************************************/ + + +#define resume(exception) \ + do { \ + goto resume_ ## exception; \ + } while (false) + + +/**/ +/********************************************************************/ +#endif diff --git a/nsprpub/pr/src/md/mac/macdll.c b/nsprpub/pr/src/md/mac/macdll.c new file mode 100644 index 00000000000..a5ecce78b06 --- /dev/null +++ b/nsprpub/pr/src/md/mac/macdll.c @@ -0,0 +1,587 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "IterateDirectory.h" /* MoreFiles */ + +#include "MacErrorHandling.h" +#include "macdll.h" +#include "mdmac.h" +#include "macio.h" + +#include "primpl.h" +#include "plstr.h" + +/* + turds used to iterate through the directories looking + for the desired library. +*/ + +struct GetSharedLibraryFilterProcData +{ + Boolean inRecursive; + StringPtr inName; + + Boolean outFound; + CFragConnectionID outID; + Ptr outAddress; + OSErr outError; +}; +typedef struct GetSharedLibraryFilterProcData GetSharedLibraryFilterProcData; + +static pascal void +GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData); + + +/* + NSGetSharedLibrary + + Unfortunately CFM doesn't support user specified loader paths, + so we emulate the behavior. Effectively this is a GetSharedLibrary + where the loader path is user defined. +*/ + +OSErr +NSGetSharedLibrary(Str255 inLibName, CFragConnectionID* outID, Ptr* outMainAddr) +{ + char* curLibPath; + char* freeCurLibPath; + OSErr tempErr; + Boolean recursive; + FSSpec curFolder; + GetSharedLibraryFilterProcData filterData; + char *endCurLibPath; + Boolean done; + + filterData.outFound = false; + filterData.outID = (CFragConnectionID)(-1); + filterData.outAddress = NULL; + filterData.inName = inLibName; + + freeCurLibPath = curLibPath = PR_GetLibraryPath(); + + if (curLibPath == NULL) + return (cfragNoLibraryErr); + + tempErr = cfragNoLibraryErr; + + do + { + endCurLibPath = PL_strchr(curLibPath, PR_PATH_SEPARATOR); + done = (endCurLibPath == NULL); + +#if 0 + // we overload the first character of a path if it's : + // then we want to recursively search that path + // see if path should be recursive + if (*curLibPath == ':') + { + // ':' is an illegal character in the name of a file + // if we start any path with this, we want to allow + // search recursively + curLibPath++; + recursive = true; + } + else +#endif + { + recursive = false; + } + + if (!done) + *endCurLibPath = '\0'; // NULL terminate the string + + // convert to FSSpec + tempErr = ConvertUnixPathToFSSpec(curLibPath, &curFolder); + + // now look in this directory + if (noErr == tempErr) + { + filterData.inRecursive = recursive; + FSpIterateDirectory(&curFolder, recursive ? 0 : 1, &GetSharedLibraryFilterProc, &filterData); + + if (filterData.outFound) + { + *outID = filterData.outID; + *outMainAddr = filterData.outAddress; + tempErr = noErr; + break; + } + else + { + tempErr = cfragNoLibraryErr; + } + } + + curLibPath = endCurLibPath + 1; // skip to next path (past the '\0'); + } while (!done); + + free(freeCurLibPath); + return (tempErr); +} + + +static Boolean +LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength); + + +/* + GetSharedLibraryFilterProc + + Callback to FSpIterateDirectory, finds a library with the name matching the + data in inFilterData (of type GetSharedLibraryFilterProcData). Forces a quit + when a match is found. +*/ + +static pascal void +GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData) +{ + GetSharedLibraryFilterProcData* pFilterData = (GetSharedLibraryFilterProcData*) inFilterData; + + if ((inCpb->hFileInfo.ioFlAttrib & (1 << ioDirFlg)) == 0) + { + FSSpec fragSpec; + OSErr tempErr; + Str255 errName; + Boolean crap; + UInt32 codeOffset; + UInt32 codeLength; + + // it's a file + + // ¥ fix-me do we really want to allow all 'APPL's' for in which to find this library? + switch (inCpb->hFileInfo.ioFlFndrInfo.fdType) + { + case kCFragLibraryFileType: + case 'APPL': + tempErr = FSMakeFSSpec(inCpb->hFileInfo.ioVRefNum, inCpb->hFileInfo.ioFlParID, inCpb->hFileInfo.ioNamePtr, &fragSpec); + + // this shouldn't fail + if (noErr != tempErr) + { + return; + } + + // resolve an alias if this was one + tempErr = ResolveAliasFile(&fragSpec, true, &crap, &crap); + + // if got here we have a shlb (or app-like shlb) + if (noErr != tempErr) + { + // probably couldn't resolve an alias + return; + } + + break; + default: + return; + } + + // see if this symbol is in this fragment + if (LibInPefContainer(&fragSpec, pFilterData->inName, &codeOffset, &codeLength)) + tempErr = GetDiskFragment(&fragSpec, codeOffset, codeLength, fragSpec.name, kLoadCFrag, &pFilterData->outID, &pFilterData->outAddress, errName); + else + return; + + // stop if we found a library by that name + if (noErr == tempErr) + { + *inWantQuit = true; + pFilterData->outFound = true; + pFilterData->outError = tempErr; + } + } + // FSpIterateDirectory will automagically call us for subsequent sub-dirs if necessary +} + + +/* + LibInPefContainer + + Tell whether library inName is contained it the file pointed to by inSpec. + Return the codeOffset and codeLength information, for a subsequent + call to GetDiskFragment. +*/ + +static Boolean +LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength) +{ + short refNum; + CFragResourceHandle hCfrg; + CFragResourceMember* pCurItem; + UInt32 curLibIndex; + Boolean found; + + // asume we didn't find it + found = false; + + // open the resource fork, if we can't bail + refNum = FSpOpenResFile(inSpec, fsRdPerm); + require(-1 != refNum, Exit); + + // grab out the alias record, if it's not there bail + hCfrg = (CFragResourceHandle) Get1Resource(kCFragResourceType, kCFragResourceID); + require(NULL != hCfrg, CloseResourceAndExit); + + HLock((Handle)hCfrg); + + // get ptr to first item + pCurItem = &(*hCfrg)->firstMember; + for (curLibIndex = 0; curLibIndex < (*hCfrg)->memberCount; curLibIndex++) + { + // is this our library? + if ((pCurItem->name[0] == inName[0]) && + (strncmp((char*) inName + 1, (char*) pCurItem->name + 1, PR_MIN(pCurItem->name[0], inName[0])) == 0)) + { + *outCodeOffset = pCurItem->offset; + *outCodeLength = pCurItem->length; + found = true; + } + + // skip to next one + pCurItem = (CFragResourceMember*) ((char*) pCurItem + pCurItem->memberSize); + } + + HUnlock((Handle)hCfrg); + +CloseResourceAndExit: + CloseResFile(refNum); +Exit: + return (found); + +} + + +/* + NSFindSymbol + + Workaround bug in CFM FindSymbol (in at least 7.5.5) where symbols with lengths + greater than 63 chars cause a "paramErr". We iterate through all symbols + in the library to find the desired symbol. +*/ + +OSErr +NSFindSymbol(CFragConnectionID inID, Str255 inSymName, Ptr* outMainAddr, CFragSymbolClass *outSymClass) +{ + OSErr err; + + if (inSymName[0] > 63) + { + /* + if there are greater than 63 characters in the + name, CFM FindSymbol fails, so let's iterate through all + of the symbols in the fragment and grab it + that way. + */ + long symbolCount; + Str255 curSymName; + long curIndex; + Boolean found; + + found = false; + err = CountSymbols(inID, &symbolCount); + if (noErr == err) + { + /* now iterate through all the symbols in the library */ + /* per DTS the indices apparently go 0 to n-1 */ + for (curIndex = 0; (curIndex <= symbolCount - 1 && !found); curIndex++) + { + err = GetIndSymbol(inID, curIndex, curSymName, outMainAddr, outSymClass); + if (noErr == err && curSymName[0] == inSymName[0] && !strncmp((char*)curSymName + 1, (char*)inSymName + 1, curSymName[0])) + { + /* found our symbol */ + found = true; + } + } + + /* if we didn't find it set the error code so below it won't take this symbol */ + if (!found) + err = cfragNoSymbolErr; + } + } + else + { + err = FindSymbol(inID, inSymName, outMainAddr, outSymClass); + } + + return (err); +} + + +#pragma mark - + + +/*----------------------------------------------------------------- + + GetNamedFragmentOffsets + + Get the offsets into the data fork of the named fragment, + by reading the 'cfrg' resoruce. + +-----------------------------------------------------------------*/ +OSErr GetNamedFragmentOffsets(const FSSpec *fileSpec, const char* fragmentName, + UInt32 *outOffset, UInt32 *outLength) +{ + CFragResourceHandle cFragHandle; + short fileRefNum; + OSErr err = noErr; + + fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm); + err = ResError(); + if (err != noErr) return err; + + cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID); + if (!cFragHandle) + { + err = resNotFound; + goto done; + } + + /* nothing here moves memory, so no need to lock the handle */ + + err = cfragNoLibraryErr; /* in case of failure */ + *outOffset = 0; + *outLength = 0; + + /* Now look for the named fragment */ + if ((**cFragHandle).memberCount > 0) + { + CFragResourceMemberPtr memberPtr; + UInt16 i; + + for ( i = 0, memberPtr = &(**cFragHandle).firstMember; + i < (**cFragHandle).memberCount; + i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize)) + { + char memberName[256]; + UInt16 nameLen = PR_MIN(memberPtr->name[0], 255); + + // avoid malloc here for speed + strncpy(memberName, (char *)&memberPtr->name[1], nameLen); + memberName[nameLen] = '\0'; + + // fragment names are case insensitive, so act like the system + if (PL_strcasecmp(memberName, fragmentName) == 0) + { + *outOffset = memberPtr->offset; + *outLength = memberPtr->length; + err = noErr; + break; + } + } + } + + /* Resource handle will go away when the res fork is closed */ + +done: + CloseResFile(fileRefNum); + return err; +} + + +/*----------------------------------------------------------------- + + GetIndexedFragmentOffsets + + Get the offsets into the data fork of the indexed fragment, + by reading the 'cfrg' resoruce. + +-----------------------------------------------------------------*/ +OSErr GetIndexedFragmentOffsets(const FSSpec *fileSpec, UInt32 fragmentIndex, + UInt32 *outOffset, UInt32 *outLength, char **outFragmentName) +{ + CFragResourceHandle cFragHandle; + short fileRefNum; + OSErr err = noErr; + + fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm); + err = ResError(); + if (err != noErr) return err; + + cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID); + if (!cFragHandle) + { + err = resNotFound; + goto done; + } + + err = cfragNoLibraryErr; /* in case of failure */ + *outOffset = 0; + *outLength = 0; + *outFragmentName = NULL; + + /* the CStrFromPStr mallocs, so might move memory */ + HLock((Handle)cFragHandle); + + /* Now look for the named fragment */ + if ((**cFragHandle).memberCount > 0) + { + CFragResourceMemberPtr memberPtr; + UInt16 i; + + for ( i = 0, memberPtr = &(**cFragHandle).firstMember; + i < (**cFragHandle).memberCount; + i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize)) + { + + if (i == fragmentIndex) + { + char *fragmentStr; + CStrFromPStr(memberPtr->name, &fragmentStr); + if (!fragmentStr) /* test for allocation failure */ + { + err = memFullErr; + break; + } + + *outFragmentName = fragmentStr; + *outOffset = memberPtr->offset; + *outLength = memberPtr->length; + err = noErr; + break; + } + } + } + + HUnlock((Handle)cFragHandle); + + /* Resource handle will go away when the res fork is closed */ + +done: + CloseResFile(fileRefNum); + return err; +} + + +/*----------------------------------------------------------------- + + NSLoadNamedFragment + + Load the named fragment from the specified file. Aliases must + have been resolved by this point. + +-----------------------------------------------------------------*/ + +OSErr NSLoadNamedFragment(const FSSpec *fileSpec, const char* fragmentName, CFragConnectionID *outConnectionID) +{ + UInt32 fragOffset, fragLength; + short fragNameLength; + Ptr main; + Str255 fragName; + Str255 errName; + OSErr err; + + err = GetNamedFragmentOffsets(fileSpec, fragmentName, &fragOffset, &fragLength); + if (err != noErr) return err; + + // convert fragment name to pascal string + fragNameLength = strlen(fragmentName); + if (fragNameLength > 255) + fragNameLength = 255; + BlockMoveData(fragmentName, &fragName[1], fragNameLength); + fragName[0] = fragNameLength; + + // Note that we pass the fragment name as the 4th param to GetDiskFragment. + // This value affects the ability of debuggers, and the Talkback system, + // to match code fragments with symbol files + err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName, + kLoadCFrag, outConnectionID, &main, errName); + + return err; +} + + +/*----------------------------------------------------------------- + + NSLoadIndexedFragment + + Load the indexed fragment from the specified file. Aliases must + have been resolved by this point. + + *outFragName is a malloc'd block containing the fragment name, + if returning noErr. + +-----------------------------------------------------------------*/ + +OSErr NSLoadIndexedFragment(const FSSpec *fileSpec, PRUint32 fragmentIndex, + char** outFragName, CFragConnectionID *outConnectionID) +{ + UInt32 fragOffset, fragLength; + char *fragNameBlock = NULL; + Ptr main; + Str255 fragName = "\p"; + Str255 errName; + OSErr err; + + *outFragName = NULL; + + err = GetIndexedFragmentOffsets(fileSpec, fragmentIndex, &fragOffset, &fragLength, &fragNameBlock); + if (err != noErr) return err; + + if (fragNameBlock) + { + UInt32 nameLen = strlen(fragNameBlock); + if (nameLen > 63) + nameLen = 63; + BlockMoveData(fragNameBlock, &fragName[1], nameLen); + fragName[0] = nameLen; + } + + // Note that we pass the fragment name as the 4th param to GetDiskFragment. + // This value affects the ability of debuggers, and the Talkback system, + // to match code fragments with symbol files + err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName, + kLoadCFrag, outConnectionID, &main, errName); + if (err != noErr) + { + free(fragNameBlock); + return err; + } + + *outFragName = fragNameBlock; + return noErr; +} + + diff --git a/nsprpub/pr/src/md/mac/macdll.h b/nsprpub/pr/src/md/mac/macdll.h new file mode 100644 index 00000000000..a34890cd33f --- /dev/null +++ b/nsprpub/pr/src/md/mac/macdll.h @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef macdll_h__ +#define macdll_h__ + +#include "prtypes.h" + +OSErr GetNamedFragmentOffsets(const FSSpec *fileSpec, const char* fragmentName, + UInt32 *outOffset, UInt32 *outLength); +OSErr GetIndexedFragmentOffsets(const FSSpec *fileSpec, UInt32 fragmentIndex, + UInt32 *outOffset, UInt32 *outLength, char **outFragmentName); + +OSErr NSLoadNamedFragment(const FSSpec *fileSpec, const char* fragmentName, CFragConnectionID *outConnectionID); +OSErr NSLoadIndexedFragment(const FSSpec *fileSpec, PRUint32 fragmentIndex, + char** outFragName, CFragConnectionID *outConnectionID); + + +OSErr NSGetSharedLibrary(Str255 inLibName, CFragConnectionID* outID, Ptr* outMainAddr); +OSErr NSFindSymbol(CFragConnectionID inID, Str255 inSymName, + Ptr* outMainAddr, CFragSymbolClass *outSymClass); + +#endif /* macdll_h__ */ diff --git a/nsprpub/pr/src/md/mac/macio.c b/nsprpub/pr/src/md/mac/macio.c new file mode 100644 index 00000000000..ae3516de1bf --- /dev/null +++ b/nsprpub/pr/src/md/mac/macio.c @@ -0,0 +1,1949 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "FullPath.h" /* MoreFiles */ + +#include "primpl.h" +#include "MacErrorHandling.h" +#include "mdmac.h" + +#include "macio.h" + +/* forward declarations */ +extern unsigned long gJanuaryFirst1970Seconds; + +extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout); +extern void DoneWaitingOnThisThread(PRThread *thread); +extern void AsyncNotify(PRThread *thread); + + +/* PB for Read and Write */ +struct ExtendedParamBlock { + /* PB must be first so that the file system can get the right data. */ + ParamBlockRec pb; + PRThread *thread; +}; +typedef struct ExtendedParamBlock ExtendedParamBlock; + + +/* XXX Not done yet for 68K */ +/* I/O completion routne for _MD_READ and _MD_WRITE */ +static void AsyncIOCompletion (ExtendedParamBlock *pbAsyncPtr) +{ + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + PRThread *thread = pbAsyncPtr->thread; + PRIntn is; + + if (_PR_MD_GET_INTSOFF()) { + thread->md.missedIONotify = PR_TRUE; + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + } else { + _PR_INTSOFF(is); + + thread->md.osErrCode = noErr; + DoneWaitingOnThisThread(thread); + + _PR_FAST_INTSON(is); + } + + SignalIdleSemaphore(); +} + +void _MD_SetError(OSErr oserror) +{ + PRErrorCode code; + + switch (oserror) { + case memFullErr: + code = PR_OUT_OF_MEMORY_ERROR; + break; + case fnfErr: + code = PR_FILE_NOT_FOUND_ERROR; + break; + case dupFNErr: + code = PR_FILE_EXISTS_ERROR; + break; + case ioErr: + code = PR_IO_ERROR; + break; + case nsvErr: + case wrgVolTypErr: + code = PR_INVALID_DEVICE_STATE_ERROR; + break; + case bdNamErr: + case fsRnErr: + code = PR_NAME_TOO_LONG_ERROR; + break; + case tmfoErr: + code = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case opWrErr: + case wrPermErr: + case permErr: + case afpAccessDenied: + code = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case afpObjectTypeErr: + code = PR_DIRECTORY_LOOKUP_ERROR; + break; + case wPrErr: + case vLckdErr: + code = PR_DEVICE_IS_LOCKED_ERROR; + break; + case fLckdErr: + code = PR_FILE_IS_LOCKED_ERROR; + break; + case dirNFErr: + code = PR_NOT_DIRECTORY_ERROR; + break; + case dirFulErr: + code = PR_MAX_DIRECTORY_ENTRIES_ERROR; + break; + case dskFulErr: + code = PR_NO_DEVICE_SPACE_ERROR; + break; + case rfNumErr: + case fnOpnErr: + code = PR_BAD_DESCRIPTOR_ERROR; + break; + case eofErr: + code = PR_END_OF_FILE_ERROR; + break; + case posErr: + case gfpErr: + code = PR_FILE_SEEK_ERROR; + break; + case fBsyErr: + code = PR_FILE_IS_BUSY_ERROR; + break; + case extFSErr: + code = PR_REMOTE_FILE_ERROR; + break; + case abortErr: + code = PR_PENDING_INTERRUPT_ERROR; + break; + case paramErr: + code = PR_INVALID_ARGUMENT_ERROR; + break; + case unimpErr: + code = PR_NOT_IMPLEMENTED_ERROR; + break; + } + + PR_SetError(code, oserror); +} + +void _MD_IOInterrupt(void) +{ + PRCList *qp; + PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + + _PR_SLEEPQ_LOCK(me->cpu); + qp = _PR_PAUSEQ(me->cpu).next; + while (qp != &_PR_PAUSEQ(me->cpu)) { + + thread = _PR_THREAD_PTR(qp); + PR_ASSERT(thread->flags & _PR_ON_PAUSEQ); + + qp = qp->next; + + if (thread->md.missedIONotify) { + thread->md.missedIONotify = PR_FALSE; + DoneWaitingOnThisThread(thread); + } + + if (thread->md.missedAsyncNotify) { + thread->md.missedAsyncNotify = PR_FALSE; + AsyncNotify(thread); + } + } + qp = _PR_SLEEPQ(me->cpu).next; + while (qp != &_PR_SLEEPQ(me->cpu)) { + + thread = _PR_THREAD_PTR(qp); + PR_ASSERT(thread->flags & _PR_ON_SLEEPQ); + + qp = qp->next; + + if (thread->md.missedIONotify) { + thread->md.missedIONotify = PR_FALSE; + DoneWaitingOnThisThread(thread); + } + + if (thread->md.missedAsyncNotify) { + thread->md.missedAsyncNotify = PR_FALSE; + AsyncNotify(thread); + } + } + _PR_SLEEPQ_UNLOCK(thread->cpu); +} + +/* +** All PR_read and PR_Write calls are synchronous from caller's perspective. +** They are internally made asynchronous calls. This gives cpu to other +** user threads while the async io is in progress. +*/ +PRInt32 ReadWriteProc(PRFileDesc *fd, void *buf, PRUint32 bytes, IOOperation op) +{ + PRInt32 refNum = fd->secret->md.osfd; + OSErr err; + ExtendedParamBlock pbAsync; + PRThread *me = _PR_MD_CURRENT_THREAD(); + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + + /* quick hack to allow PR_fprintf, etc to work with stderr, stdin, stdout */ + /* note, if a user chooses "seek" or the like as an operation in another function */ + /* this will not work */ + if (refNum >= 0 && refNum < 3) + { + switch (refNum) + { + case 0: + /* stdin - not on a Mac for now */ + err = paramErr; + goto ErrorExit; + break; + case 1: /* stdout */ + case 2: /* stderr */ + puts(buf); + break; + } + + return (bytes); + } + else + { + static IOCompletionUPP sCompletionUPP = NULL; + + PRBool doingAsync = PR_FALSE; + + /* allocate the callback Universal Procedure Pointer (UPP). This actually allocates + a 32 byte Ptr in the heap, so only do this once + */ + if (!sCompletionUPP) + sCompletionUPP = NewIOCompletionUPP((IOCompletionProcPtr)&AsyncIOCompletion); + + /* grab the thread so we know which one to post to at completion */ + pbAsync.thread = me; + + pbAsync.pb.ioParam.ioCompletion = sCompletionUPP; + pbAsync.pb.ioParam.ioResult = noErr; + pbAsync.pb.ioParam.ioRefNum = refNum; + pbAsync.pb.ioParam.ioBuffer = buf; + pbAsync.pb.ioParam.ioReqCount = bytes; + pbAsync.pb.ioParam.ioPosMode = fsAtMark; + pbAsync.pb.ioParam.ioPosOffset = 0; + + /* + ** Issue the async read call and wait for the io semaphore associated + ** with this thread. + ** Async file system calls *never* return error values, so ignore their + ** results (see ); + ** the completion routine is always called. + */ + me->io_fd = refNum; + me->md.osErrCode = noErr; + if (op == READ_ASYNC) + { + /* + ** Skanky optimization so that reads < 20K are actually done synchronously + ** to optimize performance on small reads (e.g. registry reads on startup) + */ + if ( bytes > 20480L ) + { + doingAsync = PR_TRUE; + me->io_pending = PR_TRUE; + + (void)PBReadAsync(&pbAsync.pb); + } + else + { + pbAsync.pb.ioParam.ioCompletion = NULL; + me->io_pending = PR_FALSE; + + err = PBReadSync(&pbAsync.pb); + if (err != noErr && err != eofErr) + goto ErrorExit; + } + } + else + { + doingAsync = PR_TRUE; + me->io_pending = PR_TRUE; + + /* writes are currently always async */ + (void)PBWriteAsync(&pbAsync.pb); + } + + if (doingAsync) { + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + } + } + + err = me->md.osErrCode; + if (err != noErr) + goto ErrorExit; + + err = pbAsync.pb.ioParam.ioResult; + if (err != noErr && err != eofErr) + goto ErrorExit; + + return pbAsync.pb.ioParam.ioActCount; + +ErrorExit: + me->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +/* +Special WriteSyncProc for logging only. IO occurs synchronously. Otherwise, +logging internal to NSPR causes ReadWriteProc above to recurse on PR_WaitSem logging. +*/ +PRInt32 WriteSyncProc(PRFileDesc *fd, void *buf, PRUint32 bytes) +{ + PRInt32 refNum = fd->secret->md.osfd; + OSErr err; + ParamBlockRec pb; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (refNum >= 0 && refNum < 3) + { + PR_ASSERT(FALSE); /* writing to these is hazardous to a Mac's health (refNum 2 is the system file) */ + err = paramErr; + goto ErrorExit; + } + + pb.ioParam.ioCompletion = NULL; + pb.ioParam.ioResult = noErr; + pb.ioParam.ioRefNum = refNum; + pb.ioParam.ioBuffer = buf; + pb.ioParam.ioReqCount = bytes; + pb.ioParam.ioPosMode = fsAtMark; + pb.ioParam.ioPosOffset = 0; + + err = PBWriteSync(&pb); + + if (err != noErr) + goto ErrorExit; + else + return pb.ioParam.ioActCount; + +ErrorExit: + me->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +/* File I/O functions called by PR I/O routines */ +PRInt32 _MD_Open(const char *path, PRIntn flags, int mode) +{ +// Macintosh doesn't really have mode bits, just drop them +#pragma unused (mode) + + OSErr err; + HParamBlockRec hpb; + ParamBlockRec pb; + char *macFileName = NULL; + Str255 pascalName; + PRInt8 perm; + + err = ConvertUnixPathToMacPath(path, &macFileName); + + if (err != noErr) + goto ErrorExit; + + hpb.ioParam.ioCompletion = NULL; + PStrFromCStr(macFileName, pascalName); + PR_DELETE(macFileName); + hpb.ioParam.ioNamePtr = pascalName; + hpb.ioParam.ioVRefNum = 0; + hpb.ioParam.ioVersNum = 0; + hpb.fileParam.ioDirID = 0; + + if (flags & PR_RDWR) + perm = fsRdWrPerm; + else if (flags & PR_WRONLY) + perm = fsWrPerm; + else + perm = fsRdPerm; + hpb.ioParam.ioPermssn = perm; + + + if (flags & PR_CREATE_FILE) { + err = PBHCreateSync(&hpb); + + /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */ + if ((flags & PR_EXCL) && (err == dupFNErr)) { + err = PR_FILE_EXISTS_ERROR; + goto ErrorExit; + } + + if ((err != noErr) && (err != dupFNErr)) + goto ErrorExit; + } + + err = PBHOpenDFSync(&hpb); + + if (err != noErr) + goto ErrorExit; + + if (flags & PR_TRUNCATE) { + pb.ioParam.ioCompletion = NULL; + pb.ioParam.ioRefNum = hpb.ioParam.ioRefNum; + pb.ioParam.ioMisc = NULL; + err = PBSetEOFSync(&pb); + if (err != noErr) + goto ErrorExit; + } else if (flags & PR_APPEND) { + pb.ioParam.ioCompletion = NULL; + pb.ioParam.ioRefNum = hpb.ioParam.ioRefNum; + pb.ioParam.ioPosMode = fsFromLEOF; + pb.ioParam.ioPosOffset = 0; + err = PBSetFPosSync(&pb); + if (err != noErr) + goto ErrorExit; + } + return hpb.ioParam.ioRefNum; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +/* _MD_CLOSE_FILE, _MD_READ, _MD_WRITE, _MD_GET_FILE_ERROR are defined in _macos.h */ + +PROffset32 _MD_LSeek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how) +{ + PRInt32 refNum = fd->secret->md.osfd; + OSErr err = noErr; + long curPos, endPos; + + /* compute new mark */ + switch (how) { + case PR_SEEK_SET: + endPos = offset; + break; + + case PR_SEEK_CUR: + err = GetFPos(refNum, &curPos); + endPos = curPos + offset; + break; + + case PR_SEEK_END: + err = GetEOF(refNum, &curPos); + endPos = curPos + offset; + break; + + default: + err = paramErr; + break; + } + + /* set the new mark and extend the file if seeking beyond current EOF */ + /* making sure to set the mark after any required extend */ + if (err == noErr) { + err = SetFPos(refNum, fsFromStart, endPos); + if (err == eofErr) { + err = SetEOF(refNum, endPos); + if (err == noErr) { + err = SetFPos(refNum, fsFromStart, endPos); + } + } + } + + if (err == noErr) { + return endPos; + } else { + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; + } +} + +PRInt32 _MD_FSync(PRFileDesc *fd) +{ + PRInt32 refNum = fd->secret->md.osfd; + OSErr err; + ParamBlockRec pb; + + pb.ioParam.ioCompletion = NULL; + pb.ioParam.ioRefNum = refNum; + + err = PBFlushFileSync(&pb); + if (err != noErr) + goto ErrorExit; + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +#include "plstr.h" + +PRStatus _MD_OpenDir(_MDDir *mdDir,const char *name) +{ + // Emulate the Unix opendir() routine. + + OSErr err; + CInfoPBRec pb; + char *macDirName = NULL; + char *position = NULL; + char volumeName[32]; + Str255 pascalName; + + // Get the Macintosh path + err = ConvertUnixPathToMacPath(name, &macDirName); + if (err != noErr) + goto ErrorExit; + + // Get the vRefNum + position = PL_strchr(macDirName, PR_PATH_SEPARATOR); + if ((position == macDirName) || (position == NULL)) + mdDir->ioVRefNum = 0; // Use application relative searching + else { + memset(volumeName, 0, sizeof(volumeName)); + strncpy(volumeName, macDirName, position-macDirName); + mdDir->ioVRefNum = GetVolumeRefNumFromName(volumeName); + } + + // Get info about the object. + PStrFromCStr(macDirName, pascalName); + PR_DELETE(macDirName); + + pb.dirInfo.ioNamePtr = pascalName; + pb.dirInfo.ioVRefNum = mdDir->ioVRefNum; + pb.dirInfo.ioDrDirID = 0; + pb.dirInfo.ioFDirIndex = 0; + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + // Are we dealing with a directory? + if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) { + err = dirNFErr; + goto ErrorExit; + } + + /* This is a directory, store away the pertinent information. + ** We post increment. I.e. index is always the nth. item we + ** should get on the next call + */ + mdDir->ioDirID = pb.dirInfo.ioDrDirID; + mdDir->currentEntryName = NULL; + mdDir->ioFDirIndex = 1; + return PR_SUCCESS; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return PR_FAILURE; +} + +char *_MD_ReadDir(_MDDir *mdDir, PRIntn flags) +{ + // Emulate the Unix readdir() routine. + + // Mac doesnÕt have the concept of .(PR_SKIP_DOT) & ..(PR_SKIP_DOT_DOT) + + OSErr err; + CInfoPBRec pb; + char *returnedCStr; + Str255 pascalName = "\p"; + PRBool foundEntry; + + PR_ASSERT(mdDir != NULL); + + do { + + // Release the last name read. + PR_DELETE(mdDir->currentEntryName); + mdDir->currentEntryName = NULL; + + // WeÕve got all the info we need, just get info about this guy. + pb.hFileInfo.ioNamePtr = pascalName; + pb.hFileInfo.ioVRefNum = mdDir->ioVRefNum; + pb.hFileInfo.ioFDirIndex = mdDir->ioFDirIndex; + pb.hFileInfo.ioDirID = mdDir->ioDirID; + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + // Convert the Pascal string to a C string (actual allocation occurs in CStrFromPStr) + CStrFromPStr(pascalName, &returnedCStr); + + mdDir->currentEntryName = returnedCStr; + mdDir->ioFDirIndex++; + + // If it is not a hidden file and the flags did not specify skipping, we are done. + if ((flags & PR_SKIP_HIDDEN) && (pb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible)) + foundEntry = PR_FALSE; + else + foundEntry = PR_TRUE; + + } while (!foundEntry); + + return (mdDir->currentEntryName); + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return NULL; +} + + +void _MD_CloseDir(_MDDir *mdDir) +{ + // Emulate the Unix closedir() routine + + PR_DELETE(mdDir->currentEntryName); +} + +PRInt32 _MD_MkDir(char *unixPath, PRIntn mode) +{ + HFileParam fpb; + Str255 pascalName = "\p"; + char *cMacPath = NULL; + OSErr err; + + #pragma unused (mode) // Mode is ignored on the Mac + + if (unixPath) { + err = ConvertUnixPathToMacPath(unixPath, &cMacPath); + if (err != noErr) + goto ErrorExit; + + PStrFromCStr(cMacPath, pascalName); + PR_DELETE(cMacPath); + fpb.ioNamePtr = pascalName; + fpb.ioVRefNum = 0; + fpb.ioDirID = 0L; + + err = PBDirCreateSync((HParmBlkPtr)&fpb); + if (err != noErr) + goto ErrorExit; + } + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_Delete(char *unixPath) +{ + HFileParam fpb; + Str255 pascalName = "\p"; + char *cMacPath = NULL; + OSErr err; + + if (unixPath) { + err = ConvertUnixPathToMacPath(unixPath, &cMacPath); + if (err != noErr) + goto ErrorExit; + + PStrFromCStr(cMacPath, pascalName); + PR_DELETE(cMacPath); + fpb.ioNamePtr = pascalName; + fpb.ioVRefNum = 0; + fpb.ioDirID = 0L; + + err = PBHDeleteSync((HParmBlkPtr)&fpb); + if (err != noErr) + goto ErrorExit; + } + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_Rename(char *fromUnixPath, char *toUnixPath) +{ + OSErr err; + FSSpec fromSpec; + FSSpec toSpec; + FSSpec destDirSpec; + FSSpec beforeRenameSpec; + + if (fromUnixPath && toUnixPath) { + err = ConvertUnixPathToFSSpec(fromUnixPath, &fromSpec); + if (err != noErr) + goto ErrorExit; + + err = ConvertUnixPathToFSSpec(toUnixPath, &toSpec); + if (err != noErr && err != fnfErr) + goto ErrorExit; + + /* make an FSSpec for the destination directory */ + err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, nil, &destDirSpec); + if (err != noErr) /* parent directory must exist */ + goto ErrorExit; + + // move it to the directory specified + err = FSpCatMove(&fromSpec, &destDirSpec); + if (err != noErr) + goto ErrorExit; + + // make a new FSSpec for the file or directory in its new location + err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, fromSpec.name, &beforeRenameSpec); + if (err != noErr) + goto ErrorExit; + + // rename the file or directory + err = FSpRename(&beforeRenameSpec, toSpec.name); + if (err != noErr) + goto ErrorExit; + + } else { + err = paramErr; + goto ErrorExit; + } + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +#define kWriteAccessAllowed (0x100) +PRInt32 _MD_Access(char *unixPath, int amode) +{ + // + // Emulate the Unix access routine + // + + OSErr err; + CInfoPBRec pb; + FCBPBRec fcbpb; + char *cMacPath = NULL; + Str255 pascalMacPath; + struct stat info; + + // Convert to a Mac style path + err = ConvertUnixPathToMacPath(unixPath, &cMacPath); + if (err != noErr) + goto ErrorExit; + + err = stat(cMacPath, &info); + if (err != noErr) + goto ErrorExit; + + + // If all weÕre doing is checking for the existence of the file, weÕre out of here. + // On the Mac, if a file exists, you can read from it. + // This doesnÕt handle remote AppleShare volumes. Does it need to? + if ((amode == PR_ACCESS_EXISTS) || (amode == PR_ACCESS_READ_OK)) { + goto success; + } + + PStrFromCStr(cMacPath, pascalMacPath); + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = info.st_dev; + pb.hFileInfo.ioDirID = 0; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + // Check out all the access permissions. + + if (amode == PR_ACCESS_WRITE_OK) { + fcbpb.ioNamePtr = NULL; + fcbpb.ioVRefNum = pb.hFileInfo.ioVRefNum; + fcbpb.ioRefNum = pb.hFileInfo.ioFRefNum; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) + goto ErrorExit; + + /* Look at Inside Mac IV-180 */ + if ((fcbpb.ioFCBFlags & kWriteAccessAllowed) == 0) { + err = permErr; + goto ErrorExit; + } + } + +success: + PR_DELETE(cMacPath); + return 0; + +ErrorExit: + if (cMacPath != NULL) + PR_DELETE(cMacPath); + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_GetFileInfo(char *unixPath, PRFileInfo *info) +{ + CInfoPBRec pb; + OSErr err; + char *cMacPath = NULL; + Str255 pascalMacPath; + PRTime oneMillion, dateInMicroSeconds; + + // Convert to a Mac style path + err = ConvertUnixPathToMacPath(unixPath, &cMacPath); + if (err != noErr) + goto ErrorExit; + + PStrFromCStr(cMacPath, pascalMacPath); + PR_DELETE(cMacPath); + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = 0; + pb.hFileInfo.ioDirID = 0; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + if (pb.hFileInfo.ioFlAttrib & ioDirMask) { + info->type = PR_FILE_DIRECTORY; + info->size = 0; + } else { + info->type = PR_FILE_FILE; + info->size = pb.hFileInfo.ioFlLgLen + pb.hFileInfo.ioFlRLgLen; + } + + pb.hFileInfo.ioFlCrDat -= gJanuaryFirst1970Seconds; + LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlCrDat); + LL_I2L(oneMillion, PR_USEC_PER_SEC); + LL_MUL(info->creationTime, oneMillion, dateInMicroSeconds); + + pb.hFileInfo.ioFlMdDat -= gJanuaryFirst1970Seconds; + LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlMdDat); + LL_MUL(info->modifyTime, oneMillion, dateInMicroSeconds); + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_GetOpenFileInfo(const PRFileDesc *fd, PRFileInfo *info) +{ + OSErr err; + FCBPBRec fcbpb; + CInfoPBRec pb; + Str255 pascalMacPath; + PRTime oneMillion, dateInMicroSeconds; + + fcbpb.ioNamePtr = pascalMacPath; + fcbpb.ioVRefNum = 0; + fcbpb.ioRefNum = fd->secret->md.osfd; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) + goto ErrorExit; + + info->type = PR_FILE_FILE; + info->size = fcbpb.ioFCBEOF; + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = fcbpb.ioFCBVRefNum; + pb.hFileInfo.ioDirID = fcbpb.ioFCBParID; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + pb.hFileInfo.ioFlCrDat -= gJanuaryFirst1970Seconds; + LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlCrDat); + LL_I2L(oneMillion, PR_USEC_PER_SEC); + LL_MUL(info->creationTime, oneMillion, dateInMicroSeconds); + + pb.hFileInfo.ioFlMdDat -= gJanuaryFirst1970Seconds; + LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlMdDat); + LL_MUL(info->modifyTime, oneMillion, dateInMicroSeconds); + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_Stat(const char *path, struct stat *buf) +{ + OSErr err; + char *macFileName = NULL; + + err = ConvertUnixPathToMacPath(path, &macFileName); + if (err != noErr) + goto ErrorExit; + + err = stat(macFileName, buf); + if (err != noErr) + goto ErrorExit; + + PR_DELETE(macFileName); + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRStatus _MD_LockFile(PRInt32 fd) +{ + OSErr err; + FCBPBRec fcbpb; + HFileParam fpb; + Str255 pascalName; + + fcbpb.ioNamePtr = pascalName; + fcbpb.ioVRefNum = 0; + fcbpb.ioRefNum = fd; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) + goto ErrorExit; + + fpb.ioCompletion = NULL; + fpb.ioNamePtr = pascalName; + fpb.ioVRefNum = fcbpb.ioFCBVRefNum; + fpb.ioDirID = fcbpb.ioFCBParID; + + err = PBHSetFLockSync((HParmBlkPtr)&fpb); + if (err != noErr) + goto ErrorExit; + + return PR_SUCCESS; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return PR_FAILURE; +} + +PRStatus _MD_TLockFile(PRInt32 fd) +{ + return (_MD_LockFile(fd)); +} + +PRStatus _MD_UnlockFile(PRInt32 fd) +{ + OSErr err; + FCBPBRec fcbpb; + HFileParam fpb; + Str255 pascalName; + + fcbpb.ioNamePtr = pascalName; + fcbpb.ioVRefNum = 0; + fcbpb.ioRefNum = fd; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) + goto ErrorExit; + + fpb.ioCompletion = NULL; + fpb.ioNamePtr = pascalName; + fpb.ioVRefNum = fcbpb.ioFCBVRefNum; + fpb.ioDirID = fcbpb.ioFCBParID; + + err = PBHRstFLockSync((HParmBlkPtr)&fpb); + if (err != noErr) + goto ErrorExit; + + return PR_SUCCESS; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return PR_FAILURE; +} + +void SetLogFileTypeCreator(const char *logFile) +{ + HParamBlockRec pb; + OSErr err; + Str31 pName; + + PStrFromCStr(logFile, pName); + pb.fileParam.ioCompletion = nil; + pb.fileParam.ioNamePtr = pName; + pb.fileParam.ioVRefNum = 0; + pb.fileParam.ioFDirIndex = 0; + pb.fileParam.ioDirID = 0; + err = PBHGetFInfoSync(&pb); + PR_ASSERT(err == noErr); + + pb.fileParam.ioDirID = 0; + pb.fileParam.ioFlFndrInfo.fdType = 'TEXT'; + pb.fileParam.ioFlFndrInfo.fdCreator = 'ttxt'; + err = PBHSetFInfoSync(&pb); + PR_ASSERT(err == noErr); +} + +#if DEVELOPER_DEBUG +PR_IMPLEMENT (void) +SetupMacPrintfLog(char *logFile) +{ + /* + * We do _PR_InitLog() twice. The first to force the implicit initialization which + * will set logging to highest levels in _MD_EARLY_INIT. Then, change the env variable + * to disable kernel logging and call _PR_InitLog() again to make it effective. Since + * we are using logging to log test program output, we disable kernel logging to avoid + * all Kernel logging output. + */ +#ifdef PR_INTERNAL_LOGGING + _PR_InitLog(); + _MD_PutEnv("NSPR_LOG_MODULES=clock:0,cmon:0,io:0,mon:0,linker:0,cvar:0,sched:0,thread:0"); + _PR_InitLog(); +#endif + PR_ASSERT(PR_SetLogFile(logFile) == PR_TRUE); + + SetLogFileTypeCreator(logFile); +} +#endif + + +/* +********************** Old name related stuff that is unchanged. ********************** +*/ + +#if !defined(MAC_NSPR_STANDALONE) + +short GetVolumeRefNumFromName(const char *cTgtVolName) +{ + OSErr err; + Str32 pVolName; + char *cVolName = NULL; + HParamBlockRec hPB; + short refNum = 0; + + hPB.volumeParam.ioVolIndex = 0; + hPB.volumeParam.ioNamePtr = pVolName; + do { + hPB.volumeParam.ioVolIndex++; + err = PBHGetVInfoSync(&hPB); + CStrFromPStr(pVolName, &cVolName); + if (strcmp(cTgtVolName, cVolName) == 0) { + refNum = hPB.volumeParam.ioVRefNum; + PR_DELETE(cVolName); + break; + } + PR_DELETE(cVolName); + } while (err == noErr); + + return refNum; +} + +static OSErr CreateMacPathFromUnixPath(const char *unixPath, char **macPath) +{ + // Given a Unix style path with '/' directory separators, this allocates + // a path with Mac style directory separators in the path. + // + // It does not do any special directory translation; use ConvertUnixPathToMacPath + // for that. + + const char *src; + char *tgt; + OSErr err = noErr; + + PR_ASSERT(unixPath != nil); + if (nil == unixPath) { + err = paramErr; + goto exit; + } + + // If unixPath is a zero-length string, we copy ":" into + // macPath, so we need a minimum of two bytes to handle + // the case of ":". + *macPath = malloc(strlen(unixPath) + 2); // Will be enough extra space. + require_action (*macPath != NULL, exit, err = memFullErr;); + + src = unixPath; + tgt = *macPath; + + if (PL_strchr(src, PR_DIRECTORY_SEPARATOR) == src) // If weÕre dealing with an absolute + src++; // path, skip the separator + else + *(tgt++) = PR_PATH_SEPARATOR; + + if (PL_strstr(src, UNIX_THIS_DIRECTORY_STR) == src) // If it starts with / + src += 2; // skip it. + + while (*src) + { // deal with the rest of the path + if (PL_strstr(src, UNIX_PARENT_DIRECTORY_STR) == src) { // Going up? + *(tgt++) = PR_PATH_SEPARATOR; // simply add an extra colon. + src +=3; + } + else if (*src == PR_DIRECTORY_SEPARATOR) { // Change the separator + *(tgt++) = PR_PATH_SEPARATOR; + src++; + } + else + *(tgt++) = *(src++); + } + + *tgt = NULL; // make sure itÕs null terminated. + +exit: + return err; +} + + +static ProcessInfoRec gNavigatorProcInfo; +static FSSpec gGutsFolder; +static FSSpec gNetscapeFolder; + +static OSErr SetupRequiredFSSpecs(void) +{ + OSErr err; + CInfoPBRec pb; + ProcessSerialNumber curPSN = {0, kCurrentProcess}; + + gNavigatorProcInfo.processInfoLength = sizeof(ProcessInfoRec); + gNavigatorProcInfo.processName = NULL; + gNavigatorProcInfo.processAppSpec = &gNetscapeFolder; + + err = GetProcessInformation (&curPSN, &gNavigatorProcInfo); + if (err != noErr) + goto ErrorExit; + + /* guts folder resides at the same place as the app file itself */ + gGutsFolder = gNetscapeFolder; + /* How else do we do this hack??? + * Should NSPR have a string resource for this ? + */ + GetIndString( gGutsFolder.name, 300, 34); + + /* + * vRefNum and parentDirID are now set up correctly for the app file itself. + * parentDirID is the Netscape Folder's ID. Then Find it's parent ID to + * set up the FSSpec and its own name. + */ + + pb.dirInfo.ioCompletion = NULL; + pb.dirInfo.ioNamePtr = gNetscapeFolder.name; + pb.dirInfo.ioVRefNum = gNetscapeFolder.vRefNum; + pb.dirInfo.ioFDirIndex = -1; + pb.dirInfo.ioDrDirID = gNetscapeFolder.parID; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + gNetscapeFolder.parID = pb.dirInfo.ioDrParID; + + return noErr; + +ErrorExit: + return err; +} + +static OSErr FindGutsFolder(FSSpec *foundSpec) +{ + OSErr err; + + if (gNavigatorProcInfo.processInfoLength == 0) { /* Uninitialized? */ + err = SetupRequiredFSSpecs(); + if (err != noErr) + goto ErrorExit; + } + + *foundSpec = gGutsFolder; + + return noErr; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + return err; +} + +static OSErr FindNetscapeFolder(FSSpec *foundSpec) +{ + OSErr err; + + if (gNavigatorProcInfo.processInfoLength == 0) { /* Uninitialized? */ + err = SetupRequiredFSSpecs(); + if (err != noErr) + goto ErrorExit; + } + + *foundSpec = gNetscapeFolder; + + return noErr; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + return err; +} + + +PR_IMPLEMENT (OSErr) +ConvertUnixPathToMacPath(const char *unixPath, char **macPath) +{ + OSErr err = noErr; + + // ******** HACK ALERT ******** + // + // Java really wants long file names (>31 chars). We truncate file names + // greater than 31 characters long. Truncation is from the middle. + // + // Convert UNIX style path names (with . and / separators) into a Macintosh + // style path (with :). + // + // There are also a couple of special paths that need to be dealt with + // by translating them to the appropriate Mac special folders. These include: + // + // /usr/tmp/file => {TempFolder}file + // + // The file conversions we need to do are as follows: + // + // file => file + // dir/file => :dir:file + // ./file => file + // ../file => ::file + // ../dir/file => ::dir:file + // /file => ::BootDrive:file + // /dir/file => ::BootDrive:dir:file + + + if (!strcmp(unixPath, ".")) + { + *macPath = malloc(sizeof(":")); + if (*macPath == NULL) + err = memFullErr; + (*macPath)[0] = ':'; + (*macPath)[1] = '\0'; + } + else + + if (*unixPath != PR_DIRECTORY_SEPARATOR) { // Not root relative, just convert it. + err = CreateMacPathFromUnixPath(unixPath, macPath); + } + + else { + // WeÕre root-relative. This is either a special Unix directory, or a + // full path (which weÕll support on the Mac since they might be generated). + // This is not condoning the use of full-paths on the Macintosh for file + // specification. + + FSSpec foundSpec; + short pathBufferSize; +#if DEBUG + char *temp; +#endif + int tempLen; + + // Are we dealing with the temp folder? + if ((strncmp(unixPath, "/usr/tmp", strlen("/usr/tmp")) == 0) || + ((strncmp(unixPath, "/tmp", strlen("/tmp")) == 0))) { + CInfoPBRec pb; + + unixPath = PL_strchr(unixPath, PR_DIRECTORY_SEPARATOR); + if (strncmp(unixPath, "/tmp", strlen("/tmp")) == 0) // skip past temp spec + unixPath += 5; + else + unixPath += 9; + + err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed + &foundSpec.vRefNum, &foundSpec.parID); + if (err == noErr) { + pb.dirInfo.ioCompletion = NULL; + pb.dirInfo.ioNamePtr = foundSpec.name; + pb.dirInfo.ioVRefNum = foundSpec.vRefNum; + pb.dirInfo.ioFDirIndex = -1; + pb.dirInfo.ioDrDirID = foundSpec.parID; + + err = PBGetCatInfoSync(&pb); + foundSpec.parID = pb.dirInfo.ioDrParID; + } + } + + else if (!strncmp(unixPath, "/usr/local/netscape/", (tempLen = strlen("/usr/local/netscape/")))) { + + unixPath += tempLen; + + if (!strncmp(unixPath, "RequiredGuts/", (tempLen = strlen("RequiredGuts/")))) + { + unixPath += tempLen; + err = FindGutsFolder(&foundSpec); + } + else if (!strncmp(unixPath, "bin/", (tempLen = strlen("bin/")))) + { + unixPath += tempLen; + err = FindNetscapeFolder(&foundSpec); + } + else if (*unixPath == '\0') + { + // it's /usr/local/netscape + err = FindGutsFolder(&foundSpec); + } + + } + + else { + // This is a root relative directory, weÕll just convert the whole thing. + err = CreateMacPathFromUnixPath(unixPath, macPath); + goto Exit_ConvertUnixPathToMacPath; + } + + + + // WeÕre dealing with a special folder + if (err == noErr) + { + Handle hPathStr; + // Get the path to the root-relative directory + err = FSpGetFullPath(&foundSpec, &pathBufferSize, &hPathStr); // NewHandle's hPathStr + + if (noErr == err) + { + // convert handle to c-string + // add one for NULL termination + // pathBufferSize is now one greater than the length of the string + pathBufferSize++; + + *macPath = (char*) malloc(sizeof(char) * pathBufferSize); + (*macPath)[pathBufferSize - 1] = '\0'; + BlockMoveData(*hPathStr, *macPath, pathBufferSize - 1); + + DisposeHandle(hPathStr); + } + } + + if (err == noErr) + { + UInt32 unixPathLeft; + UInt32 macPathLen; + + unixPathLeft = strlen(unixPath); + macPathLen = strlen(*macPath); + + + // copy over the remaining file name, converting + if (pathBufferSize - 1 < macPathLen + unixPathLeft) + { + // need to grow string + *macPath = realloc(*macPath, macPathLen + unixPathLeft + 1); + err = (*macPath == NULL ? memFullErr : noErr); + } + + if (err == noErr) + { + // carefully remove the '/''s out of the unix path. If we see an "escaped" / + // we will leave it in there, otherwise we take it out and replace it with a : + // we have to do this before we convert to a mac-path, so we can tell what is + // really a path separator and what is in the name of a file or directory + // Make sure that all of the /Õs are :Õs in the final pathname + // effectively we do a + // strcat(*macPath, unixPath); while replace all occurrences of / with : in unixPath + char* dp; + const char* sp; + + sp = unixPath; + dp = *macPath + macPathLen; + + for (;*sp != '\0'; sp++, dp++) + { + if (*sp == PR_DIRECTORY_SEPARATOR) + { + // if we can look at the previous character + if (sp > unixPath) + { + // check to see if previous character is an escape + if (sp[-1] == '\\') + { + // leave it in, and cycle + continue; + } + else + { + *dp = PR_PATH_SEPARATOR; + } + } + else + *dp = PR_PATH_SEPARATOR; + } + else + { + // just copy; + *dp = *sp; + } + } + + *dp = '\0'; // NULL terminate *macPath + } +#if DEBUG + // we used to check here, now we check above, we leave this in + // the debug build to make sure we didn't screw up + // Make sure that all of the /Õs are :Õs in the final pathname + for (temp = *macPath + strlen(*macPath) - strlen(unixPath); *temp != '\0'; temp++) { + + if (*temp == PR_DIRECTORY_SEPARATOR) + { + DebugStr("\pFound a slash"); + *temp = PR_PATH_SEPARATOR; + } + } +#endif + } + } + + +Exit_ConvertUnixPathToMacPath: + + return err; +} + +// Hey! Before you delete this "hack" you should look at how it's being +// used by sun-java/netscape/applet/appletStubs.c. +PR_IMPLEMENT (OSErr) +ConvertMacPathToUnixPath(const char *macPath, char **unixPath) +{ + // *** HACK *** + // Get minimal version working + + char *unixPathPtr; + + *unixPath = malloc(strlen(macPath) + 2); // Add one for the front slash, one for null + if (*unixPath == NULL) + return (memFullErr); + + unixPathPtr = *unixPath; + + *unixPathPtr++ = PR_DIRECTORY_SEPARATOR; + + do { + // Translate all colons to slashes + if (*macPath == PR_PATH_SEPARATOR) + *unixPathPtr = PR_DIRECTORY_SEPARATOR; + else + *unixPathPtr = *macPath; + + unixPathPtr++; + macPath++; + } while (*macPath != NULL); + + // Terminate the string + *unixPathPtr = '\0'; + + return (noErr); +} + +OSErr +ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec) +{ + char* macPath; + OSErr convertError; + int len; + + convertError = ConvertUnixPathToMacPath(unixPath, &macPath); + if (convertError != noErr) + return convertError; + + len = strlen(macPath); + + if (*macPath == PR_PATH_SEPARATOR) + { + if (len < sizeof(Str255)) + { + short vRefNum; + long dirID; + Str255 pascalMacPath; + + convertError = HGetVol(NULL, &vRefNum, &dirID); + if (convertError == noErr) + { + PStrFromCStr(macPath, pascalMacPath); + convertError = FSMakeFSSpec(vRefNum, dirID, pascalMacPath, fileSpec); + } + } + else + convertError = paramErr; + } + else + { + convertError = FSpLocationFromFullPath(len, macPath, fileSpec); + if (convertError == fnfErr) + { + CInfoPBRec pb; + Str255 pascalMacPath; + OSErr err; + + PStrFromCStr(macPath, pascalMacPath); + /* + FSpLocationFromFullPath does not work for directories unless there is + a ":" at the end. We will make sure of an existence of a directory. + If so, the returned fileSpec is valid from FSpLocationFromFullPath eventhough + it returned an error. + */ + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = 0; + pb.hFileInfo.ioDirID = 0; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err == noErr) + convertError = noErr; + } + } + + free(macPath); + + return (convertError); +} + + +FILE *_OS_FOPEN(const char *filename, const char *mode) +{ + OSErr err = noErr; + char *macFileName = NULL; + FILE *result; + + err = ConvertUnixPathToMacPath(filename, &macFileName); + if (err != noErr) + goto ErrorExit; + + result = fopen(macFileName, mode); + + PR_DELETE(macFileName); + + return result; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return NULL; +} + +#else + +short GetVolumeRefNumFromName(const char *cTgtVolName) +{ + OSErr err; + Str32 pVolName; + char *cVolName = NULL; + HParamBlockRec hPB; + short refNum = 0; + + hPB.volumeParam.ioVolIndex = 0; + hPB.volumeParam.ioNamePtr = pVolName; + do { + hPB.volumeParam.ioVolIndex++; + err = PBHGetVInfoSync(&hPB); + CStrFromPStr(pVolName, &cVolName); + if (strcmp(cTgtVolName, cVolName) == 0) { + refNum = hPB.volumeParam.ioVRefNum; + PR_DELETE(cVolName); + break; + } + PR_DELETE(cVolName); + } while (err == noErr); + + return refNum; +} + + + +static OSErr GetFullPath(short vRefNum, long dirID, char **fullPath, int *strSize) +{ + Str255 pascalDirName; + char cDirName[256]; + char *tmpPath = NULL; // needed since sprintf isnÕt safe + CInfoPBRec myPB; + OSErr err = noErr; + + + // get the full path of the temp folder. + *strSize = 256; + *fullPath = NULL; + *fullPath = malloc(*strSize); // How big should this thing be? + require_action (*fullPath != NULL, errorExit, err = memFullErr;); + + tmpPath = malloc(*strSize); + require_action (tmpPath != NULL, errorExit, err = memFullErr;); + + strcpy(*fullPath, ""); // Clear C result + strcpy(tmpPath, ""); + pascalDirName[0] = 0; // Clear Pascal intermediate string + + myPB.dirInfo.ioNamePtr = &pascalDirName[0]; + myPB.dirInfo.ioVRefNum = vRefNum; + myPB.dirInfo.ioDrParID = dirID; + myPB.dirInfo.ioFDirIndex = -1; // Getting info about + + do { + myPB.dirInfo.ioDrDirID = myPB.dirInfo.ioDrParID; + + err = PBGetCatInfoSync(&myPB); + require(err == noErr, errorExit); + + // Move the name into C domain + memcpy(&cDirName, &pascalDirName, 256); + p2cstr((unsigned char *)&cDirName); // Changes in place! + + if ((strlen(cDirName) + strlen(*fullPath)) > *strSize) { + // We need to grow the string, do it in 256 byte chunks + (*strSize) += 256; + *fullPath = PR_REALLOC(*fullPath, *strSize); + require_action (*fullPath != NULL, errorExit, err = memFullErr;); + + tmpPath = PR_REALLOC(tmpPath, *strSize); + require_action (tmpPath != NULL, errorExit, err = memFullErr;); + } + sprintf(tmpPath, "%s:%s", cDirName, *fullPath); + strcpy(*fullPath, tmpPath); + } while (myPB.dirInfo.ioDrDirID != fsRtDirID); + + PR_DELETE(tmpPath); + + return noErr; + + +errorExit: + PR_DELETE(*fullPath); + PR_DELETE(tmpPath); + + return err; + +} + +static OSErr CreateMacPathFromUnixPath(const char *unixPath, char **macPath) +{ + // Given a Unix style path with '/' directory separators, this allocates + // a path with Mac style directory separators in the path. + // + // It does not do any special directory translation; use ConvertUnixPathToMacPath + // for that. + + const char *src; + char *tgt; + OSErr err = noErr; + + PR_ASSERT(unixPath != nil); + if (nil == unixPath) { + err = paramErr; + goto exit; + } + + // If unixPath is a zero-length string, we copy ":" into + // macPath, so we need a minimum of two bytes to handle + // the case of ":". + *macPath = malloc(strlen(unixPath) + 2); // Will be enough extra space. + require_action (*macPath != NULL, exit, err = memFullErr;); + + src = unixPath; + tgt = *macPath; + + if (PL_strchr(src, PR_DIRECTORY_SEPARATOR) == src) // If weÕre dealing with an absolute + src++; // path, skip the separator + else + *(tgt++) = PR_PATH_SEPARATOR; + + if (PL_strstr(src, UNIX_THIS_DIRECTORY_STR) == src) // If it starts with ./ + src += 2; // skip it. + + while (*src) + { // deal with the rest of the path + if (PL_strstr(src, UNIX_PARENT_DIRECTORY_STR) == src) { // Going up? + *(tgt++) = PR_PATH_SEPARATOR; // simply add an extra colon. + src +=3; + } + else if (*src == PR_DIRECTORY_SEPARATOR) { // Change the separator + *(tgt++) = PR_PATH_SEPARATOR; + src++; + } + else + *(tgt++) = *(src++); + } + + *tgt = NULL; // make sure itÕs null terminated. + +exit: + return err; +} + +static OSErr ConvertUnixPathToMacPath(const char *unixPath, char **macPath) +{ + OSErr err = noErr; + + + // + // Convert UNIX style path names (with . and / separators) into a Macintosh + // style path (with :). + // + // There are also a couple of special paths that need to be dealt with + // by translating them to the appropriate Mac special folders. These include: + // + // /usr/tmp/file => {TempFolder}file + // + // The file conversions we need to do are as follows: + // + // file => file + // dir/file => :dir:file + // ./file => file + // ../file => ::file + // ../dir/file => ::dir:file + // /file => ::BootDrive:file + // /dir/file => ::BootDrive:dir:file + + + if (*unixPath != PR_DIRECTORY_SEPARATOR) { // Not root relative, just convert it. + err = CreateMacPathFromUnixPath(unixPath, macPath); + } + + else { + // WeÕre root-relative. This is either a special Unix directory, or a + // full path (which weÕll support on the Mac since they might be generated). + // This is not condoning the use of full-paths on the Macintosh for file + // specification. + + short foundVRefNum; + long foundDirID; + int pathBufferSize; + char *temp; + char isNetscapeDir = false; + + // Are we dealing with the temp folder? + if (strncmp(unixPath, "/usr/tmp", strlen("/usr/tmp")) == 0){ + unixPath += 8; + if (*unixPath == PR_DIRECTORY_SEPARATOR) + unixPath++; // Skip the slash + err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed + &foundVRefNum, &foundDirID); + } + + if (strncmp(unixPath, "/tmp", strlen("/tmp")) == 0) { + unixPath += 4; // Skip the slash + if (*unixPath == PR_DIRECTORY_SEPARATOR) + unixPath++; // Skip the slash + err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed + &foundVRefNum, &foundDirID); + } + + else if (strncmp(unixPath, "/usr", strlen("/usr")) == 0) { + + int usrNetscapePathLen; + + usrNetscapePathLen = strlen("/usr/local/netscape/"); + + if (strncmp(unixPath, "/usr/local/netscape/", usrNetscapePathLen) == 0) { + unixPath += usrNetscapePathLen; +// err = FindPreferencesFolder(&foundVRefNum, &foundDirID); + err = paramErr; + isNetscapeDir = true; + } + + else { + dprintf("Unable to translate Unix file path %s to Mac path\n", unixPath); + err = -1; + goto Exit_ConvertUnixPathToMacPath; + } + + } + + else { + // This is a root relative directory, weÕll just convert the whole thing. + err = CreateMacPathFromUnixPath(unixPath, macPath); + goto Exit_ConvertUnixPathToMacPath; + } + + // WeÕre dealing with a special folder + if (err == noErr) + // Get the path to the root-relative directory + err = GetFullPath(foundVRefNum, foundDirID, macPath, &pathBufferSize); // mallocs macPath + + if (err == noErr){ + + // copy over the remaining file name, converting + if (pathBufferSize < (strlen(*macPath) + strlen(unixPath))) { + // need to grow string + *macPath = PR_REALLOC(*macPath, (strlen(*macPath) + strlen(unixPath) + + (isNetscapeDir ? strlen("Netscape Ä:") : 0))); + err = (*macPath == NULL ? memFullErr : noErr); + } + + if (isNetscapeDir) + strcat(*macPath, "Netscape Ä:"); + + if (err == noErr) + strcat(*macPath, unixPath); + + // Make sure that all of the /Õs are :Õs in the final pathname + + for (temp = *macPath + strlen(*macPath) - strlen(unixPath); *temp != '\0'; temp++) { + if (*temp == PR_DIRECTORY_SEPARATOR) + *temp = PR_PATH_SEPARATOR; + } + + } + } + + +Exit_ConvertUnixPathToMacPath: + + return err; +} + +OSErr +ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec) +{ + char* macPath; + OSErr convertError; + int len; + + convertError = ConvertUnixPathToMacPath(unixPath, &macPath); + if (convertError != noErr) + return convertError; + + len = strlen(macPath); + + if (*macPath == PR_PATH_SEPARATOR) + { + if (len < sizeof(Str255)) + { + short vRefNum; + long dirID; + Str255 pascalMacPath; + + convertError = HGetVol(NULL, &vRefNum, &dirID); + if (convertError == noErr) + { + PStrFromCStr(macPath, pascalMacPath); + convertError = FSMakeFSSpec(vRefNum, dirID, pascalMacPath, fileSpec); + } + } + else + convertError = paramErr; + } + else + { + convertError = FSpLocationFromFullPath(len, macPath, fileSpec); + } + + free(macPath); + + return (convertError); +} + + +#endif + +/* + ********************************************************************** + * + * Memory-mapped files are not implementable on the Mac. + * + ********************************************************************** + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ +#pragma unused (fmap, size) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRInt32 _MD_GetMemMapAlignment(void) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +void * _MD_MemMap( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len) +{ +#pragma unused (fmap, offset, len) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ +#pragma unused (addr, len) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ +#pragma unused (fmap) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} diff --git a/nsprpub/pr/src/md/mac/macio.h b/nsprpub/pr/src/md/mac/macio.h new file mode 100644 index 00000000000..06b85a9a272 --- /dev/null +++ b/nsprpub/pr/src/md/mac/macio.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef macio_h__ +#define macio_h__ + + +PR_BEGIN_EXTERN_C + +OSErr ConvertUnixPathToMacPath(const char *, char **); +OSErr ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec); + +PR_END_EXTERN_C + + +#endif /* macio_h__ */ + diff --git a/nsprpub/pr/src/md/mac/macrng.c b/nsprpub/pr/src/md/mac/macrng.c new file mode 100644 index 00000000000..c869cc3d1e3 --- /dev/null +++ b/nsprpub/pr/src/md/mac/macrng.c @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* XXX are all these headers required for a call to TickCount()? */ +#include +#include +#include +#include +#include +#include +#include "primpl.h" + +extern PRSize _PR_MD_GetRandomNoise( buf, size ) +{ + uint32 c = TickCount(); + return _pr_CopyLowBits((void *)buf, size, &c, sizeof(c)); +} diff --git a/nsprpub/pr/src/md/mac/macsocket.h b/nsprpub/pr/src/md/mac/macsocket.h new file mode 100644 index 00000000000..7e99faf2875 --- /dev/null +++ b/nsprpub/pr/src/md/mac/macsocket.h @@ -0,0 +1,238 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef macksocket_h___ +#define macksocket_h___ + +// macsock.h +// Interface visible to xp code +// C socket type definitions and routines +// from sys/socket.h +#include +#include // All the internet typedefs +#include // For timeval +/* + * sleep and delay conflict with the same in unistd.h from Metrowerks. OT + * defines them as + * + * extern pascal void OTDelay(UInt32 seconds); + * extern pascal void OTIdle(void); + * + * #define sleep(x) OTDelay(x) + * #define delay(x) OTDelay(x) + */ + +#undef sleep +#undef delay + +#pragma once + +#include "prio.h" + +struct sockaddr { + unsigned char sa_len; /* total length */ + unsigned char sa_family; /* address family */ + char sa_data[14]; /* actually longer; address value */ +}; + +// from netinet/in.h +struct in_addr { + unsigned long s_addr; +}; + +struct sockaddr_in { + unsigned char sin_len; + unsigned char sin_family; // AF_INET + unsigned short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatiblity */ +}; + +// Necessary network defines, found by grepping unix headers when XP code would not compile +#define FIONBIO 1 +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define IPPROTO_TCP INET_TCP // Default TCP protocol +#define IPPROTO_UDP INET_UDP // Default UDP protocol +#define INADDR_ANY kOTAnyInetAddress +#define SOL_SOCKET XTI_GENERIC // Any type of socket +#define SO_REUSEADDR IP_REUSEADDR +#define SO_BROADCAST IP_BROADCAST +#define MSG_PEEK 0x2 // Just look at a message waiting, donÕt actually read it. + +typedef unsigned long u_long; + +/* ldap.h has its own definition of fd_set */ +/* select support */ +#if !defined(FD_SET) +#define NBBY 8 +typedef long fd_mask; +#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ + +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif +#define FD_SETSIZE 64 +typedef struct fd_set{ + fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; +} fd_set; + +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p) memset (p, 0, sizeof(*(p))) +#endif /* !FD_SET */ + + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned long inet_addr(const char *cp); +extern char *inet_ntoa(struct in_addr in); + +inline unsigned long htonl(unsigned long hostlong) {return hostlong;} +inline unsigned long ntohl(unsigned long netlong) {return netlong;} +inline unsigned short ntohs(unsigned short netshort) {return netshort;} +inline unsigned short htons(unsigned short hostshort) {return hostshort;} + + +// UNIX look-alike routines +// They make sure that the arguments passed in are valid, and then +// +extern struct hostent *macsock_gethostbyaddr(const void *addr, int addrlen, int type); + +extern int macsock_socket(int domain, int type, int protocol); +extern int macsock_ioctl(int sID, unsigned int request, void *value); +extern int macsock_connect(int sID, struct sockaddr *name, int namelen); +extern int macsock_write(int sID, const void *buffer, unsigned buflen); +extern int macsock_read(int sID, void *buf, unsigned nbyte); +extern int macsock_close(int sID); + +extern int macsock_accept(int sID, struct sockaddr *addr, int *addrlen); +extern int macsock_bind(int sID, const struct sockaddr *name, int namelen); +extern int macsock_listen(int sID, int backlog); + +extern int macsock_shutdown(int sID, int how); +extern int macsock_getpeername(int sID, struct sockaddr *name, int *namelen); +extern int macsock_getsockname(int sID, struct sockaddr *name, int *namelen); +extern int macsock_getsockopt(int sID, int level, int optname, void *optval,int *optlen); +extern int macsock_setsockopt(int sID, int level, int optname, const void *optval,int optlen); +extern int macsock_socketavailable(int sID, size_t *bytesAvailable); +extern int macsock_dup(int sID); + +extern int macsock_send(int sID, const void *msg, int len, int flags); +extern int macsock_sendto(int sID, const void *msg, int len, int flags, struct sockaddr *toAddr, int toLen); +extern int macsock_recvfrom(int sID, void *buf, int len, int flags, struct sockaddr *from, int *fromLen); +extern int macsock_recv(int sID, void *buf, int len, int flags); + +extern int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); + + +#define macsock_gethostbyaddr PR_GetHostByAddr +#define macsock_socket PR_Socket +#define macsock_connect PR_Connect +#define macsock_write PR_Write +#define macsock_read PR_Read +#define macsock_close PR_Close +#define macsock_accept PR_Accept +#define macsock_bind PR_Bind +#define macsock_listen PR_Listen +#define macsock_shutdown PR_Shutdown +#define macsock_getpeername PR_GetPeerName +#define macsock_getsockname PR_GetSockName +#define macsock_socketavailable PR_SocketAvailable +#define macsock_send PR_Send +#define macsock_sendto PR_SendTo +#define macsock_recvfrom PR_RecvFrom +#define macsock_recv PR_Recv + +#ifdef __cplusplus +} +#endif +//extern int errno; + +/* +macsock_sendmsg +macsock_readv +macsock_writev +*/ + +/* New definitions that are not defined in macsock.h in macsock library */ +struct protoent { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + int p_proto; /* protocol # */ +}; + +extern struct protoent *getprotobyname(const char * name); +extern struct protoent *getprotobynumber(int number); + +extern int gethostname (char *name, int namelen); +extern struct hostent *gethostbyname(const char * name); +extern struct hostent *gethostbyaddr(const void *addr, int addrlen, int type); + +#define INADDR_LOOPBACK 0x7F000001 + +#define SO_KEEPALIVE TCP_KEEPALIVE +#define SO_RCVBUF XTI_RCVBUF +#define SO_SNDBUF XTI_SNDBUF +#define SO_LINGER XTI_LINGER /* linger on close if data present */ + +#define IPPROTO_IP INET_IP + +/* Get/Set sock opt until fixed in NSPR 2.0 */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time */ +}; + +struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + +#endif /* macksocket_h___ */ diff --git a/nsprpub/pr/src/md/mac/macsockotpt.c b/nsprpub/pr/src/md/mac/macsockotpt.c new file mode 100644 index 00000000000..b357eea6740 --- /dev/null +++ b/nsprpub/pr/src/md/mac/macsockotpt.c @@ -0,0 +1,2321 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* This turns on UNIX style errors in OT 1.1 headers */ +#define OTUNIXERRORS 1 + +#include + +#include +#include +#include +#include + +#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresentMask +#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresentMask + +#include // All the internet typedefs + +#if (UNIVERSAL_INTERFACES_VERSION >= 0x0330) +// for some reason Apple removed this typedef. +typedef struct OTConfiguration OTConfiguration; +#endif + +#include "primpl.h" + +typedef enum SndRcvOpCode { + kSTREAM_SEND, + kSTREAM_RECEIVE, + kDGRAM_SEND, + kDGRAM_RECEIVE +} SndRcvOpCode; + +static struct { + PRLock * lock; + InetSvcRef serviceRef; + PRThread * thread; + void * cookie; +} dnsContext; + + +static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie); +static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie); +static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie); + +static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady); + +void +WakeUpNotifiedThread(PRThread *thread, OTResult result); + +extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout); +extern void DoneWaitingOnThisThread(PRThread *thread); + +#if TARGET_CARBON +OTClientContextPtr clientContext = NULL; + +#define INIT_OPEN_TRANSPORT() InitOpenTransportInContext(kInitOTForExtensionMask, &clientContext) +#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServicesInContext(config, flags, err, clientContext) +#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpointInContext(config, flags, info, err, clientContext) + +#else + +#define INIT_OPEN_TRANSPORT() InitOpenTransport() +#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServices(config, flags, err) +#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpoint(config, flags, info, err) +#endif /* TARGET_CARBON */ + +static OTNotifyUPP DNSNotifierRoutineUPP; +static OTNotifyUPP NotifierRoutineUPP; +static OTNotifyUPP RawEndpointNotifierRoutineUPP; + +void _MD_InitNetAccess() +{ + OSErr err; + OSStatus errOT; + PRBool hasOTTCPIP = PR_FALSE; + PRBool hasOT = PR_FALSE; + long gestaltResult; + + 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); + + DNSNotifierRoutineUPP = NewOTNotifyUPP(DNSNotifierRoutine); + NotifierRoutineUPP = NewOTNotifyUPP(NotifierRoutine); + RawEndpointNotifierRoutineUPP = NewOTNotifyUPP(RawEndpointNotifierRoutine); + + errOT = INIT_OPEN_TRANSPORT(); + PR_ASSERT(err == kOTNoError); + + dnsContext.serviceRef = NULL; + dnsContext.lock = PR_NewLock(); + PR_ASSERT(dnsContext.lock != NULL); + + dnsContext.thread = _PR_MD_CURRENT_THREAD(); + dnsContext.cookie = NULL; + +/* XXX Does not handle absence of open tpt and tcp yet! */ +} + +static void _MD_FinishInitNetAccess() +{ + OSStatus errOT; + + if (dnsContext.serviceRef) + return; + + dnsContext.serviceRef = OT_OPEN_INTERNET_SERVICES(kDefaultInternetServicesPath, NULL, &errOT); + if (errOT != kOTNoError) { + dnsContext.serviceRef = NULL; + return; /* no network -- oh well */ + } + + PR_ASSERT((dnsContext.serviceRef != NULL) && (errOT == kOTNoError)); + + /* Install notify function for DNR Address To String completion */ + errOT = OTInstallNotifier(dnsContext.serviceRef, DNSNotifierRoutineUPP, &dnsContext); + PR_ASSERT(errOT == kOTNoError); + + /* Put us into async mode */ + errOT = OTSetAsynchronous(dnsContext.serviceRef); + PR_ASSERT(errOT == kOTNoError); +} + + +static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode otEvent, OTResult result, void * cookie) +{ +#pragma unused(contextPtr) + _PRCPU * cpu = _PR_MD_CURRENT_CPU(); + OSStatus errOT; + + dnsContext.thread->md.osErrCode = result; + dnsContext.cookie = cookie; + + switch (otEvent) { + case T_DNRSTRINGTOADDRCOMPLETE: + if (_PR_MD_GET_INTSOFF()) { + dnsContext.thread->md.missedIONotify = PR_TRUE; + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + } else { + DoneWaitingOnThisThread(dnsContext.thread); + } + break; + + case kOTProviderWillClose: + errOT = OTSetSynchronous(dnsContext.serviceRef); + // fall through to kOTProviderIsClosed case + + case kOTProviderIsClosed: + errOT = OTCloseProvider((ProviderRef)dnsContext.serviceRef); + dnsContext.serviceRef = nil; + + if (_PR_MD_GET_INTSOFF()) { + dnsContext.thread->md.missedIONotify = PR_TRUE; + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + } else { + DoneWaitingOnThisThread(dnsContext.thread); + } + break; + + default: // or else we don't handle the event + PR_ASSERT(otEvent==NULL); + + } + // or else we don't handle the event + + SignalIdleSemaphore(); +} + + +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_SetError(PR_UNKNOWN_ERROR, err); + break; + } + } +} + +static void PrepareForAsyncCompletion(PRThread * thread, PRInt32 osfd) +{ + thread->io_pending = PR_TRUE; + thread->io_fd = osfd; + thread->md.osErrCode = noErr; +} + + +void +WakeUpNotifiedThread(PRThread *thread, OTResult result) +{ + _PRCPU * cpu = _PR_MD_CURRENT_CPU(); + + if (thread) { + thread->md.osErrCode = result; + if (_PR_MD_GET_INTSOFF()) { + thread->md.missedIONotify = PR_TRUE; + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + } else { + DoneWaitingOnThisThread(thread); + } + } + + SignalIdleSemaphore(); +} + +// Notification routine +// Async callback routine. +// A5 is OK. Cannot allocate memory here +// Ref: http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-100.html +// +static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie) +{ + PRFilePrivate *secret = (PRFilePrivate *) contextPtr; + _MDFileDesc * md = &(secret->md); + EndpointRef endpoint = (EndpointRef)secret->md.osfd; + PRThread * readThread = NULL; // also used for 'misc' + PRThread * writeThread = NULL; + OSStatus err; + OTResult resultOT; + TDiscon discon; + + switch (code) + { +// OTLook Events - + case T_LISTEN: // A connection request is available + // If md->doListen is true, then PR_Listen has been + // called on this endpoint; therefore, we're ready to + // accept connections. But we'll do that with PR_Accept + // (which calls OTListen, OTAccept, etc) instead of + // doing it here. + if (md->doListen) { + readThread = secret->md.misc.thread; + secret->md.misc.thread = NULL; + secret->md.misc.cookie = cookie; + break; + } else { + // Reject the connection, we're not listening + OTSndDisconnect(endpoint, NULL); + } + break; + + case T_CONNECT: // Confirmation of a connect request + // cookie = sndCall parameter from OTConnect() + err = OTRcvConnect(endpoint, NULL); + PR_ASSERT(err == kOTNoError); + + // wake up waiting thread, if any. + writeThread = secret->md.write.thread; + secret->md.write.thread = NULL; + secret->md.write.cookie = cookie; + break; + + case T_DATA: // Standard data is available + // Mark this socket as readable. + secret->md.readReady = PR_TRUE; + + // wake up waiting thread, if any + readThread = secret->md.read.thread; + secret->md.read.thread = NULL; + secret->md.read.cookie = cookie; + break; + + case T_EXDATA: // Expedited data is available + PR_ASSERT(!"T_EXDATA Not implemented"); + return; + + case T_DISCONNECT: // A disconnect is available + discon.udata.len = 0; + err = OTRcvDisconnect(endpoint, &discon); + PR_ASSERT(err == kOTNoError); + secret->md.exceptReady = PR_TRUE; // XXX Check this + + md->disconnectError = discon.reason; // save for _MD_mac_get_nonblocking_connect_error + + // wake up waiting threads, if any + result = -3199 - discon.reason; // obtain the negative error code + if ((readThread = secret->md.read.thread) != NULL) { + secret->md.read.thread = NULL; + secret->md.read.cookie = cookie; + } + + if ((writeThread = secret->md.write.thread) != NULL) { + secret->md.write.thread = NULL; + secret->md.write.cookie = cookie; + } + break; + + case T_ERROR: // obsolete/unused in library + PR_ASSERT(!"T_ERROR Not implemented"); + return; + + case T_UDERR: // UDP Send error; clear the error + (void) OTRcvUDErr((EndpointRef) cookie, NULL); + break; + + case T_ORDREL: // An orderly release is available + err = OTRcvOrderlyDisconnect(endpoint); + PR_ASSERT(err == kOTNoError); + secret->md.readReady = PR_TRUE; // mark readable (to emulate bsd sockets) + // remember connection is closed, so we can return 0 on read or receive + secret->md.orderlyDisconnect = PR_TRUE; + + readThread = secret->md.read.thread; + secret->md.read.thread = NULL; + secret->md.read.cookie = cookie; + break; + + case T_GODATA: // Flow control lifted on standard data + secret->md.writeReady = PR_TRUE; + resultOT = OTLook(endpoint); // clear T_GODATA event + PR_ASSERT(resultOT == T_GODATA); + + // wake up waiting thread, if any + writeThread = secret->md.write.thread; + secret->md.write.thread = NULL; + secret->md.write.cookie = cookie; + break; + + case T_GOEXDATA: // Flow control lifted on expedited data + PR_ASSERT(!"T_GOEXDATA Not implemented"); + return; + + case T_REQUEST: // An Incoming request is available + PR_ASSERT(!"T_REQUEST Not implemented"); + return; + + case T_REPLY: // An Incoming reply is available + PR_ASSERT(!"T_REPLY Not implemented"); + return; + + case T_PASSCON: // State is now T_DATAXFER + // OTAccept() complete, receiving endpoint in T_DATAXFER state + // cookie = OTAccept() resRef parameter + break; + + case T_RESET: // Protocol has been reset + PR_ASSERT(!"T_RESET Not implemented"); + return; + +// Async Completion Events + case T_BINDCOMPLETE: + case T_UNBINDCOMPLETE: + case T_ACCEPTCOMPLETE: + case T_OPTMGMTCOMPLETE: + case T_GETPROTADDRCOMPLETE: + readThread = secret->md.misc.thread; + secret->md.misc.thread = NULL; + secret->md.misc.cookie = cookie; + break; + +// case T_OPENCOMPLETE: // we open endpoints in synchronous mode +// case T_REPLYCOMPLETE: +// case T_DISCONNECTCOMPLETE: // we don't call OTSndDisconnect() +// case T_RESOLVEADDRCOMPLETE: +// case T_GETINFOCOMPLETE: +// case T_SYNCCOMPLETE: +// case T_MEMORYRELEASED: // only if OTAckSends() called on endpoint +// case T_REGNAMECOMPLETE: +// case T_DELNAMECOMPLETE: +// case T_LKUPNAMECOMPLETE: +// case T_LKUPNAMERESULT: + // OpenTptInternet.h +// case T_DNRSTRINGTOADDRCOMPLETE: // DNS is handled by dnsContext in DNSNotifierRoutine() +// case T_DNRADDRTONAMECOMPLETE: +// case T_DNRSYSINFOCOMPLETE: +// case T_DNRMAILEXCHANGECOMPLETE: +// case T_DNRQUERYCOMPLETE: + default: + // we should probably have a bit more sophisticated handling of kOTSystemSleep, etc. + // PR_ASSERT(code != 0); + return; + } + + if (readThread) + WakeUpNotifiedThread(readThread, result); + + if (writeThread && (writeThread != readThread)) + WakeUpNotifiedThread(writeThread, result); +} + + +static OSErr CreateSocket(int type, EndpointRef *endpoint) +{ + OSStatus err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + char * configName; + OTConfiguration *config; + EndpointRef ep; + + // for now we just create the endpoint + // we'll make it asynchronous and give it a notifier routine in _MD_makenonblock() + + switch (type){ + case SOCK_STREAM: configName = kTCPName; break; + case SOCK_DGRAM: configName = kUDPName; break; + } + config = OTCreateConfiguration(configName); + ep = OT_OPEN_ENDPOINT(config, 0, NULL, &err); + if (err != kOTNoError) + goto ErrorExit; + + *endpoint = ep; + PR_ASSERT(*endpoint != NULL); + + return kOTNoError; + +ErrorExit: + return err; +} + + +// Errors returned: +// kOTXXXX - OT returned error +// EPROTONOSUPPORT - bad socket type/protocol +// 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; + + _MD_FinishInitNetAccess(); + + // 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); + return -1; +} + + +// Errors: +// EBADF -- bad socket id +// EFAULT -- bad address format +PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen) +{ + OSStatus err; + EndpointRef endpoint = (EndpointRef) fd->secret->md.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; + } + +/* + * There seems to be a bug with OT related to OTBind failing with kOTNoAddressErr even though + * a proper legal address was supplied. This happens very rarely and just retrying the + * operation after a certain time (less than 1 sec. does not work) seems to succeed. + */ + +TryAgain: + // setup our request + bindReq.addr.len = addrlen; + + bindReq.addr.maxlen = addrlen; + bindReq.addr.buf = (UInt8*) addr; + bindReq.qlen = 1; + + PR_Lock(fd->secret->md.miscLock); + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; + + err = OTBind(endpoint, &bindReq, NULL); + if (err != kOTNoError) { + me->io_pending = PR_FALSE; + PR_Unlock(fd->secret->md.miscLock); + goto ErrorExit; + } + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(fd->secret->md.miscLock); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + return kOTNoError; + +ErrorExit: + if ((err == kOTNoAddressErr) && (++retryCount <= 4)) { + unsigned long finalTicks; + + Delay(100,&finalTicks); + goto TryAgain; + } + macsock_map_error(err); + return -1; +} + + +// Errors: +// EBADF -- bad socket id +PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 osfd = fd->secret->md.osfd; + OSStatus err = 0; + EndpointRef endpoint = (EndpointRef) osfd; + TBind bindReq; + PRNetAddr addr; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ((fd == NULL) || (endpoint == NULL)) { + err = EBADF; + goto ErrorExit; + } + + if (backlog == 0) + backlog = 1; + + if (endpoint == NULL) { + err = EBADF; + goto ErrorExit; + } + + addr.inet.family = AF_INET; + 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; + + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; // tell notifier routine what to wake up + + err = OTGetProtAddress(endpoint, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; // tell notifier routine what to wake up + + err = OTUnbind(endpoint); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + /* tell the notifier func that we are interested in pending connections */ + fd->secret->md.doListen = PR_TRUE; + /* accept up to (backlog) pending connections at any one time */ + bindReq.qlen = backlog; + + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; // tell notifier routine what to wake up + + err = OTBind(endpoint, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + + err = me->md.osErrCode; + if (err != kOTNoError) + { + // If OTBind failed, we're really not ready to listen after all. + fd->secret->md.doListen = PR_FALSE; + goto ErrorExit; + } + + return kOTNoError; + +ErrorExit: + me->io_pending = PR_FALSE; // clear pending wait state if any + macsock_map_error(err); + return -1; +} + + +// Errors: +// EBADF -- bad socket id +PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + OSStatus err; + EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd; + TBind bindReq; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + if (addr == NULL) { + err = kEFAULTErr; + goto ErrorExit; + } + + bindReq.addr.len = *addrlen; + bindReq.addr.maxlen = *addrlen; + bindReq.addr.buf = (UInt8*) addr; + bindReq.qlen = 0; + + PR_Lock(fd->secret->md.miscLock); + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; + + err = OTGetProtAddress(endpoint, &bindReq, NULL); + if (err != kOTNoError) { + me->io_pending = PR_FALSE; + PR_Unlock(fd->secret->md.miscLock); + goto ErrorExit; + } + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(fd->secret->md.miscLock); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + *addrlen = PR_NETADDR_SIZE(addr); + return kOTNoError; + +ErrorExit: + macsock_map_error(err); + return -1; +} + + +PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +{ + OSStatus err; + EndpointRef endpoint = (EndpointRef) fd->secret->md.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; + + PR_Lock(fd->secret->md.miscLock); + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; + + err = OTOptionManagement(endpoint, &cmd, &cmd); + if (err != kOTNoError) { + me->io_pending = PR_FALSE; + PR_Unlock(fd->secret->md.miscLock); + goto ErrorExit; + } + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(fd->secret->md.miscLock); + + 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); + return PR_FAILURE; +} + + +PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +{ + OSStatus err; + EndpointRef endpoint = (EndpointRef) fd->secret->md.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; + } + + PR_Lock(fd->secret->md.miscLock); + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; + + err = OTOptionManagement(endpoint, &cmd, &cmd); + if (err != kOTNoError) { + me->io_pending = PR_FALSE; + PR_Unlock(fd->secret->md.miscLock); + goto ErrorExit; + } + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(fd->secret->md.miscLock); + + 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); + 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; + +ErrorExit: + macsock_map_error(err); + return -1; +} + + +typedef struct RawEndpointAndThread +{ + PRThread * thread; + EndpointRef endpoint; +} RawEndpointAndThread; + +// Notification routine for raw endpoints not yet attached to a PRFileDesc. +// Async callback routine. +// A5 is OK. Cannot allocate memory here +static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie) +{ + RawEndpointAndThread *endthr = (RawEndpointAndThread *) contextPtr; + PRThread * thread = endthr->thread; + EndpointRef * endpoint = endthr->endpoint; + _PRCPU * cpu = _PR_MD_CURRENT_CPU(); + OSStatus err; + OTResult resultOT; + + switch (code) + { +// OTLook Events - + case T_LISTEN: // A connection request is available + PR_ASSERT(!"T_EXDATA not implemented for raw endpoints"); + break; + + case T_CONNECT: // Confirmation of a connect request + // cookie = sndCall parameter from OTConnect() + err = OTRcvConnect(endpoint, NULL); + PR_ASSERT(err == kOTNoError); + + // wake up waiting thread + break; + + case T_DATA: // Standard data is available + break; + + case T_EXDATA: // Expedited data is available + PR_ASSERT(!"T_EXDATA Not implemented for raw endpoints"); + return; + + case T_DISCONNECT: // A disconnect is available + err = OTRcvDisconnect(endpoint, NULL); + PR_ASSERT(err == kOTNoError); + break; + + case T_ERROR: // obsolete/unused in library + PR_ASSERT(!"T_ERROR Not implemented for raw endpoints"); + return; + + case T_UDERR: // UDP Send error; clear the error + (void) OTRcvUDErr((EndpointRef) cookie, NULL); + break; + + case T_ORDREL: // An orderly release is available + err = OTRcvOrderlyDisconnect(endpoint); + PR_ASSERT(err == kOTNoError); + break; + + case T_GODATA: // Flow control lifted on standard data + resultOT = OTLook(endpoint); // clear T_GODATA event + PR_ASSERT(resultOT == T_GODATA); + + // wake up waiting thread, if any + break; + + case T_GOEXDATA: // Flow control lifted on expedited data + PR_ASSERT(!"T_GOEXDATA Not implemented"); + return; + + case T_REQUEST: // An Incoming request is available + PR_ASSERT(!"T_REQUEST Not implemented"); + return; + + case T_REPLY: // An Incoming reply is available + PR_ASSERT(!"T_REPLY Not implemented"); + return; + + case T_PASSCON: // State is now T_DATAXFER + // OTAccept() complete, receiving endpoint in T_DATAXFER state + // cookie = OTAccept() resRef parameter + break; + +// Async Completion Events + case T_BINDCOMPLETE: + case T_UNBINDCOMPLETE: + case T_ACCEPTCOMPLETE: + case T_OPTMGMTCOMPLETE: + case T_GETPROTADDRCOMPLETE: + break; + + // for other OT events, see NotifierRoutine above + default: + return; + } + + if (thread) { + thread->md.osErrCode = result; + if (_PR_MD_GET_INTSOFF()) { + thread->md.asyncNotifyPending = PR_TRUE; + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + } else { + DoneWaitingOnThisThread(thread); + } + } + + SignalIdleSemaphore(); +} + +PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + OSStatus err; + EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + TBind bindReq; + PRNetAddr bindAddr; + PRInt32 newosfd = -1; + TCall call; + PRNetAddr callAddr; + RawEndpointAndThread *endthr = NULL; + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + memset(&call, 0 , sizeof(call)); + + if (addr != NULL) { + call.addr.maxlen = *addrlen; + call.addr.len = *addrlen; + call.addr.buf = (UInt8*) addr; + } else { + call.addr.maxlen = sizeof(callAddr); + call.addr.len = sizeof(callAddr); + call.addr.buf = (UInt8*) &callAddr; + } + + do { + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; + + // Perform the listen. + err = OTListen (endpoint, &call); + if (err == kOTNoError) + break; // got the call information + else if ((!fd->secret->nonblocking) && (err == kOTNoDataErr)) { + WaitOnThisThread(me, timeout); + err = me->md.osErrCode; + if ((err != kOTNoError) && (err != kOTNoDataErr)) + goto ErrorExit; + // we can get kOTNoError here, but still need + // to loop back to call OTListen, in order + // to get call info for OTAccept + } else { + goto ErrorExit; // we're nonblocking, and/or we got an error + } + } + while(1); + + newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0); + if (newosfd == -1) + return -1; + + // Attach the raw endpoint handler to this endpoint for now. + endthr = (RawEndpointAndThread *) PR_Malloc(sizeof(RawEndpointAndThread)); + endthr->thread = me; + endthr->endpoint = (EndpointRef) newosfd; + + err = OTInstallNotifier((ProviderRef) newosfd, RawEndpointNotifierRoutineUPP, endthr); + PR_ASSERT(err == kOTNoError); + + err = OTSetAsynchronous((EndpointRef) newosfd); + PR_ASSERT(err == kOTNoError); + + // Bind to a local port; let the system assign it. + bindAddr.inet.family = AF_INET; + 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; + + PrepareForAsyncCompletion(me, newosfd); + err = OTBind((EndpointRef) newosfd, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, timeout); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + PrepareForAsyncCompletion(me, newosfd); + + err = OTAccept (endpoint, (EndpointRef) newosfd, &call); + if ((err != kOTNoError) && (err != kOTNoDataErr)) + goto ErrorExit; + + WaitOnThisThread(me, timeout); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + if (addrlen != NULL) + *addrlen = call.addr.len; + + // Remove the temporary notifier we installed to set up the new endpoint. + OTRemoveNotifier((EndpointRef) newosfd); + PR_Free(endthr); // free the temporary context we set up for this endpoint + + return newosfd; + +ErrorExit: + me->io_pending = PR_FALSE; // clear pending wait state if any + if (newosfd != -1) + _MD_closesocket(newosfd); + macsock_map_error(err); + return -1; +} + + +PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + OSStatus err; + EndpointRef endpoint = (EndpointRef) fd->secret->md.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.family = AF_INET; + 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; + + PR_Lock(fd->secret->md.miscLock); + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; + + err = OTBind(endpoint, &bindReq, NULL); + if (err != kOTNoError) { + me->io_pending = PR_FALSE; + PR_Unlock(fd->secret->md.miscLock); + goto ErrorExit; + } + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(fd->secret->md.miscLock); + + 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; + + if (!fd->secret->nonblocking) { + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + PR_ASSERT(fd->secret->md.write.thread == NULL); + fd->secret->md.write.thread = me; + } + + err = OTConnect (endpoint, &sndCall, NULL); + if (err == kOTNoError) { + PR_ASSERT(!"OTConnect returned kOTNoError in async mode!?!"); + } + if (fd->secret->nonblocking) { + if (err == kOTNoDataErr) + err = EINPROGRESS; + goto ErrorExit; + } else { + if (err != kOTNoError && err != kOTNoDataErr) { + me->io_pending = PR_FALSE; + goto ErrorExit; + } + } + + WaitOnThisThread(me, timeout); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + return kOTNoError; + +ErrorExit: + macsock_map_error(err); + return -1; +} + + +// Errors: +// EBADF -- bad socket id +// EFAULT -- bad buffer +static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout, SndRcvOpCode opCode) +{ + OSStatus err; + OTResult result; + EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 bytesLeft = amount; + + PR_ASSERT(flags == 0 || + (opCode == kSTREAM_RECEIVE && flags == PR_MSG_PEEK)); + PR_ASSERT(opCode == kSTREAM_SEND || opCode == kSTREAM_RECEIVE); + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + if (buf == NULL) { + err = kEFAULTErr; + goto ErrorExit; + } + + PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL : + fd->secret->md.read.thread == NULL); + + while (bytesLeft > 0) + { + Boolean disabledNotifications = OTEnterNotifier(endpoint); + + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + + if (opCode == kSTREAM_SEND) { + do { + fd->secret->md.write.thread = me; + fd->secret->md.writeReady = PR_FALSE; // expect the worst + result = OTSnd(endpoint, buf, bytesLeft, NULL); + fd->secret->md.writeReady = (result != kOTFlowErr); + if (fd->secret->nonblocking) // hope for the best + break; + else { + + // We drop through on anything other than a blocking write. + if (result != kOTFlowErr) + break; + + // Blocking write, but the pipe is full. Turn notifications on and + // wait for an event, hoping that it's a T_GODATA event. + if (disabledNotifications) { + OTLeaveNotifier(endpoint); + disabledNotifications = false; + } + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + result = me->md.osErrCode; + if (result != kOTNoError) // got interrupted, or some other error + break; + + // Prepare to loop back and try again + disabledNotifications = OTEnterNotifier(endpoint); + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + } + } + while(1); + } else { + do { + fd->secret->md.read.thread = me; + fd->secret->md.readReady = PR_FALSE; // expect the worst + result = OTRcv(endpoint, buf, bytesLeft, NULL); + if (fd->secret->nonblocking) { + fd->secret->md.readReady = (result != kOTNoDataErr); + break; + } else { + if (result != kOTNoDataErr) { + // If we successfully read a blocking socket, check for more data. + // According to IM:OT, we should be able to rely on OTCountDataBytes + // to tell us whether there is a nonzero amount of data pending. + size_t count; + OSErr tmpResult; + tmpResult = OTCountDataBytes(endpoint, &count); + fd->secret->md.readReady = ((tmpResult == kOTNoError) && (count > 0)); + break; + } + + // Blocking read, but no data available. Turn notifications on and + // wait for an event on this endpoint, and hope that we get a T_DATA event. + if (disabledNotifications) { + OTLeaveNotifier(endpoint); + disabledNotifications = false; + } + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + result = me->md.osErrCode; + if (result != kOTNoError) // interrupted thread, etc. + break; + + // Prepare to loop back and try again + disabledNotifications = OTEnterNotifier(endpoint); + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + } + } + // Retry read if we had to wait for data to show up. + while(1); + } + + me->io_pending = PR_FALSE; + + if (opCode == kSTREAM_SEND) + fd->secret->md.write.thread = NULL; + else + fd->secret->md.read.thread = NULL; + + // turn notifications back on + if (disabledNotifications) + OTLeaveNotifier(endpoint); + + if (result > 0) { + buf = (void *) ( (UInt32) buf + (UInt32)result ); + bytesLeft -= result; + if (opCode == kSTREAM_RECEIVE) { + amount = result; + goto NormalExit; + } + } else { + switch (result) { + case kOTLookErr: + PR_ASSERT(!"call to OTLook() required after all."); + break; + + case kOTFlowErr: + case kOTNoDataErr: + case kEAGAINErr: + case kEWOULDBLOCKErr: + if (fd->secret->nonblocking) { + + if (bytesLeft == amount) { // no data was sent + err = result; + goto ErrorExit; + } + + // some data was sent + amount -= bytesLeft; + goto NormalExit; + } + + WaitOnThisThread(me, timeout); + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + break; + + case kOTOutStateErr: // if provider already closed, fall through to handle error + if (fd->secret->md.orderlyDisconnect) { + amount = 0; + goto NormalExit; + } + // else fall through + default: + err = result; + goto ErrorExit; + } + } + } + +NormalExit: + PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL : + fd->secret->md.read.thread == NULL); + return amount; + +ErrorExit: + PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL : + fd->secret->md.read.thread == NULL); + 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)); +} + + +PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND)); +} + + +// Errors: +// EBADF -- bad socket id +// EFAULT -- bad buffer +static PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout, SndRcvOpCode opCode) +{ + OSStatus err; + EndpointRef endpoint = (EndpointRef) fd->secret->md.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) { + + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + + if (opCode == kDGRAM_SEND) { + fd->secret->md.write.thread = me; + fd->secret->md.writeReady = PR_FALSE; // expect the worst + err = OTSndUData(endpoint, &dgram); + if (err != kOTFlowErr) // hope for the best + fd->secret->md.writeReady = PR_TRUE; + } else { + fd->secret->md.read.thread = me; + fd->secret->md.readReady = PR_FALSE; // expect the worst + err = OTRcvUData(endpoint, &dgram, NULL); + if (err != kOTNoDataErr) // hope for the best + fd->secret->md.readReady = PR_TRUE; + } + + 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); + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + } + } + + if (opCode == kDGRAM_RECEIVE) + *addrlen = dgram.addr.len; + + return amount; + +ErrorExit: + macsock_map_error(err); + return -1; +} + + +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)); +} + + +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)); +} + + +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; + + (void) OTSndOrderlyDisconnect(endpoint); + err = OTCloseProvider(endpoint); + if (err != kOTNoError) + goto ErrorExit; + + return kOTNoError; + +ErrorExit: + macsock_map_error(err); + return -1; +} + + +PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +{ +#pragma unused (fd, iov, iov_size, timeout) + + PR_ASSERT(0); + _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr; + return -1; +} + +// OT endpoint states are documented here: +// http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-27.html#MARKER-9-65 +// +static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady) +{ + OTResult resultOT; + // hack to emulate BSD sockets; say that a socket that has disconnected + // is still readable. + size_t availableData = 1; + if (!fd->secret->md.orderlyDisconnect) + OTCountDataBytes((EndpointRef)fd->secret->md.osfd, &availableData); + + *readReady = fd->secret->md.readReady && (availableData > 0); + *exceptReady = fd->secret->md.exceptReady; + + resultOT = OTGetEndpointState((EndpointRef)fd->secret->md.osfd); + switch (resultOT) { + case T_IDLE: + case T_UNBND: + // the socket is not connected. Emulating BSD sockets, + // we mark it readable and writable. The next PR_Read + // or PR_Write will then fail. Usually, in this situation, + // fd->secret->md.exceptReady is also set, and returned if + // anyone is polling for it. + *readReady = PR_FALSE; + *writeReady = PR_FALSE; + break; + + case T_DATAXFER: // data transfer + *writeReady = fd->secret->md.writeReady; + break; + + case T_INREL: // incoming orderly release + *writeReady = fd->secret->md.writeReady; + break; + + case T_OUTCON: // outgoing connection pending + case T_INCON: // incoming connection pending + case T_OUTREL: // outgoing orderly release + default: + *writeReady = PR_FALSE; + } + + return *readReady || *writeReady || *exceptReady; +} + +// check to see if any of the poll descriptors have data available +// for reading or writing, by calling their poll methods (layered IO). +static PRInt32 CheckPollDescMethods(PRPollDesc *pds, PRIntn npds, PRInt16 *outReadFlags, PRInt16 *outWriteFlags) +{ + PRInt32 ready = 0; + PRPollDesc *pd, *epd; + PRInt16 *readFlag, *writeFlag; + + for (pd = pds, epd = pd + npds, readFlag = outReadFlags, writeFlag = outWriteFlags; + pd < epd; + pd++, readFlag++, writeFlag++) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + pd->out_flags = 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; + } + + *readFlag = in_flags_read; + *writeFlag = in_flags_write; + } + + return ready; +} + +// check to see if any of OT endpoints of the poll descriptors have data available +// for reading or writing. +static PRInt32 CheckPollDescEndpoints(PRPollDesc *pds, PRIntn npds, const PRInt16 *inReadFlags, const PRInt16 *inWriteFlags) +{ + PRInt32 ready = 0; + PRPollDesc *pd, *epd; + const PRInt16 *readFlag, *writeFlag; + + for (pd = pds, epd = pd + npds, readFlag = inReadFlags, writeFlag = inWriteFlags; + pd < epd; + pd++, readFlag++, writeFlag++) + { + PRFileDesc *bottomFD; + PRBool readReady, writeReady, exceptReady; + PRInt16 in_flags_read = *readFlag; + PRInt16 in_flags_write = *writeFlag; + + if (NULL == pd->fd || pd->in_flags == 0) continue; + + if ((pd->in_flags & ~pd->out_flags) == 0) { + ready++; + continue; + } + + bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + /* bottomFD can be NULL for pollable sockets */ + if (bottomFD) + { + if (_PR_FILEDESC_OPEN == bottomFD->secret->state) + { + if (GetState(bottomFD, &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 /* bad state */ + { + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + + return ready; +} + + +// see how many of the poll descriptors are ready +static PRInt32 CountReadyPollDescs(PRPollDesc *pds, PRIntn npds) +{ + PRInt32 ready = 0; + PRPollDesc *pd, *epd; + + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + if (pd->out_flags) + ready ++; + } + + return ready; +} + +// set or clear the poll thread on the poll descriptors +static void SetDescPollThread(PRPollDesc *pds, PRIntn npds, PRThread* thread) +{ + PRInt32 ready = 0; + PRPollDesc *pd, *epd; + + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + if (pd->fd) + { + PRFileDesc *bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state)) + { + if (pd->in_flags & PR_POLL_READ) { + PR_ASSERT(thread == NULL || bottomFD->secret->md.read.thread == NULL); + bottomFD->secret->md.read.thread = thread; + } + + if (pd->in_flags & PR_POLL_WRITE) { + // it's possible for the writing thread to be non-null during + // a non-blocking connect, so we assert that we're on + // the same thread, or the thread is null. + // Note that it's strictly possible for the connect and poll + // to be on different threads, so ideally we need to assert + // that if md.write.thread is non-null, there is a non-blocking + // connect in progress. + PR_ASSERT(thread == NULL || + (bottomFD->secret->md.write.thread == NULL || + bottomFD->secret->md.write.thread == thread)); + bottomFD->secret->md.write.thread = thread; + } + } + } + } +} + + +#define DESCRIPTOR_FLAGS_ARRAY_SIZE 32 + +PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRInt16 readFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE]; + PRInt16 writeFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE]; + + PRInt16 *readFlags = readFlagsArray; + PRInt16 *writeFlags = writeFlagsArray; + + PRInt16 *ioFlags = NULL; + + PRThread *thread = _PR_MD_CURRENT_THREAD(); + PRInt32 ready; + + if (npds > DESCRIPTOR_FLAGS_ARRAY_SIZE) + { + // we allocate a single double-size array. The first half is used + // for read flags, and the second half for write flags. + ioFlags = (PRInt16*)PR_Malloc(sizeof(PRInt16) * npds * 2); + if (!ioFlags) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + + readFlags = ioFlags; + writeFlags = &ioFlags[npds]; + } + + // we have to be outside the lock when calling this, since + // it can call arbitrary user code (including other socket + // entry points) + ready = CheckPollDescMethods(pds, npds, readFlags, writeFlags); + + if (!ready && timeout != PR_INTERVAL_NO_WAIT) { + intn is; + + + _PR_INTSOFF(is); + PR_Lock(thread->md.asyncIOLock); + PrepareForAsyncCompletion(thread, 0); + + SetDescPollThread(pds, npds, thread); + + (void)CheckPollDescEndpoints(pds, npds, readFlags, writeFlags); + + PR_Unlock(thread->md.asyncIOLock); + _PR_FAST_INTSON(is); + + ready = CountReadyPollDescs(pds, npds); + + if (ready == 0) { + WaitOnThisThread(thread, timeout); + + // since we may have been woken by a pollable event firing, + // we have to check both poll methods and endpoints. + (void)CheckPollDescMethods(pds, npds, readFlags, writeFlags); + ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags); + } + + thread->io_pending = PR_FALSE; + SetDescPollThread(pds, npds, NULL); + } + else { + ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags); + } + + if (readFlags != readFlagsArray) + PR_Free(ioFlags); + + return ready; +} + + +void _MD_initfiledesc(PRFileDesc *fd) +{ + // Allocate a PR_Lock to arbitrate miscellaneous OT calls for this endpoint between threads + // We presume that only one thread will be making Read calls (Recv/Accept) and that only + // one thread will be making Write calls (Send/Connect) on the endpoint at a time. + if (fd->methods->file_type == PR_DESC_SOCKET_TCP || + fd->methods->file_type == PR_DESC_SOCKET_UDP ) + { + PR_ASSERT(fd->secret->md.miscLock == NULL); + fd->secret->md.miscLock = PR_NewLock(); + PR_ASSERT(fd->secret->md.miscLock != NULL); + fd->secret->md.orderlyDisconnect = PR_FALSE; + fd->secret->md.readReady = PR_FALSE; // let's not presume we have data ready to read + fd->secret->md.writeReady = PR_TRUE; // let's presume we can write unless we hear otherwise + fd->secret->md.exceptReady = PR_FALSE; + } +} + + +void _MD_freefiledesc(PRFileDesc *fd) +{ + if (fd->secret->md.miscLock) + { + PR_ASSERT(fd->methods->file_type == PR_DESC_SOCKET_TCP || fd->methods->file_type == PR_DESC_SOCKET_UDP); + PR_DestroyLock(fd->secret->md.miscLock); + fd->secret->md.miscLock = NULL; + } else { + PR_ASSERT(fd->methods->file_type != PR_DESC_SOCKET_TCP && PR_DESC_SOCKET_TCP != PR_DESC_SOCKET_UDP); + } +} + +// _MD_makenonblock is also used for sockets meant to be used for blocking I/O, +// in order to install the notifier routine for async completion. +void _MD_makenonblock(PRFileDesc *fd) +{ + // We simulate non-blocking mode using async mode rather + // than put the endpoint in non-blocking mode. + // We need to install the PRFileDesc as the contextPtr for the NotifierRoutine, but it + // didn't exist at the time the endpoint was created. It does now though... + ProviderRef endpointRef = (ProviderRef)fd->secret->md.osfd; + OSStatus err; + + // Install fd->secret as the contextPtr for the Notifier function associated with this + // endpoint. We use this instead of the fd itself because: + // (a) in cases where you import I/O layers, the containing + // fd changes, but the secret structure does not; + // (b) the notifier func refers only to the secret data structure + // anyway. + err = OTInstallNotifier(endpointRef, NotifierRoutineUPP, fd->secret); + PR_ASSERT(err == kOTNoError); + + // Now that we have a NotifierRoutine installed, we can make the endpoint asynchronous + err = OTSetAsynchronous(endpointRef); + PR_ASSERT(err == kOTNoError); +} + + +void _MD_initfdinheritable(PRFileDesc *fd, PRBool imported) +{ + /* XXX this function needs to be implemented */ + fd->secret->inheritable = _PR_TRI_UNKNOWN; +} + + +void _MD_queryfdinheritable(PRFileDesc *fd) +{ + /* XXX this function needs to be implemented */ + PR_ASSERT(0); +} + + +PR_IMPLEMENT(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how) +{ +#pragma unused (fd, how) + +/* Just succeed silently!!! */ +return (0); +} + + +PR_IMPLEMENT(PRStatus) +_MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + EndpointRef ep = (EndpointRef) fd->secret->md.osfd; + InetAddress inetAddr; + TBind peerAddr; + OSErr err; + + if (*addrlen < sizeof(InetAddress)) { + + err = (OSErr) kEINVALErr; + goto ErrorExit; + } + + peerAddr.addr.maxlen = sizeof(InetAddress); + peerAddr.addr.len = 0; + peerAddr.addr.buf = (UInt8*) &inetAddr; + peerAddr.qlen = 0; + + PrepareForAsyncCompletion(me, fd->secret->md.osfd); + fd->secret->md.misc.thread = me; // tell notifier routine what to wake up + + err = OTGetProtAddress(ep, NULL, &peerAddr); + + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + + err = me->md.osErrCode; + if ((err == kOTNoError) && (peerAddr.addr.len < sizeof(InetAddress))) + err = kEBADFErr; // we don't understand the address we got + if (err != kOTNoError) + goto ErrorExit; + + // Translate the OT peer information into an NSPR address. + addr->inet.family = AF_INET; + addr->inet.port = (PRUint16) inetAddr.fPort; + addr->inet.ip = (PRUint32) inetAddr.fHost; + + *addrlen = PR_NETADDR_SIZE(addr); // return the amount of data obtained + return PR_SUCCESS; + +ErrorExit: + macsock_map_error(err); + return PR_FAILURE; +} + + +PR_IMPLEMENT(unsigned long) inet_addr(const char *cp) +{ + OSStatus err; + InetHost host; + + _MD_FinishInitNetAccess(); + + err = OTInetStringToHost((char*) cp, &host); + if (err != kOTNoError) + return -1; + + return host; +} + + +static char *sAliases[1] = {NULL}; +static struct hostent sHostEnt = {NULL, &sAliases[0], AF_INET, sizeof (long), NULL}; +static InetHostInfo sHostInfo; +static InetHost *sAddresses[kMaxHostAddrs+1]; + + +PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name) +{ + OSStatus err; + PRUint32 index; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + _MD_FinishInitNetAccess(); + + me->io_pending = PR_TRUE; + me->io_fd = NULL; + me->md.osErrCode = noErr; + + PR_Lock(dnsContext.lock); // so we can safely store our thread ptr in dnsContext + dnsContext.thread = me; // so we know what thread to wake up when OTInetStringToAddress completes + + err = OTInetStringToAddress(dnsContext.serviceRef, (char *)name, &sHostInfo); + if (err != kOTNoError) { + me->io_pending = PR_FALSE; + me->md.osErrCode = err; + goto ErrorExit; + } + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(dnsContext.lock); + + if (me->md.osErrCode != kOTNoError) + goto ErrorExit; + + sHostEnt.h_name = sHostInfo.name; + for (index=0; indexsecret->md.osfd; + OTResult resultOT = OTGetEndpointState(endpoint); + + switch (resultOT) { + case T_OUTCON: + macsock_map_error(EINPROGRESS); + return -1; + + case T_DATAXFER: + return 0; + + case T_IDLE: + macsock_map_error(fd->secret->md.disconnectError); + fd->secret->md.disconnectError = 0; + return -1; + + case T_INREL: + macsock_map_error(ENOTCONN); + return -1; + + default: + PR_ASSERT(0); + return -1; + } + + return -1; // not reached +} diff --git a/nsprpub/pr/src/md/mac/macthr.c b/nsprpub/pr/src/md/mac/macthr.c new file mode 100644 index 00000000000..292389ea8d5 --- /dev/null +++ b/nsprpub/pr/src/md/mac/macthr.c @@ -0,0 +1,721 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mdcriticalregion.h" + +TimerUPP gTimerCallbackUPP = NULL; +PRThread * gPrimaryThread = NULL; + +ProcessSerialNumber gApplicationProcess; + +PR_IMPLEMENT(PRThread *) PR_GetPrimaryThread() +{ + return gPrimaryThread; +} + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark CREATING MACINTOSH THREAD STACKS + +#if defined(GC_LEAK_DETECTOR) +extern void* GC_malloc_atomic(PRUint32 size); +#endif + +/* +** Allocate a new memory segment. We allocate it from our figment heap. Currently, +** it is being used for per thread stack space. +** +** Return the segment's access rights and size. vaddr is used on Unix platforms to +** map an existing address for the segment. +*/ +PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr) +{ + PR_ASSERT(seg != 0); + PR_ASSERT(size != 0); + PR_ASSERT(vaddr == 0); + + /* + ** Take the actual memory for the segment out of our Figment heap. + */ + +#if defined(GC_LEAK_DETECTOR) + seg->vaddr = (char *)GC_malloc_atomic(size); +#else + seg->vaddr = (char *)malloc(size); +#endif + + if (seg->vaddr == NULL) { + +#if DEBUG + DebugStr("\p_MD_AllocSegment failed."); +#endif + + return PR_FAILURE; + } + + seg->size = size; + + return PR_SUCCESS; +} + + +/* +** Free previously allocated memory segment. +*/ +void _MD_FreeSegment(PRSegment *seg) +{ + PR_ASSERT((seg->flags & _PR_SEG_VM) == 0); + + if (seg->vaddr != NULL) + free(seg->vaddr); +} + + +/* +** The thread's stack has been allocated and its fields are already properly filled +** in by PR. Perform any debugging related initialization here. +** +** Put a recognizable pattern so that we can find it from Macsbug. +** Put a cookie at the top of the stack so that we can find it from Macsbug. +*/ +void _MD_InitStack(PRThreadStack *ts, int redZoneBytes) + { +#pragma unused (redZoneBytes) +#if DEVELOPER_DEBUG + // Put a cookie at the top of the stack so that we can find + // it from Macsbug. + + memset(ts->allocBase, 0xDC, ts->stackSize); + + ((UInt32 *)ts->stackTop)[-1] = 0xBEEFCAFE; + ((UInt32 *)ts->stackTop)[-2] = (UInt32)gPrimaryThread; + ((UInt32 *)ts->stackTop)[-3] = (UInt32)(ts); + ((UInt32 *)ts->stackBottom)[0] = 0xCAFEBEEF; +#else +#pragma unused (ts) +#endif + } + +extern void _MD_ClearStack(PRThreadStack *ts) + { +#if DEVELOPER_DEBUG + // Clear out our cookies. + + memset(ts->allocBase, 0xEF, ts->allocSize); + ((UInt32 *)ts->stackTop)[-1] = 0; + ((UInt32 *)ts->stackTop)[-2] = 0; + ((UInt32 *)ts->stackTop)[-3] = 0; + ((UInt32 *)ts->stackBottom)[0] = 0; +#else +#pragma unused (ts) +#endif + } + + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark TIME MANAGER-BASED CLOCK + +// On Mac OS X, it's possible for the application to spend lots of time +// in WaitNextEvent, yielding to other applications. Since NSPR threads are +// cooperative here, this means that NSPR threads will also get very little +// time to run. To kick ourselves out of a WaitNextEvent call when we have +// determined that it's time to schedule another thread, the Timer Task +// (which fires every 8ms, even when other apps have the CPU) calls WakeUpProcess. +// We only want to do this on Mac OS X; the gTimeManagerTaskDoesWUP variable +// indicates when we're running on that OS. +// +// Note that the TimerCallback makes use of gApplicationProcess. We need to +// have set this up before the first possible run of the timer task; we do +// so in _MD_EarlyInit(). +static Boolean gTimeManagerTaskDoesWUP; + +static TMTask gTimeManagerTaskElem; + +extern void _MD_IOInterrupt(void); +_PRInterruptTable _pr_interruptTable[] = { + { "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, }, + { "i/o", _PR_MISSED_IO, _MD_IOInterrupt, }, + { 0 } +}; + +#define kMacTimerInMiliSecs 8L + +pascal void TimerCallback(TMTaskPtr tmTaskPtr) +{ + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + PRIntn is; + + if (_PR_MD_GET_INTSOFF()) { + cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK; + PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs); + return; + } + + _PR_INTSOFF(is); + + // And tell nspr that a clock interrupt occured. + _PR_ClockInterrupt(); + + if ((_PR_RUNQREADYMASK(cpu)) >> ((_PR_MD_CURRENT_THREAD()->priority))) { + if (gTimeManagerTaskDoesWUP) { + // We only want to call WakeUpProcess if we know that NSPR has managed to switch threads + // since the last call, otherwise we end up spewing out WakeUpProcess() calls while the + // application is blocking somewhere. This can interfere with events loops other than + // our own (see bug 158927). + if (UnsignedWideToUInt64(cpu->md.lastThreadSwitch) > UnsignedWideToUInt64(cpu->md.lastWakeUpProcess)) + { + WakeUpProcess(&gApplicationProcess); + cpu->md.lastWakeUpProcess = UpTime(); + } + } + _PR_SET_RESCHED_FLAG(); + } + + _PR_FAST_INTSON(is); + + // Reset the clock timer so that we fire again. + PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs); +} + + +void _MD_StartInterrupts(void) +{ + gPrimaryThread = _PR_MD_CURRENT_THREAD(); + + gTimeManagerTaskDoesWUP = RunningOnOSX(); + + if ( !gTimerCallbackUPP ) + gTimerCallbackUPP = NewTimerUPP(TimerCallback); + + // Fill in the Time Manager queue element + + gTimeManagerTaskElem.tmAddr = (TimerUPP)gTimerCallbackUPP; + gTimeManagerTaskElem.tmCount = 0; + gTimeManagerTaskElem.tmWakeUp = 0; + gTimeManagerTaskElem.tmReserved = 0; + + // Make sure that our time manager task is ready to go. + InsTime((QElemPtr)&gTimeManagerTaskElem); + + PrimeTime((QElemPtr)&gTimeManagerTaskElem, kMacTimerInMiliSecs); +} + +void _MD_StopInterrupts(void) +{ + if (gTimeManagerTaskElem.tmAddr != NULL) { + RmvTime((QElemPtr)&gTimeManagerTaskElem); + gTimeManagerTaskElem.tmAddr = NULL; + } +} + + +#define MAX_PAUSE_TIMEOUT_MS 500 + +void _MD_PauseCPU(PRIntervalTime timeout) +{ + if (timeout != PR_INTERVAL_NO_WAIT) + { + // There is a race condition entering the critical section + // in AsyncIOCompletion (and probably elsewhere) that can + // causes deadlock for the duration of this timeout. To + // work around this, use a max 500ms timeout for now. + // See bug 99561 for details. + if (PR_IntervalToMilliseconds(timeout) > MAX_PAUSE_TIMEOUT_MS) + timeout = PR_MillisecondsToInterval(MAX_PAUSE_TIMEOUT_MS); + + WaitOnIdleSemaphore(timeout); + (void) _MD_IOInterrupt(); + } +} + +void _MD_InitRunningCPU(_PRCPU* cpu) +{ + cpu->md.trackScheduling = RunningOnOSX(); + if (cpu->md.trackScheduling) { + AbsoluteTime zeroTime = {0, 0}; + cpu->md.lastThreadSwitch = UpTime(); + cpu->md.lastWakeUpProcess = zeroTime; + } +} + + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark THREAD SUPPORT FUNCTIONS + +#include /* for error codes */ + +PRStatus _MD_InitThread(PRThread *thread) +{ + thread->md.asyncIOLock = PR_NewLock(); + PR_ASSERT(thread->md.asyncIOLock != NULL); + thread->md.asyncIOCVar = PR_NewCondVar(thread->md.asyncIOLock); + PR_ASSERT(thread->md.asyncIOCVar != NULL); + + if (thread->md.asyncIOLock == NULL || thread->md.asyncIOCVar == NULL) + return PR_FAILURE; + else + return PR_SUCCESS; +} + +PRStatus _MD_wait(PRThread *thread, PRIntervalTime timeout) +{ +#pragma unused (timeout) + + _MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + + +void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout) +{ + intn is; + PRIntervalTime timein = PR_IntervalNow(); + PRStatus status = PR_SUCCESS; + + // Turn interrupts off to avoid a race over lock ownership with the callback + // (which can fire at any time). Interrupts may stay off until we leave + // this function, or another NSPR thread turns them back on. They certainly + // stay off until PR_WaitCondVar() relinquishes the asyncIOLock lock, which + // is what we care about. + _PR_INTSOFF(is); + PR_Lock(thread->md.asyncIOLock); + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + while ((thread->io_pending) && (status == PR_SUCCESS)) + status = PR_WaitCondVar(thread->md.asyncIOCVar, PR_INTERVAL_NO_TIMEOUT); + } else { + while ((thread->io_pending) && ((PRIntervalTime)(PR_IntervalNow() - timein) < timeout) && (status == PR_SUCCESS)) + status = PR_WaitCondVar(thread->md.asyncIOCVar, timeout); + } + if ((status == PR_FAILURE) && (PR_GetError() == PR_PENDING_INTERRUPT_ERROR)) { + thread->md.osErrCode = kEINTRErr; + } else if (thread->io_pending) { + thread->md.osErrCode = kETIMEDOUTErr; + PR_SetError(PR_IO_TIMEOUT_ERROR, kETIMEDOUTErr); + } + + thread->io_pending = PR_FALSE; + PR_Unlock(thread->md.asyncIOLock); + _PR_FAST_INTSON(is); +} + + +void DoneWaitingOnThisThread(PRThread *thread) +{ + intn is; + + PR_ASSERT(thread->md.asyncIOLock->owner == NULL); + + // DoneWaitingOnThisThread() is called from OT notifiers and async file I/O + // callbacks that can run at "interrupt" time (Classic Mac OS) or on pthreads + // that may run concurrently with the main threads (Mac OS X). They can thus + // be called when any NSPR thread is running, or even while NSPR is in a + // thread context switch. It is therefore vital that we can guarantee to + // be able to get the asyncIOLock without blocking (thus avoiding code + // that makes assumptions about the current NSPR thread etc). To achieve + // this, we use NSPR interrrupts as a semaphore on the lock; all code + // that grabs the lock also disables interrupts for the time the lock + // is held. Callers of DoneWaitingOnThisThread() thus have to check whether + // interrupts are already off, and, if so, simply set the missed_IO flag on + // the CPU rather than calling this function. + + _PR_INTSOFF(is); + PR_Lock(thread->md.asyncIOLock); + thread->io_pending = PR_FALSE; + /* let the waiting thread know that async IO completed */ + PR_NotifyCondVar(thread->md.asyncIOCVar); + PR_Unlock(thread->md.asyncIOLock); + _PR_FAST_INTSON(is); +} + + +PR_IMPLEMENT(void) PR_Mac_WaitForAsyncNotify(PRIntervalTime timeout) +{ + intn is; + PRIntervalTime timein = PR_IntervalNow(); + PRStatus status = PR_SUCCESS; + PRThread *thread = _PR_MD_CURRENT_THREAD(); + + // See commments in WaitOnThisThread() + _PR_INTSOFF(is); + PR_Lock(thread->md.asyncIOLock); + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + while ((!thread->md.asyncNotifyPending) && (status == PR_SUCCESS)) + status = PR_WaitCondVar(thread->md.asyncIOCVar, PR_INTERVAL_NO_TIMEOUT); + } else { + while ((!thread->md.asyncNotifyPending) && ((PRIntervalTime)(PR_IntervalNow() - timein) < timeout) && (status == PR_SUCCESS)) + status = PR_WaitCondVar(thread->md.asyncIOCVar, timeout); + } + if ((status == PR_FAILURE) && (PR_GetError() == PR_PENDING_INTERRUPT_ERROR)) { + thread->md.osErrCode = kEINTRErr; + } else if (!thread->md.asyncNotifyPending) { + thread->md.osErrCode = kETIMEDOUTErr; + PR_SetError(PR_IO_TIMEOUT_ERROR, kETIMEDOUTErr); + } + thread->md.asyncNotifyPending = PR_FALSE; + PR_Unlock(thread->md.asyncIOLock); + _PR_FAST_INTSON(is); +} + + +void AsyncNotify(PRThread *thread) +{ + intn is; + + PR_ASSERT(thread->md.asyncIOLock->owner == NULL); + + // See commments in DoneWaitingOnThisThread() + _PR_INTSOFF(is); + PR_Lock(thread->md.asyncIOLock); + thread->md.asyncNotifyPending = PR_TRUE; + /* let the waiting thread know that async IO completed */ + PR_NotifyCondVar(thread->md.asyncIOCVar); + PR_Unlock(thread->md.asyncIOLock); + _PR_FAST_INTSON(is); +} + + +PR_IMPLEMENT(void) PR_Mac_PostAsyncNotify(PRThread *thread) +{ + _PRCPU * cpu = _PR_MD_CURRENT_CPU(); + + if (_PR_MD_GET_INTSOFF()) { + thread->md.missedAsyncNotify = PR_TRUE; + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + } else { + AsyncNotify(thread); + } +} + + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark PROCESS SUPPORT FUNCTIONS + +PRProcess * _MD_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ +#pragma unused (path, argv, envp, attr) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); + return NULL; +} + +PRStatus _MD_DetachProcess(PRProcess *process) +{ +#pragma unused (process) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); + return PR_FAILURE; +} + +PRStatus _MD_WaitProcess(PRProcess *process, PRInt32 *exitCode) +{ +#pragma unused (process, exitCode) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); + return PR_FAILURE; +} + +PRStatus _MD_KillProcess(PRProcess *process) +{ +#pragma unused (process) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); + return PR_FAILURE; +} + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark ATOMIC OPERATIONS + +#ifdef _PR_HAVE_ATOMIC_OPS +PRInt32 +_MD_AtomicSet(PRInt32 *val, PRInt32 newval) +{ + PRInt32 rv; + do { + rv = *val; + } while (!OTCompareAndSwap32(rv, newval, (UInt32*)val)); + + return rv; +} + +#endif // _PR_HAVE_ATOMIC_OPS + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark INTERRUPT SUPPORT + +#if TARGET_CARBON + +/* + This critical region support is required for Mac NSPR to work correctly on dual CPU + machines on Mac OS X. This note explains why. + + NSPR uses a timer task, and has callbacks for async file I/O and Open Transport + whose runtime behaviour differs depending on environment. On "Classic" Mac OS + these run at "interrupt" time (OS-level interrupts, that is, not NSPR interrupts), + and can thus preempt other code, but they always run to completion. + + On Mac OS X, these are all emulated using MP tasks, which sit atop pthreads. Thus, + they can be preempted at any time (and not necessarily run to completion), and can + also run *concurrently* with eachother, and with application code, on multiple + CPU machines. Note that all NSPR threads are emulated, and all run on the main + application MP task. + + We thus have to use MP critical sections to protect data that is shared between + the various callbacks and the main MP thread. It so happens that NSPR has this + concept of software interrupts, and making interrupt-off times be critical + sections works. + +*/ + + +/* + Whether to use critical regions. True if running on Mac OS X and later +*/ + +PRBool gUseCriticalRegions; + +/* + Count of the number of times we've entered the critical region. + We need this because ENTER_CRITICAL_REGION() will *not* block when + called from different NSPR threads (which all run on one MP thread), + and we need to ensure that when code turns interrupts back on (by + settings _pr_intsOff to 0) we exit the critical section enough times + to leave it. +*/ + +PRInt32 gCriticalRegionEntryCount; + + +void _MD_SetIntsOff(PRInt32 ints) +{ + ENTER_CRITICAL_REGION(); + gCriticalRegionEntryCount ++; + + _pr_intsOff = ints; + + if (!ints) + { + PRInt32 i = gCriticalRegionEntryCount; + + gCriticalRegionEntryCount = 0; + for ( ;i > 0; i --) { + LEAVE_CRITICAL_REGION(); + } + } +} + + +#endif /* TARGET_CARBON */ + + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark CRITICAL REGION SUPPORT + + +static PRBool RunningOnOSX() +{ + long systemVersion; + OSErr err = Gestalt(gestaltSystemVersion, &systemVersion); + return (err == noErr) && (systemVersion >= 0x00001000); +} + + +#if MAC_CRITICAL_REGIONS + +MDCriticalRegionID gCriticalRegion; + +void InitCriticalRegion() +{ + OSStatus err; + + // we only need to do critical region stuff on Mac OS X + gUseCriticalRegions = RunningOnOSX(); + if (!gUseCriticalRegions) return; + + err = MD_CriticalRegionCreate(&gCriticalRegion); + PR_ASSERT(err == noErr); +} + +void TermCriticalRegion() +{ + OSStatus err; + + if (!gUseCriticalRegions) return; + + err = MD_CriticalRegionDelete(gCriticalRegion); + PR_ASSERT(err == noErr); +} + + +void EnterCritialRegion() +{ + OSStatus err; + + if (!gUseCriticalRegions) return; + + PR_ASSERT(gCriticalRegion != kInvalidID); + + /* Change to a non-infinite timeout for debugging purposes */ + err = MD_CriticalRegionEnter(gCriticalRegion, kDurationForever /* 10000 * kDurationMillisecond */ ); + PR_ASSERT(err == noErr); +} + +void LeaveCritialRegion() +{ + OSStatus err; + + if (!gUseCriticalRegions) return; + + PR_ASSERT(gCriticalRegion != kInvalidID); + + err = MD_CriticalRegionExit(gCriticalRegion); + PR_ASSERT(err == noErr); +} + + +#endif // MAC_CRITICAL_REGIONS + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark IDLE SEMAPHORE SUPPORT + +/* + Since the WaitNextEvent() in _MD_PauseCPU() is causing all sorts of + headache under Mac OS X we're going to switch to MPWaitOnSemaphore() + which should do what we want +*/ + +#if TARGET_CARBON +PRBool gUseIdleSemaphore = PR_FALSE; +MPSemaphoreID gIdleSemaphore = NULL; +#endif + +void InitIdleSemaphore() +{ + // we only need to do idle semaphore stuff on Mac OS X +#if TARGET_CARBON + gUseIdleSemaphore = RunningOnOSX(); + if (gUseIdleSemaphore) + { + OSStatus err = MPCreateSemaphore(1 /* max value */, 0 /* initial value */, &gIdleSemaphore); + PR_ASSERT(err == noErr); + } +#endif +} + +void TermIdleSemaphore() +{ +#if TARGET_CARBON + if (gUseIdleSemaphore) + { + OSStatus err = MPDeleteSemaphore(gIdleSemaphore); + PR_ASSERT(err == noErr); + gUseIdleSemaphore = NULL; + } +#endif +} + + +void WaitOnIdleSemaphore(PRIntervalTime timeout) +{ +#if TARGET_CARBON + if (gUseIdleSemaphore) + { + OSStatus err = MPWaitOnSemaphore(gIdleSemaphore, kDurationMillisecond * PR_IntervalToMilliseconds(timeout)); + PR_ASSERT(err == noErr); + } + else +#endif + { + EventRecord theEvent; + /* + ** Calling WaitNextEvent() here is suboptimal. This routine should + ** pause the process until IO or the timeout occur, yielding time to + ** other processes on operating systems that require this (Mac OS classic). + ** WaitNextEvent() may incur too much latency, and has other problems, + ** such as the potential to drop suspend/resume events. + */ + (void)WaitNextEvent(nullEvent, &theEvent, 1, NULL); + } +} + + +void SignalIdleSemaphore() +{ +#if TARGET_CARBON + if (gUseIdleSemaphore) + { + // often we won't be waiting on the semaphore here, so ignore any errors + (void)MPSignalSemaphore(gIdleSemaphore); + } + else +#endif + { + WakeUpProcess(&gApplicationProcess); + } +} + + diff --git a/nsprpub/pr/src/md/mac/mactime.c b/nsprpub/pr/src/md/mac/mactime.c new file mode 100644 index 00000000000..1e7d2a2223c --- /dev/null +++ b/nsprpub/pr/src/md/mac/mactime.c @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include + +#include "primpl.h" + +#include "mactime.h" + +unsigned long gJanuaryFirst1970Seconds; + +/* + * The geographic location and time zone information of a Mac + * are stored in extended parameter RAM. The ReadLocation + * produdure uses the geographic location record, MachineLocation, + * to read the geographic location and time zone information in + * extended parameter RAM. + * + * Because serial port and SLIP conflict with ReadXPram calls, + * we cache the call here. + * + * Caveat: this caching will give the wrong result if a session + * extend across the DST changeover time. + */ + +static void MyReadLocation(MachineLocation *loc) +{ + static MachineLocation storedLoc; + static Boolean didReadLocation = false; + + if (!didReadLocation) { + ReadLocation(&storedLoc); + didReadLocation = true; + } + *loc = storedLoc; +} + +static long GMTDelta(void) +{ + MachineLocation loc; + long gmtDelta; + + MyReadLocation(&loc); + gmtDelta = loc.u.gmtDelta & 0x00ffffff; + if (gmtDelta & 0x00800000) { /* test sign extend bit */ + gmtDelta |= 0xff000000; + } + return gmtDelta; +} + +void MacintoshInitializeTime(void) +{ + /* + * The NSPR epoch is midnight, Jan. 1, 1970 GMT. + * + * At midnight Jan. 1, 1970 GMT, the local time was + * midnight Jan. 1, 1970 + GMTDelta(). + * + * Midnight Jan. 1, 1970 is 86400 * (365 * (1970 - 1904) + 17) + * = 2082844800 seconds since the Mac epoch. + * (There were 17 leap years from 1904 to 1970.) + * + * So the NSPR epoch is 2082844800 + GMTDelta() seconds since + * the Mac epoch. Whew! :-) + */ + gJanuaryFirst1970Seconds = 2082844800 + GMTDelta(); +} + +/* + *----------------------------------------------------------------------- + * + * PR_Now -- + * + * Returns the current time in microseconds since the epoch. + * The epoch is midnight January 1, 1970 GMT. + * The implementation is machine dependent. This is the Mac + * Implementation. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PRTime PR_Now(void) +{ + unsigned long currentTime; /* unsigned 32-bit integer, ranging + from midnight Jan. 1, 1904 to + 6:28:15 AM Feb. 6, 2040 */ + PRTime retVal; + int64 usecPerSec; + + /* + * Get the current time expressed as the number of seconds + * elapsed since the Mac epoch, midnight, Jan. 1, 1904 (local time). + * On a Mac, current time accuracy is up to a second. + */ + GetDateTime(¤tTime); + + /* + * Express the current time relative to the NSPR epoch, + * midnight, Jan. 1, 1970 GMT. + * + * At midnight Jan. 1, 1970 GMT, the local time was + * midnight Jan. 1, 1970 + GMTDelta(). + * + * Midnight Jan. 1, 1970 is 86400 * (365 * (1970 - 1904) + 17) + * = 2082844800 seconds since the Mac epoch. + * (There were 17 leap years from 1904 to 1970.) + * + * So the NSPR epoch is 2082844800 + GMTDelta() seconds since + * the Mac epoch. Whew! :-) + */ + currentTime = currentTime - 2082844800 - GMTDelta(); + + /* Convert seconds to microseconds */ + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_I2L(retVal, currentTime); + LL_MUL(retVal, retVal, usecPerSec); + + return retVal; +} + +/* + *------------------------------------------------------------------------- + * + * PR_LocalTimeParameters -- + * + * returns the time parameters for the local time zone + * + * This is the machine-dependent implementation for Mac. + * + * Caveat: On a Mac, we only know the GMT and DST offsets for + * the current time, not for the time in question. + * Mac has no support for DST handling. + * DST changeover is all manually set by the user. + * + *------------------------------------------------------------------------- + */ + +PRTimeParameters PR_LocalTimeParameters(const PRExplodedTime *gmt) +{ +#pragma unused (gmt) + + PRTimeParameters retVal; + MachineLocation loc; + + MyReadLocation(&loc); + + /* + * On a Mac, the GMT value is in seconds east of GMT. For example, + * San Francisco is at -28,800 seconds (8 hours * 3600 seconds per hour) + * east of GMT. The gmtDelta field is a 3-byte value contained in a + * long word, so you must take care to get it properly. + */ + + retVal.tp_gmt_offset = loc.u.gmtDelta & 0x00ffffff; + if (retVal.tp_gmt_offset & 0x00800000) { /* test sign extend bit */ + retVal.tp_gmt_offset |= 0xff000000; + } + + /* + * The daylight saving time value, dlsDelta, is a signed byte + * value representing the offset for the hour field -- whether + * to add 1 hour, subtract 1 hour, or make no change at all. + */ + + if (loc.u.dlsDelta) { + retVal.tp_gmt_offset -= 3600; + retVal.tp_dst_offset = 3600; + } else { + retVal.tp_dst_offset = 0; + } + return retVal; +} + +PRIntervalTime _MD_GetInterval(void) +{ + PRIntervalTime retVal; + PRUint64 upTime, microtomilli; + + /* + * Use the Microseconds procedure to obtain the number of + * microseconds elapsed since system startup time. + */ + Microseconds((UnsignedWide *)&upTime); + LL_I2L(microtomilli, PR_USEC_PER_MSEC); + LL_DIV(upTime, upTime, microtomilli); + LL_L2I(retVal, upTime); + + return retVal; +} + +struct tm *Maclocaltime(const time_t * t) +{ + DateTimeRec dtr; + MachineLocation loc; + time_t macLocal = *t + gJanuaryFirst1970Seconds; /* GMT Mac */ + static struct tm statictime; + static const short monthday[12] = + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + SecondsToDate(macLocal, &dtr); + statictime.tm_sec = dtr.second; + statictime.tm_min = dtr.minute; + statictime.tm_hour = dtr.hour; + statictime.tm_mday = dtr.day; + statictime.tm_mon = dtr.month - 1; + statictime.tm_year = dtr.year - 1900; + statictime.tm_wday = dtr.dayOfWeek - 1; + statictime.tm_yday = monthday[statictime.tm_mon] + + statictime.tm_mday - 1; + if (2 < statictime.tm_mon && !(statictime.tm_year & 3)) + ++statictime.tm_yday; + MyReadLocation(&loc); + statictime.tm_isdst = loc.u.dlsDelta; + return(&statictime); +} + + diff --git a/nsprpub/pr/src/md/mac/mactime.h b/nsprpub/pr/src/md/mac/mactime.h new file mode 100644 index 00000000000..a78424df594 --- /dev/null +++ b/nsprpub/pr/src/md/mac/mactime.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef mactime_h__ +#define mactime_h__ + + +PR_BEGIN_EXTERN_C + +void MacintoshInitializeTime(void); + + +PR_END_EXTERN_C + + +#endif /* mactime_h__ */ diff --git a/nsprpub/pr/src/md/mac/mdcriticalregion.c b/nsprpub/pr/src/md/mac/mdcriticalregion.c new file mode 100644 index 00000000000..15eea19ad58 --- /dev/null +++ b/nsprpub/pr/src/md/mac/mdcriticalregion.c @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: NULL; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * George Warner, Apple Computer Inc. + * Simon Fraser + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "mdcriticalregion.h" +#include + +/* + This code is a replacement for MPEnterCriticalRegion/MPLeaveCriticalRegion, + which is broken on Mac OS 10.0.x builds, but fixed in 10.1. This code works + everywhere. +*/ + + +typedef struct MDCriticalRegionData_struct { + MPTaskID mMPTaskID; /* Who's in the critical region? */ + UInt32 mDepthCount; /* How deep? */ + MPSemaphoreID mMPSemaphoreID; /* ready semaphore */ +} MDCriticalRegionData, *MDCriticalRegionDataPtr; + + +OSStatus +MD_CriticalRegionCreate(MDCriticalRegionID * outCriticalRegionID) +{ + MDCriticalRegionDataPtr newCriticalRegionPtr; + MPSemaphoreID mpSemaphoreID; + OSStatus err = noErr; + + if (outCriticalRegionID == NULL) + return paramErr; + + *outCriticalRegionID = NULL; + + newCriticalRegionPtr = (MDCriticalRegionDataPtr)MPAllocateAligned(sizeof(MDCriticalRegionData), + kMPAllocateDefaultAligned, kMPAllocateClearMask); + if (newCriticalRegionPtr == NULL) + return memFullErr; + + // Note: this semaphore is pre-fired (ready!) + err = MPCreateBinarySemaphore(&mpSemaphoreID); + if (err == noErr) + { + newCriticalRegionPtr->mMPTaskID = kInvalidID; + newCriticalRegionPtr->mDepthCount = 0; + newCriticalRegionPtr->mMPSemaphoreID = mpSemaphoreID; + + *outCriticalRegionID = (MDCriticalRegionID)newCriticalRegionPtr; + } + else + { + MPFree((LogicalAddress)newCriticalRegionPtr); + } + + return err; +} + +OSStatus +MD_CriticalRegionDelete(MDCriticalRegionID inCriticalRegionID) +{ + MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID; + OSStatus err = noErr; + + if (criticalRegion == NULL) + return paramErr; + + if ((criticalRegion->mMPTaskID != kInvalidID) && (criticalRegion->mDepthCount > 0)) + return kMPInsufficientResourcesErr; + + if (criticalRegion->mMPSemaphoreID != kInvalidID) + err = MPDeleteSemaphore(criticalRegion->mMPSemaphoreID); + if (noErr != err) return err; + + criticalRegion->mMPSemaphoreID = kInvalidID; + MPFree((LogicalAddress) criticalRegion); + + return noErr; +} + +OSStatus +MD_CriticalRegionEnter(MDCriticalRegionID inCriticalRegionID, Duration inTimeout) +{ + MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID; + MPTaskID currentTaskID = MPCurrentTaskID(); + OSStatus err = noErr; + + if (criticalRegion == NULL) + return paramErr; + + // if I'm inside the critical region... + if (currentTaskID == criticalRegion->mMPTaskID) + { + // bump my depth + criticalRegion->mDepthCount++; + // and continue + return noErr; + } + + // wait for the ready semaphore + err = MPWaitOnSemaphore(criticalRegion->mMPSemaphoreID, inTimeout); + // we didn't get it. return the error + if (noErr != err) return err; + + // we got it! + criticalRegion->mMPTaskID = currentTaskID; + criticalRegion->mDepthCount = 1; + + return noErr; +} + +OSStatus +MD_CriticalRegionExit(MDCriticalRegionID inCriticalRegionID) +{ + MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID; + MPTaskID currentTaskID = MPCurrentTaskID(); + OSStatus err = noErr; + + // if we don't own the critical region... + if (currentTaskID != criticalRegion->mMPTaskID) + return kMPInsufficientResourcesErr; + + // if we aren't at a depth... + if (criticalRegion->mDepthCount == 0) + return kMPInsufficientResourcesErr; + + // un-bump my depth + criticalRegion->mDepthCount--; + + // if we just bottomed out... + if (criticalRegion->mDepthCount == 0) + { + // release ownership of the structure + criticalRegion->mMPTaskID = kInvalidID; + // and signal the ready semaphore + err = MPSignalSemaphore(criticalRegion->mMPSemaphoreID); + } + return err; +} + diff --git a/nsprpub/pr/src/md/mac/mdcriticalregion.h b/nsprpub/pr/src/md/mac/mdcriticalregion.h new file mode 100644 index 00000000000..abcd20e3b63 --- /dev/null +++ b/nsprpub/pr/src/md/mac/mdcriticalregion.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * George Warner, Apple Computer Inc. + * Simon Fraser + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef mdcriticalregion_h___ +#define mdcriticalregion_h___ + + +#ifndef __MULTIPROCESSING__ +#include +#endif + +typedef struct OpaqueMDCriticalRegionID* MDCriticalRegionID; + +OSStatus MD_CriticalRegionCreate(MDCriticalRegionID * pMDCriticalRegionID); + +OSStatus MD_CriticalRegionDelete(MDCriticalRegionID pMDCriticalRegionID); + +OSStatus MD_CriticalRegionEnter(MDCriticalRegionID pMDCriticalRegionID, Duration pTimeout); + +OSStatus MD_CriticalRegionExit(MDCriticalRegionID pMDCriticalRegionID); + +#endif /* mdcriticalregion_h___ */ + diff --git a/nsprpub/pr/src/md/mac/mdmac.c b/nsprpub/pr/src/md/mac/mdmac.c new file mode 100644 index 00000000000..cda67fb78e2 --- /dev/null +++ b/nsprpub/pr/src/md/mac/mdmac.c @@ -0,0 +1,776 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "MacErrorHandling.h" + +#include "primpl.h" +#include "prgc.h" + +#include "mactime.h" + +#include "mdmac.h" + +// undefine getenv, so that _MD_GetEnv can call the version in NSStdLib::nsEnvironment.cpp. +#undef getenv + +// +// Local routines +// +unsigned char GarbageCollectorCacheFlusher(PRUint32 size); + +extern PRThread *gPrimaryThread; +extern ProcessSerialNumber gApplicationProcess; // in macthr.c + + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark CREATING MACINTOSH THREAD STACKS + + +enum { + uppExitToShellProcInfo = kPascalStackBased, + uppStackSpaceProcInfo = kRegisterBased + | RESULT_SIZE(SIZE_CODE(sizeof(long))) + | REGISTER_RESULT_LOCATION(kRegisterD0) + | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16))) +}; + +typedef CALLBACK_API( long , StackSpacePatchPtr )(UInt16 trapNo); +typedef REGISTER_UPP_TYPE(StackSpacePatchPtr) StackSpacePatchUPP; + +StackSpacePatchUPP gStackSpacePatchUPP = NULL; +UniversalProcPtr gStackSpacePatchCallThru = NULL; +long (*gCallOSTrapUniversalProc)(UniversalProcPtr,ProcInfoType,...) = NULL; + + +pascal long StackSpacePatch(UInt16 trapNo) +{ + char tos; + PRThread *thisThread; + + thisThread = PR_GetCurrentThread(); + + // If we are the primary thread, then call through to the + // good ol' fashion stack space implementation. Otherwise, + // compute it by hand. + if ((thisThread == gPrimaryThread) || + (&tos < thisThread->stack->stackBottom) || + (&tos > thisThread->stack->stackTop)) { + return gCallOSTrapUniversalProc(gStackSpacePatchCallThru, uppStackSpaceProcInfo, trapNo); + } + else { + return &tos - thisThread->stack->stackBottom; + } +} + + +static void InstallStackSpacePatch(void) +{ + long systemVersion; + OSErr err; + CFragConnectionID connID; + Str255 errMessage; + Ptr interfaceLibAddr; + CFragSymbolClass symClass; + UniversalProcPtr (*getOSTrapAddressProc)(UInt16); + void (*setOSTrapAddressProc)(StackSpacePatchUPP, UInt16); + UniversalProcPtr (*newRoutineDescriptorProc)(ProcPtr,ProcInfoType,ISAType); + + + err = Gestalt(gestaltSystemVersion,&systemVersion); + if (systemVersion >= 0x00000A00) // we don't need to patch StackSpace() + return; + + // open connection to "InterfaceLib" + err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag, + &connID, &interfaceLibAddr, errMessage); + PR_ASSERT(err == noErr); + if (err != noErr) + return; + + // get symbol GetOSTrapAddress + err = FindSymbol(connID, "\pGetOSTrapAddress", &(Ptr)getOSTrapAddressProc, &symClass); + if (err != noErr) + return; + + // get symbol SetOSTrapAddress + err = FindSymbol(connID, "\pSetOSTrapAddress", &(Ptr)setOSTrapAddressProc, &symClass); + if (err != noErr) + return; + + // get symbol NewRoutineDescriptor + err = FindSymbol(connID, "\pNewRoutineDescriptor", &(Ptr)newRoutineDescriptorProc, &symClass); + if (err != noErr) + return; + + // get symbol CallOSTrapUniversalProc + err = FindSymbol(connID, "\pCallOSTrapUniversalProc", &(Ptr)gCallOSTrapUniversalProc, &symClass); + if (err != noErr) + return; + + // get and set trap address for StackSpace (A065) + gStackSpacePatchCallThru = getOSTrapAddressProc(0x0065); + if (gStackSpacePatchCallThru) + { + gStackSpacePatchUPP = + (StackSpacePatchUPP)newRoutineDescriptorProc((ProcPtr)(StackSpacePatch), uppStackSpaceProcInfo, GetCurrentArchitecture()); + setOSTrapAddressProc(gStackSpacePatchUPP, 0x0065); + } + +#if DEBUG + StackSpace(); +#endif +} + + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark ENVIRONMENT VARIABLES + + +typedef struct EnvVariable EnvVariable; + +struct EnvVariable { + char *variable; + char *value; + EnvVariable *next; +}; + +EnvVariable *gEnvironmentVariables = NULL; + +char *_MD_GetEnv(const char *name) +{ + EnvVariable *currentVariable = gEnvironmentVariables; + + while (currentVariable) { + if (!strcmp(currentVariable->variable, name)) + return currentVariable->value; + + currentVariable = currentVariable->next; + } + + return getenv(name); +} + +PR_IMPLEMENT(int) +_MD_PutEnv(const char *string) +{ + EnvVariable *currentVariable = gEnvironmentVariables; + char *variableCopy, + *value, + *current; + + variableCopy = strdup(string); + PR_ASSERT(variableCopy != NULL); + + current = variableCopy; + while (*current != '=') + current++; + + *current = 0; + current++; + + value = current; + + while (currentVariable) { + if (!strcmp(currentVariable->variable, variableCopy)) + break; + + currentVariable = currentVariable->next; + } + + if (currentVariable == NULL) { + currentVariable = PR_NEW(EnvVariable); + + if (currentVariable == NULL) { + PR_DELETE(variableCopy); + return -1; + } + + currentVariable->variable = strdup(variableCopy); + currentVariable->value = strdup(value); + currentVariable->next = gEnvironmentVariables; + gEnvironmentVariables = currentVariable; + } + + else { + PR_DELETE(currentVariable->value); + currentVariable->value = strdup(current); + + /* This is a temporary hack. Working on a real fix, remove this when done. */ + /* OK, there are two ways to access the */ + /* library path, getenv() and PR_GetLibraryPath(). Take a look at PR_GetLibraryPath(). */ + /* You'll see that we keep the path in a global which is intialized at startup from */ + /* a call to getenv(). From then on, they have nothing in common. */ + /* We need to keep them in synch. */ + if (strcmp(currentVariable->variable, "LD_LIBRARY_PATH") == 0) + PR_SetLibraryPath(currentVariable->value); + } + + PR_DELETE(variableCopy); + return 0; +} + + + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark MISCELLANEOUS + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(t->md.jb); + } + *np = sizeof(t->md.jb) / sizeof(PRUint32); + return (PRWord*) (t->md.jb); +} + +void _MD_GetRegisters(PRUint32 *to) +{ + (void) setjmp((void*) to); +} + +void _MD_EarlyInit() +{ + Handle environmentVariables; + + GetCurrentProcess(&gApplicationProcess); + + INIT_CRITICAL_REGION(); + InitIdleSemaphore(); + +#if !defined(MAC_NSPR_STANDALONE) + // MacintoshInitializeMemory(); Moved to mdmacmem.c: AllocateRawMemory(Size blockSize) +#else + MacintoshInitializeMemory(); +#endif + MacintoshInitializeTime(); + + // Install resource-controlled environment variables. + + environmentVariables = GetResource('Envi', 128); + if (environmentVariables != NULL) { + + Size resourceSize; + char *currentPutEnvString = (char *)*environmentVariables, + *currentScanChar = currentPutEnvString; + + resourceSize = GetHandleSize(environmentVariables); + DetachResource(environmentVariables); + HLock(environmentVariables); + + while (resourceSize--) { + + if ((*currentScanChar == '\n') || (*currentScanChar == '\r')) { + *currentScanChar = 0; + _MD_PutEnv (currentPutEnvString); + currentPutEnvString = currentScanChar + 1; + } + + currentScanChar++; + + } + + DisposeHandle(environmentVariables); + + } + +#ifdef PR_INTERNAL_LOGGING + _MD_PutEnv ("NSPR_LOG_MODULES=clock:6,cmon:6,io:6,mon:6,linker:6,cvar:6,sched:6,thread:6"); +#endif + + InstallStackSpacePatch(); +} + +void _MD_FinalInit() +{ + _MD_InitNetAccess(); +} + +void PR_InitMemory(void) { +#ifndef NSPR_AS_SHARED_LIB + // Needed for Mac browsers without Java. We don't want them calling PR_INIT, since it + // brings in all of the thread support. But we do need to allow them to initialize + // the NSPR memory package. + // This should go away when all clients of the NSPR want threads AND memory. + MacintoshInitializeMemory(); +#endif +} + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark TERMINATION + + +// THIS IS *** VERY *** IMPORTANT... our CFM Termination proc. +// This allows us to deactivate our Time Mananger task even +// if we are not totally gracefully exited. If this is not +// done then we will randomly crash at later times when the +// task is called after the app heap is gone. + +#if TARGET_CARBON +extern OTClientContextPtr clientContext; +#define CLOSE_OPEN_TRANSPORT() CloseOpenTransportInContext(clientContext) + +#else + +#define CLOSE_OPEN_TRANSPORT() CloseOpenTransport() +#endif /* TARGET_CARBON */ + +extern pascal void __NSTerminate(void); + +void CleanupTermProc(void) +{ + _MD_StopInterrupts(); // deactive Time Manager task + + CLOSE_OPEN_TRANSPORT(); + TermIdleSemaphore(); + TERM_CRITICAL_REGION(); + + __NSTerminate(); +} + + + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark STRING OPERATIONS + +#if !defined(MAC_NSPR_STANDALONE) + +// PStrFromCStr converts the source C string to a destination +// pascal string as it copies. The dest string will +// be truncated to fit into an Str255 if necessary. +// If the C String pointer is NULL, the pascal string's length is set to zero +// +void +PStrFromCStr(const char* src, Str255 dst) +{ + short length = 0; + + // handle case of overlapping strings + if ( (void*)src == (void*)dst ) + { + unsigned char* curdst = &dst[1]; + unsigned char thisChar; + + thisChar = *(const unsigned char*)src++; + while ( thisChar != '\0' ) + { + unsigned char nextChar; + + // use nextChar so we don't overwrite what we are about to read + nextChar = *(const unsigned char*)src++; + *curdst++ = thisChar; + thisChar = nextChar; + + if ( ++length >= 255 ) + break; + } + } + else if ( src != NULL ) + { + unsigned char* curdst = &dst[1]; + short overflow = 255; // count down so test it loop is faster + register char temp; + + // Can't do the K&R C thing of "while (*s++ = *t++)" because it will copy trailing zero + // which might overrun pascal buffer. Instead we use a temp variable. + while ( (temp = *src++) != 0 ) + { + *(char*)curdst++ = temp; + + if ( --overflow <= 0 ) + break; + } + length = 255 - overflow; + } + dst[0] = length; +} + + +void CStrFromPStr(ConstStr255Param pString, char **cString) +{ + // Allocates a cString and copies a Pascal string into it. + unsigned int len; + + len = pString[0]; + *cString = malloc(len+1); + + if (*cString != NULL) { + strncpy(*cString, (char *)&pString[1], len); + (*cString)[len] = NULL; + } +} + + +void dprintf(const char *format, ...) +{ +#if DEBUG + va_list ap; + Str255 buffer; + + va_start(ap, format); + buffer[0] = PR_vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap); + va_end(ap); + + DebugStr(buffer); +#endif /* DEBUG */ +} + +#else + +void debugstr(const char *debuggerMsg) +{ + Str255 pStr; + + PStrFromCStr(debuggerMsg, pStr); + DebugStr(pStr); +} + + +char *strdup(const char *source) +{ + char *newAllocation; + size_t stringLength; + + PR_ASSERT(source); + + stringLength = strlen(source) + 1; + + newAllocation = (char *)PR_MALLOC(stringLength); + if (newAllocation == NULL) + return NULL; + BlockMoveData(source, newAllocation, stringLength); + return newAllocation; +} + +// PStrFromCStr converts the source C string to a destination +// pascal string as it copies. The dest string will +// be truncated to fit into an Str255 if necessary. +// If the C String pointer is NULL, the pascal string's length is set to zero +// +void PStrFromCStr(const char* src, Str255 dst) +{ + short length = 0; + + // handle case of overlapping strings + if ( (void*)src == (void*)dst ) + { + unsigned char* curdst = &dst[1]; + unsigned char thisChar; + + thisChar = *(const unsigned char*)src++; + while ( thisChar != '\0' ) + { + unsigned char nextChar; + + // use nextChar so we don't overwrite what we are about to read + nextChar = *(const unsigned char*)src++; + *curdst++ = thisChar; + thisChar = nextChar; + + if ( ++length >= 255 ) + break; + } + } + else if ( src != NULL ) + { + unsigned char* curdst = &dst[1]; + short overflow = 255; // count down so test it loop is faster + register char temp; + + // Can't do the K&R C thing of "while (*s++ = *t++)" because it will copy trailing zero + // which might overrun pascal buffer. Instead we use a temp variable. + while ( (temp = *src++) != 0 ) + { + *(char*)curdst++ = temp; + + if ( --overflow <= 0 ) + break; + } + length = 255 - overflow; + } + dst[0] = length; +} + + +void CStrFromPStr(ConstStr255Param pString, char **cString) +{ + // Allocates a cString and copies a Pascal string into it. + unsigned int len; + + len = pString[0]; + *cString = PR_MALLOC(len+1); + + if (*cString != NULL) { + strncpy(*cString, (char *)&pString[1], len); + (*cString)[len] = NULL; + } +} + + +size_t strlen(const char *source) +{ + size_t currentLength = 0; + + if (source == NULL) + return currentLength; + + while (*source++ != '\0') + currentLength++; + + return currentLength; +} + +int strcmpcore(const char *str1, const char *str2, int caseSensitive) +{ + char currentChar1, currentChar2; + + while (1) { + + currentChar1 = *str1; + currentChar2 = *str2; + + if (!caseSensitive) { + + if ((currentChar1 >= 'a') && (currentChar1 <= 'z')) + currentChar1 += ('A' - 'a'); + + if ((currentChar2 >= 'a') && (currentChar2 <= 'z')) + currentChar2 += ('A' - 'a'); + + } + + if (currentChar1 == '\0') + break; + + if (currentChar1 != currentChar2) + return currentChar1 - currentChar2; + + str1++; + str2++; + + } + + return currentChar1 - currentChar2; +} + +int strcmp(const char *str1, const char *str2) +{ + return strcmpcore(str1, str2, true); +} + +int strcasecmp(const char *str1, const char *str2) +{ + return strcmpcore(str1, str2, false); +} + + +void *memcpy(void *to, const void *from, size_t size) +{ + if (size != 0) { +#if DEBUG + if ((UInt32)to < 0x1000) + DebugStr("\pmemcpy has illegal to argument"); + if ((UInt32)from < 0x1000) + DebugStr("\pmemcpy has illegal from argument"); +#endif + BlockMoveData(from, to, size); + } + return to; +} + +void dprintf(const char *format, ...) +{ + va_list ap; + char *buffer; + + va_start(ap, format); + buffer = (char *)PR_vsmprintf(format, ap); + va_end(ap); + + debugstr(buffer); + PR_DELETE(buffer); +} + +void +exit(int result) +{ +#pragma unused (result) + + ExitToShell(); +} + +void abort(void) +{ + exit(-1); +} + +#endif + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark FLUSHING THE GARBAGE COLLECTOR + +#if !defined(MAC_NSPR_STANDALONE) + +unsigned char GarbageCollectorCacheFlusher(PRUint32) +{ + + PRIntn is; + + UInt32 oldPriority; + + // If java wasn't completely initialized, then bail + // harmlessly. + + if (PR_GetGCInfo()->lock == NULL) + return false; + +#if DEBUG + if (_MD_GET_INTSOFF() == 1) + DebugStr("\pGarbageCollectorCacheFlusher at interrupt time!"); +#endif + + // The synchronization here is very tricky. We really + // don't want any other threads to run while we are + // cleaning up the gc heap... they could call malloc, + // and then we would be in trouble in a big way. So, + // we jack up our priority and that of the finalizer + // so that we won't yield to other threads. + // dkc 5/17/96 + + oldPriority = PR_GetThreadPriority(PR_GetCurrentThread()); + _PR_INTSOFF(is); + _PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)30); + _PR_INTSON(is); + + // Garbage collect twice. This will finalize any + // dangling AWT resources (images, components), and + // then free up their GC space, too. + // dkc 2/15/96 + // interrupts must be on during PR_GC + + PR_GC(); + + // By setting the finalizer priority to 31, then we + // ensure it will run before us. When it finishes + // its list of finalizations, it returns to us + // for the second garbage collection. + + PR_Yield(); + + PR_GC(); + + // Restore our old priorities. + + _PR_INTSOFF(is); + _PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)oldPriority); + _PR_INTSON(is); + + return false; +} + +#endif + +//############################################################################## +//############################################################################## +#pragma mark - +#pragma mark MISCELLANEOUS-HACKS + + +// +// ***** HACK FIX THESE **** +// +extern long _MD_GetOSName(char *buf, long count) +{ + long len; + + len = PR_snprintf(buf, count, "Mac OS"); + + return 0; +} + +extern long _MD_GetOSVersion(char *buf, long count) +{ + long len; + + len = PR_snprintf(buf, count, "7.5"); + + return 0; +} + +extern long _MD_GetArchitecture(char *buf, long count) +{ + long len; + +#if defined(TARGET_CPU_PPC) && TARGET_CPU_PPC + len = PR_snprintf(buf, count, "PowerPC"); +#else + len = PR_snprintf(buf, count, "Motorola68k"); +#endif + + return 0; +} diff --git a/nsprpub/pr/src/md/mac/mdmac.h b/nsprpub/pr/src/md/mac/mdmac.h new file mode 100644 index 00000000000..ad8c3c4d170 --- /dev/null +++ b/nsprpub/pr/src/md/mac/mdmac.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef mdmac_h__ +#define mdmac_h__ + + +PR_BEGIN_EXTERN_C + +void PStrFromCStr(const char* src, Str255 dst); +void CStrFromPStr(ConstStr255Param pString, char **cString); + +PR_END_EXTERN_C + + +#endif /* mdmac_h__ */ diff --git a/nsprpub/pr/src/md/mac/prcpucfg.h b/nsprpub/pr/src/md/mac/prcpucfg.h new file mode 100644 index 00000000000..17d665c65db --- /dev/null +++ b/nsprpub/pr/src/md/mac/prcpucfg.h @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_MAC +#define XP_MAC +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define HAVE_LONG_LONG + +#define PR_AF_INET6 30 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1L +#define PR_BYTES_PER_SHORT 2L +#define PR_BYTES_PER_INT 4L +#define PR_BYTES_PER_INT64 8L +#define PR_BYTES_PER_LONG 4L +#define PR_BYTES_PER_FLOAT 4L +#define PR_BYTES_PER_DOUBLE 8L +#define PR_BYTES_PER_WORD 4L +#define PR_BYTES_PER_DWORD 8L + +#define PR_BITS_PER_BYTE 8L +#define PR_BITS_PER_SHORT 16L +#define PR_BITS_PER_INT 32L +#define PR_BITS_PER_INT64 64L +#define PR_BITS_PER_LONG 32L +#define PR_BITS_PER_FLOAT 32L +#define PR_BITS_PER_DOUBLE 64L +#define PR_BITS_PER_WORD 32L + +#define PR_BITS_PER_BYTE_LOG2 3L +#define PR_BITS_PER_SHORT_LOG2 4L +#define PR_BITS_PER_INT_LOG2 5L +#define PR_BITS_PER_INT64_LOG2 6L +#define PR_BITS_PER_LONG_LOG2 5L +#define PR_BITS_PER_FLOAT_LOG2 5L +#define PR_BITS_PER_DOUBLE_LOG2 6L +#define PR_BITS_PER_WORD_LOG2 5L + +#define PR_ALIGN_OF_SHORT 2L +#define PR_ALIGN_OF_INT 4L +#define PR_ALIGN_OF_LONG 4L +#define PR_ALIGN_OF_INT64 2L +#define PR_ALIGN_OF_FLOAT 4L +#define PR_ALIGN_OF_DOUBLE 4L +#define PR_ALIGN_OF_POINTER 4L +#define PR_ALIGN_OF_WORD 4L + +#define PR_BYTES_PER_WORD_LOG2 2L +#define PR_BYTES_PER_DWORD_LOG2 3L +#define PR_WORDS_PER_DWORD_LOG2 1L + +#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/nsprpub/pr/src/md/os2/.cvsignore b/nsprpub/pr/src/md/os2/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/md/os2/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/md/os2/Makefile.in b/nsprpub/pr/src/md/os2/Makefile.in new file mode 100644 index 00000000000..299cf6628ad --- /dev/null +++ b/nsprpub/pr/src/md/os2/Makefile.in @@ -0,0 +1,85 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), OS2) +CSRCS = \ + os2misc.c \ + os2sem.c \ + os2inrval.c \ + os2gc.c \ + os2thred.c \ + os2io.c \ + os2cv.c \ + os2sock.c \ + os2_errors.c \ + os2poll.c \ + os2rng.c \ + $(NULL) +endif + +ifeq ($(MOZ_OS2_TOOLS),VACPP) +ASFILES = os2vacpp.asm +endif + +ifeq ($(MOZ_OS2_TOOLS),EMX) +ASFILES = os2emx.s os2vaclegacy.s +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + + + + diff --git a/nsprpub/pr/src/md/os2/objs.mk b/nsprpub/pr/src/md/os2/objs.mk new file mode 100644 index 00000000000..008c252557c --- /dev/null +++ b/nsprpub/pr/src/md/os2/objs.mk @@ -0,0 +1,65 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# This makefile appends to the variable OBJS the platform-dependent +# object modules that will be part of the nspr20 library. + +CSRCS = \ + os2io.c \ + os2sock.c \ + os2thred.c \ + os2cv.c \ + os2gc.c \ + os2misc.c \ + os2inrval.c \ + os2sem.c \ + os2_errors.c \ + os2poll.c \ + os2rng.c \ + $(NULL) + +ifeq ($(MOZ_OS2_TOOLS),VACPP) +ASFILES = os2vacpp.asm +endif + +ifeq ($(MOZ_OS2_TOOLS),EMX) +ASFILES = os2emx.s os2vaclegacy.s +endif + +OBJS += $(addprefix md/os2/$(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix md/os2/$(OBJDIR)/,$(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))) + diff --git a/nsprpub/pr/src/md/os2/os2_errors.c b/nsprpub/pr/src/md/os2/os2_errors.c new file mode 100644 index 00000000000..59784d0ca77 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2_errors.c @@ -0,0 +1,1129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prerror.h" +#include "primpl.h" + +void _MD_os2_map_default_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EMSGSIZE: + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} +void _MD_os2_map_opendir_error(PRInt32 err) +{ + switch (err) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + case ERROR_INVALID_ACCESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + case ERROR_INVALID_PARAMETER: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + case ERROR_NOT_DOS_DISK: + case ERROR_NOT_READY: + case ERROR_OPEN_FAILED: + case ERROR_PATH_BUSY: + case ERROR_CANNOT_MAKE: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_DEVICE_IN_USE: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_SHARING_BUFFER_EXCEEDED: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_closedir_error(PRInt32 err) +{ + switch (err) { + case ERROR_FILE_NOT_FOUND: + case ERROR_ACCESS_DENIED: + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_readdir_error(PRInt32 err) +{ + + switch (err) { + case ERROR_NO_MORE_FILES: + PR_SetError(PR_NO_MORE_FILES_ERROR, err); + break; + case ERROR_FILE_NOT_FOUND: + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_DOS_DISK: + case ERROR_LOCK_VIOLATION: + case ERROR_BROKEN_PIPE: + case ERROR_NOT_READY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_delete_error(PRInt32 err) +{ + switch (err) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +/* The error code for stat() is in errno. */ +void _MD_os2_map_stat_error(PRInt32 err) +{ + switch (err) { + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + } +} + +void _MD_os2_map_fstat_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_rename_error(PRInt32 err) +{ + switch (err) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +/* The error code for access() is in errno. */ +void _MD_os2_map_access_error(PRInt32 err) +{ + switch (err) { + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + } +} + +void _MD_os2_map_mkdir_error(PRInt32 err) +{ + switch (err) { + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + case ERROR_FILE_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DISK_FULL: + case ERROR_HANDLE_DISK_FULL: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_rmdir_error(PRInt32 err) +{ + + switch (err) { + case ERROR_FILE_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_read_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_transmitfile_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_write_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + case ERROR_DISK_FULL: + case ERROR_HANDLE_DISK_FULL: + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EMSGSIZE: + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_lseek_error(PRInt32 err) +{ + switch (err) { + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_SEEK_ON_DEVICE: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_fsync_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DISK_FULL: + case ERROR_HANDLE_DISK_FULL: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_close_error(PRInt32 err) +{ + switch (err) { + case ERROR_INVALID_HANDLE: + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_socket_error(PRInt32 err) +{ + switch (err) { + case EPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_recv_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_recvfrom_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_send_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EMSGSIZE: + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_sendto_error(PRInt32 err) +{ + _MD_os2_map_default_error(err); +} + +void _MD_os2_map_writev_error(int err) +{ + _MD_os2_map_default_error(err); +} + +void _MD_os2_map_accept_error(PRInt32 err) +{ + _MD_os2_map_default_error(err); +} + +void _MD_os2_map_acceptex_error(PRInt32 err) +{ + switch (err) { + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +/* + * An error code of 0 means that the nonblocking connect succeeded. + */ + +int _MD_os2_get_nonblocking_connect_error(int osfd) +{ + int err; + int len = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) { + return sock_errno(); + } else { + return err; + } +} + +void _MD_os2_map_connect_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EINPROGRESS: + PR_SetError(PR_IN_PROGRESS_ERROR, err); + break; + case EALREADY: + case EINVAL: + PR_SetError(PR_ALREADY_INITIATED_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_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 EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_bind_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case EADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_SOCKET_ADDRESS_IS_BOUND_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_listen_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EOPNOTSUPP: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_shutdown_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +#ifndef XP_OS2_VACPP +void _MD_os2_map_socketpair_error(PRInt32 err) +{ + switch (err) { + case ENOMEM: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case EPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case EOPNOTSUPP: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; + case EPROTOTYPE: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + default: + _MD_os2_map_default_error(err); + return; + } +} +#endif + +void _MD_os2_map_getsockname_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_getpeername_error(PRInt32 err) +{ + + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_getsockopt_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_setsockopt_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_open_error(PRInt32 err) +{ + switch (err) { + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + case ERROR_FILE_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_OPEN_FAILED: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DISK_FULL: + case ERROR_HANDLE_DISK_FULL: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_gethostname_error(PRInt32 err) +{ + switch (err) { +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ENETDOWN: + case EINPROGRESS: + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_select_error(PRInt32 err) +{ + PRErrorCode prerror; + + switch (err) { + /* + * OS/2 select() only works on sockets. So in this + * context, ENOTSOCK is equivalent to EBADF on Unix. + */ + case ENOTSOCK: + prerror = PR_BAD_DESCRIPTOR_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; +#ifdef SOCEFAULT + case SOCEFAULT: + prerror = PR_ACCESS_FAULT_ERROR; + break; +#endif + default: + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, err); +} + +void _MD_os2_map_lockf_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} diff --git a/nsprpub/pr/src/md/os2/os2cv.c b/nsprpub/pr/src/md/os2/os2cv.c new file mode 100644 index 00000000000..f0aeefabe1f --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2cv.c @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * os2cv.c -- OS/2 Machine-Dependent Code for Condition Variables + * + * We implement our own condition variable wait queue. Each thread + * has a semaphore object (thread->md.blocked_sema) to block on while + * waiting on a condition variable. + * + * We use a deferred condition notify algorithm. When PR_NotifyCondVar + * or PR_NotifyAllCondVar is called, the condition notifies are simply + * recorded in the _MDLock structure. We defer the condition notifies + * until right after we unlock the lock. This way the awakened threads + * have a better chance to reaquire the lock. + */ + +#include "primpl.h" + +#ifdef USE_RAMSEM +ULONG _Far16 _Pascal Dos16GetInfoSeg(PSEL pselGlobal, PSEL pselLocal); + +#ifdef XP_OS2_EMX +typedef unsigned short BOOL16; +#endif + +typedef struct _LINFOSEG +{ + USHORT pidCurrent; + USHORT pidParent; + USHORT prtyCurrent; + USHORT tidCurrent; + USHORT sgCurrent; + UCHAR rfProcStatus; + UCHAR dummy1; + BOOL16 fForeground; + UCHAR typProcess; + UCHAR dummy2; + SEL selEnvironment; + USHORT offCmdLine; + USHORT cbDataSegment; + USHORT cbStack; + USHORT cbHeap; + USHORT hmod; + SEL selDS; + SEL selPack; + SEL selPackShr; + SEL selPackPck; + ULONG ulReserved; +} LINFOSEG; +typedef LINFOSEG FAR *PLINFOSEG; + +PLINFOSEG plisCurrent = NULL; +#endif + +/* + * AddThreadToCVWaitQueueInternal -- + * + * Add the thread to the end of the condition variable's wait queue. + * The CV's lock must be locked when this function is called. + */ + +static void +AddThreadToCVWaitQueueInternal(PRThread *thred, struct _MDCVar *cv) +{ + PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL) + || (cv->waitTail == NULL && cv->waitHead == NULL)); + cv->nwait += 1; + thred->md.inCVWaitQueue = PR_TRUE; + thred->md.next = NULL; + thred->md.prev = cv->waitTail; + if (cv->waitHead == NULL) { + cv->waitHead = thred; + } else { + cv->waitTail->md.next = thred; + } + cv->waitTail = thred; +} + +/* + * md_UnlockAndPostNotifies -- + * + * Unlock the lock, and then do the deferred condition notifies. + * If waitThred and waitCV are not NULL, waitThred is added to + * the wait queue of waitCV before the lock is unlocked. + * + * This function is called by _PR_MD_WAIT_CV and _PR_MD_UNLOCK, + * the two places where a lock is unlocked. + */ +void +md_UnlockAndPostNotifies( + _MDLock *lock, + PRThread *waitThred, + _MDCVar *waitCV) +{ + PRIntn index; + _MDNotified post; + _MDNotified *notified, *prev = NULL; + + /* + * Time to actually notify any conditions that were affected + * while the lock was held. Get a copy of the list that's in + * the lock structure and then zero the original. If it's + * linked to other such structures, we own that storage. + */ + post = lock->notified; /* a safe copy; we own the lock */ + +#if defined(DEBUG) + memset(&lock->notified, 0, sizeof(_MDNotified)); /* reset */ +#else + lock->notified.length = 0; /* these are really sufficient */ + lock->notified.link = NULL; +#endif + + /* + * Figure out how many threads we need to wake up. + */ + notified = &post; /* this is where we start */ + do { + for (index = 0; index < notified->length; ++index) { + _MDCVar *cv = notified->cv[index].cv; + PRThread *thred; + int i; + + /* Fast special case: no waiting threads */ + if (cv->waitHead == NULL) { + notified->cv[index].notifyHead = NULL; + continue; + } + + /* General case */ + if (-1 == notified->cv[index].times) { + /* broadcast */ + thred = cv->waitHead; + while (thred != NULL) { + thred->md.inCVWaitQueue = PR_FALSE; + thred = thred->md.next; + } + notified->cv[index].notifyHead = cv->waitHead; + cv->waitHead = cv->waitTail = NULL; + cv->nwait = 0; + } else { + thred = cv->waitHead; + i = notified->cv[index].times; + while (thred != NULL && i > 0) { + thred->md.inCVWaitQueue = PR_FALSE; + thred = thred->md.next; + i--; + } + notified->cv[index].notifyHead = cv->waitHead; + cv->waitHead = thred; + if (cv->waitHead == NULL) { + cv->waitTail = NULL; + } else { + if (cv->waitHead->md.prev != NULL) { + cv->waitHead->md.prev->md.next = NULL; + cv->waitHead->md.prev = NULL; + } + } + cv->nwait -= notified->cv[index].times - i; + } + } + notified = notified->link; + } while (NULL != notified); + + if (waitThred) { + AddThreadToCVWaitQueueInternal(waitThred, waitCV); + } + + /* Release the lock before notifying */ +#ifdef USE_RAMSEM + SemReleasex86(&lock->mutex, 0); +#else + DosReleaseMutexSem(lock->mutex); +#endif + + notified = &post; /* this is where we start */ + do { + for (index = 0; index < notified->length; ++index) { + PRThread *thred; + PRThread *next; + + thred = notified->cv[index].notifyHead; + while (thred != NULL) { + BOOL rv; + + next = thred->md.next; + thred->md.prev = thred->md.next = NULL; + rv = DosPostEventSem(thred->md.blocked_sema); + PR_ASSERT(rv == NO_ERROR); + thred = next; + } + } + prev = notified; + notified = notified->link; + if (&post != prev) PR_DELETE(prev); + } while (NULL != notified); +} + +/* + * Notifies just get posted to the protecting mutex. The + * actual notification is done when the lock is released so that + * MP systems don't contend for a lock that they can't have. + */ +static void md_PostNotifyToCvar(_MDCVar *cvar, _MDLock *lock, + PRBool broadcast) +{ + PRIntn index = 0; + _MDNotified *notified = &lock->notified; + + while (1) { + for (index = 0; index < notified->length; ++index) { + if (notified->cv[index].cv == cvar) { + if (broadcast) { + notified->cv[index].times = -1; + } else if (-1 != notified->cv[index].times) { + notified->cv[index].times += 1; + } + return; + } + } + /* if not full, enter new CV in this array */ + if (notified->length < _MD_CV_NOTIFIED_LENGTH) break; + + /* if there's no link, create an empty array and link it */ + if (NULL == notified->link) { + notified->link = PR_NEWZAP(_MDNotified); + } + + notified = notified->link; + } + + /* A brand new entry in the array */ + notified->cv[index].times = (broadcast) ? -1 : 1; + notified->cv[index].cv = cvar; + notified->length += 1; +} + +/* + * _PR_MD_NEW_CV() -- Creating new condition variable + * ... Solaris uses cond_init() in similar function. + * + * returns: -1 on failure + * 0 when it succeeds. + * + */ +PRInt32 +_PR_MD_NEW_CV(_MDCVar *cv) +{ + cv->magic = _MD_MAGIC_CV; + /* + * The waitHead, waitTail, and nwait fields are zeroed + * when the PRCondVar structure is created. + */ + return 0; +} + +void _PR_MD_FREE_CV(_MDCVar *cv) +{ + cv->magic = (PRUint32)-1; + return; +} + +/* + * _PR_MD_WAIT_CV() -- Wait on condition variable + */ +void +_PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout ) +{ + PRThread *thred = _PR_MD_CURRENT_THREAD(); + ULONG rv, count; + ULONG msecs = (timeout == PR_INTERVAL_NO_TIMEOUT) ? + SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(timeout); + + /* + * If we have pending notifies, post them now. + */ + if (0 != lock->notified.length) { + md_UnlockAndPostNotifies(lock, thred, cv); + } else { + AddThreadToCVWaitQueueInternal(thred, cv); +#ifdef USE_RAMSEM + SemReleasex86( &lock->mutex, 0 ); +#else + DosReleaseMutexSem(lock->mutex); +#endif + } + + /* Wait for notification or timeout; don't really care which */ + rv = DosWaitEventSem(thred->md.blocked_sema, msecs); + if (rv == NO_ERROR) { + DosResetEventSem(thred->md.blocked_sema, &count); + } + +#ifdef USE_RAMSEM + SemRequest486(&(lock->mutex), -1); +#else + DosRequestMutexSem((lock->mutex), SEM_INDEFINITE_WAIT); +#endif + + PR_ASSERT(rv == NO_ERROR || rv == ERROR_TIMEOUT); + + if(rv == ERROR_TIMEOUT) + { + if (thred->md.inCVWaitQueue) { + PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL) + || (cv->waitTail == NULL && cv->waitHead == NULL)); + cv->nwait -= 1; + thred->md.inCVWaitQueue = PR_FALSE; + if (cv->waitHead == thred) { + cv->waitHead = thred->md.next; + if (cv->waitHead == NULL) { + cv->waitTail = NULL; + } else { + cv->waitHead->md.prev = NULL; + } + } else { + PR_ASSERT(thred->md.prev != NULL); + thred->md.prev->md.next = thred->md.next; + if (thred->md.next != NULL) { + thred->md.next->md.prev = thred->md.prev; + } else { + PR_ASSERT(cv->waitTail == thred); + cv->waitTail = thred->md.prev; + } + } + thred->md.next = thred->md.prev = NULL; + } else { + /* + * This thread must have been notified, but the + * SemRelease call happens after SemRequest + * times out. Wait on the semaphore again to make it + * non-signaled. We assume this wait won't take long. + */ + rv = DosWaitEventSem(thred->md.blocked_sema, SEM_INDEFINITE_WAIT); + if (rv == NO_ERROR) { + DosResetEventSem(thred->md.blocked_sema, &count); + } + PR_ASSERT(rv == NO_ERROR); + } + } + PR_ASSERT(thred->md.inCVWaitQueue == PR_FALSE); + return; +} /* --- end _PR_MD_WAIT_CV() --- */ + +void +_PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock) +{ + md_PostNotifyToCvar(cv, lock, PR_FALSE); + return; +} + +PRStatus +_PR_MD_NEW_LOCK(_MDLock *lock) +{ +#ifdef USE_RAMSEM + // It's better if this API traps when pCriticalSect is not a valid + // pointer, because we can't return an error code and if we just return + // the API caller will have nasty bugs that are hard to find. + + PRAMSEM pramsem = (PRAMSEM)(&(lock->mutex)); + /* First time, set up addresses of processor specific functions + */ + if (plisCurrent == NULL) + { + SEL selGlobal = 0, selLocal = 0; + + /* Convert 16 bit global information segment to 32 bit address + * by performing CRMA on the 16 bit address: "shift" operation + * to convert sel to flat, "and" operation to mask the address + * to 32-bit + */ + Dos16GetInfoSeg(&selGlobal, &selLocal); + plisCurrent = (PLINFOSEG)(((ULONG)selLocal << 13) & + (ULONG)0x1fff0000); + + } + + memset(pramsem, 0, sizeof(pramsem)); + DosCreateEventSem(0, &pramsem->hevSem, DC_SEM_SHARED, 0); + + lock->notified.length=0; + lock->notified.link=NULL; + return PR_SUCCESS; +#else + DosCreateMutexSem(0, &(lock->mutex), 0, 0); + (lock)->notified.length=0; + (lock)->notified.link=NULL; + return PR_SUCCESS; +#endif +} + +void +_PR_MD_NOTIFYALL_CV(_MDCVar *cv, _MDLock *lock) +{ + md_PostNotifyToCvar(cv, lock, PR_TRUE); + return; +} + +void _PR_MD_UNLOCK(_MDLock *lock) +{ + if (0 != lock->notified.length) { + md_UnlockAndPostNotifies(lock, NULL, NULL); + } else { + DosReleaseMutexSem(lock->mutex); + } +} diff --git a/nsprpub/pr/src/md/os2/os2emx.s b/nsprpub/pr/src/md/os2/os2emx.s new file mode 100644 index 00000000000..3efd68ce433 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2emx.s @@ -0,0 +1,114 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ ***** BEGIN LICENSE BLOCK ***** +/ Version: MPL 1.1/GPL 2.0/LGPL 2.1 +/ +/ The contents of this file are subject to the Mozilla Public License Version +/ 1.1 (the "License"); you may not use this file except in compliance with +/ the License. You may obtain a copy of the License at +/ http://www.mozilla.org/MPL/ +/ +/ Software distributed under the License is distributed on an "AS IS" basis, +/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +/ for the specific language governing rights and limitations under the +/ License. +/ +/ The Original Code is the Netscape Portable Runtime (NSPR). +/ +/ The Initial Developer of the Original Code is +/ Netscape Communications Corporation. +/ Portions created by the Initial Developer are Copyright (C) 2000 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the terms of +/ either the GNU General Public License Version 2 or later (the "GPL"), or +/ the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +/ in which case the provisions of the GPL or the LGPL are applicable instead +/ of those above. If you wish to allow use of your version of this file only +/ under the terms of either the GPL or the LGPL, and not to allow others to +/ use your version of this file under the terms of the MPL, indicate your +/ decision by deleting the provisions above and replace them with the notice +/ and other provisions required by the GPL or the LGPL. If you do not delete +/ the provisions above, a recipient may use your version of this file under +/ the terms of any one of the MPL, the GPL or the LGPL. +/ +/ ***** END LICENSE BLOCK ***** + +/ PRInt32 __PR_MD_ATOMIC_INCREMENT(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl __PR_MD_ATOMIC_INCREMENT + .align 4 +__PR_MD_ATOMIC_INCREMENT: + movl 4(%esp), %ecx + movl $1, %eax + lock + xaddl %eax, (%ecx) + incl %eax + ret + +/ PRInt32 __PR_MD_ATOMIC_DECREMENT(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl __PR_MD_ATOMIC_DECREMENT + .align 4 +__PR_MD_ATOMIC_DECREMENT: + movl 4(%esp), %ecx + movl $-1, %eax + lock + xaddl %eax, (%ecx) + decl %eax + ret + +/ PRInt32 __PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ +/ An alternative implementation: +/ .text +/ .globl __PR_MD_ATOMIC_SET +/ .align 4 +/__PR_MD_ATOMIC_SET: +/ movl 4(%esp), %ecx +/ movl 8(%esp), %edx +/ movl (%ecx), %eax +/retry: +/ lock +/ cmpxchgl %edx, (%ecx) +/ jne retry +/ ret +/ + .text + .globl __PR_MD_ATOMIC_SET + .align 4 +__PR_MD_ATOMIC_SET: + movl 4(%esp), %ecx + movl 8(%esp), %eax + xchgl %eax, (%ecx) + ret + +/ PRInt32 __PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl __PR_MD_ATOMIC_ADD + .align 4 +__PR_MD_ATOMIC_ADD: + movl 4(%esp), %ecx + movl 8(%esp), %eax + movl %eax, %edx + lock + xaddl %eax, (%ecx) + addl %edx, %eax + ret diff --git a/nsprpub/pr/src/md/os2/os2gc.c b/nsprpub/pr/src/md/os2/os2gc.c new file mode 100644 index 00000000000..d9f76466861 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2gc.c @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * GC related routines + * + */ +#include "primpl.h" + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + CONTEXTRECORD context; + context.ContextFlags = CONTEXT_INTEGER; + + if (_PR_IS_NATIVE_THREAD(t)) { + context.ContextFlags |= CONTEXT_CONTROL; + if (QueryThreadContext(t->md.handle, CONTEXT_CONTROL, &context)) { + t->md.gcContext[0] = context.ctx_RegEax; + t->md.gcContext[1] = context.ctx_RegEbx; + t->md.gcContext[2] = context.ctx_RegEcx; + t->md.gcContext[3] = context.ctx_RegEdx; + t->md.gcContext[4] = context.ctx_RegEsi; + t->md.gcContext[5] = context.ctx_RegEdi; + t->md.gcContext[6] = context.ctx_RegEsp; + t->md.gcContext[7] = context.ctx_RegEbp; + *np = PR_NUM_GCREGS; + } else { + PR_ASSERT(0);/* XXX */ + } + } + return (PRWord *)&t->md.gcContext; +} + +/* This function is not used right now, but is left as a reference. + * If you ever need to get the fiberID from the currently running fiber, + * this is it. + */ +void * +GetMyFiberID() +{ + void *fiberData = 0; + + /* A pointer to our tib entry is found at FS:[18] + * At offset 10h is the fiberData pointer. The context of the + * fiber is stored in there. + */ +#ifdef HAVE_ASM + __asm { + mov EDX, FS:[18h] + mov EAX, DWORD PTR [EDX+10h] + mov [fiberData], EAX + } +#endif + + return fiberData; +} diff --git a/nsprpub/pr/src/md/os2/os2inrval.c b/nsprpub/pr/src/md/os2/os2inrval.c new file mode 100644 index 00000000000..4006f5f2b0a --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2inrval.c @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * OS/2 interval timers + * + */ + +#include "primpl.h" + +static PRBool useHighResTimer = PR_FALSE; +PRIntervalTime _os2_ticksPerSec = -1; +PRIntn _os2_bitShift = 0; +PRInt32 _os2_highMask = 0; + +void +_PR_MD_INTERVAL_INIT() +{ + char *envp; + ULONG timerFreq; + APIRET rc; + + if ((envp = getenv("NSPR_OS2_NO_HIRES_TIMER")) != NULL) { + if (atoi(envp) == 1) + return; + } + + timerFreq = 0; /* OS/2 high-resolution timer frequency in Hz */ + rc = DosTmrQueryFreq(&timerFreq); + if (NO_ERROR == rc) { + useHighResTimer = PR_TRUE; + PR_ASSERT(timerFreq != 0); + while (timerFreq > PR_INTERVAL_MAX) { + timerFreq >>= 1; + _os2_bitShift++; + _os2_highMask = (_os2_highMask << 1)+1; + } + + _os2_ticksPerSec = timerFreq; + PR_ASSERT(_os2_ticksPerSec > PR_INTERVAL_MIN); + } +} + +PRIntervalTime +_PR_MD_GET_INTERVAL() +{ + if (useHighResTimer) { + QWORD timestamp; + PRInt32 top; + APIRET rc = DosTmrQueryTime(×tamp); + if (NO_ERROR != rc) { + return -1; + } + /* Sadly, nspr requires the interval to range from 1000 ticks per + * second to only 100000 ticks per second. DosTmrQueryTime is too + * high resolution... + */ + top = timestamp.ulHi & _os2_highMask; + top = top << (32 - _os2_bitShift); + timestamp.ulLo = timestamp.ulLo >> _os2_bitShift; + timestamp.ulLo = timestamp.ulLo + top; + return (PRUint32)timestamp.ulLo; + } else { + ULONG msCount = -1; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &msCount, sizeof(msCount)); + return msCount; + } +} + +PRIntervalTime +_PR_MD_INTERVAL_PER_SEC() +{ + if (useHighResTimer) { + return _os2_ticksPerSec; + } else { + return 1000; + } +} diff --git a/nsprpub/pr/src/md/os2/os2io.c b/nsprpub/pr/src/md/os2/os2io.c new file mode 100644 index 00000000000..2d007dc8270 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2io.c @@ -0,0 +1,998 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/23/2000 IBM Corp. Changed write() to DosWrite(). EMX i/o + * calls cannot be intermixed with DosXXX + * calls since EMX remaps file/socket + * handles. + * 04/27/2000 IBM Corp. Changed open file to be more like NT and + * better handle PR_TRUNCATE | PR_CREATE_FILE + * and also fixed _PR_MD_SET_FD_INHERITABLE + */ + +/* OS2 IO module + * + * Assumes synchronous I/O. + * + */ + +#include "primpl.h" +#include "prio.h" +#include +#include +#ifdef XP_OS2_VACPP +#include +#else +#include +#include +#include +#include +#endif + +struct _MDLock _pr_ioq_lock; + +static PRBool isWSEB = PR_FALSE; /* whether we are using an OS/2 kernel that supports large files */ + +typedef APIRET (*DosOpenLType)(PSZ pszFileName, PHFILE pHf, PULONG pulAction, + LONGLONG cbFile, ULONG ulAttribute, + ULONG fsOpenFlags, ULONG fsOpenMode, + PEAOP2 peaop2); + +typedef APIRET (*DosSetFileLocksLType)(HFILE hFile, PFILELOCKL pflUnlock, + PFILELOCKL pflLock, ULONG timeout, + ULONG flags); + +typedef APIRET (*DosSetFilePtrLType)(HFILE hFile, LONGLONG ib, ULONG method, + PLONGLONG ibActual); + +DosOpenLType myDosOpenL; +DosSetFileLocksLType myDosSetFileLocksL; +DosSetFilePtrLType myDosSetFilePtrL; + +void +_PR_MD_INIT_IO() +{ + APIRET rc; + HMODULE module; + + sock_init(); + + rc = DosLoadModule(NULL, 0, "DOSCALL1", &module); + if (rc != NO_ERROR) + { + return; + } + rc = DosQueryProcAddr(module, 981, NULL, (PFN*) &myDosOpenL); + if (rc != NO_ERROR) + { + return; + } + rc = DosQueryProcAddr(module, 986, NULL, (PFN*) &myDosSetFileLocksL); + if (rc != NO_ERROR) + { + return; + } + rc = DosQueryProcAddr(module, 988, NULL, (PFN*) &myDosSetFilePtrL); + if (rc != NO_ERROR) + { + return; + } + isWSEB = PR_TRUE; +} + +PRStatus +_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PRInt32 rv; + ULONG count; + + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks); + rv = DosWaitEventSem(thread->md.blocked_sema, msecs); + DosResetEventSem(thread->md.blocked_sema, &count); + switch(rv) + { + case NO_ERROR: + return PR_SUCCESS; + break; + case ERROR_TIMEOUT: + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + ; + } else { + if (thread->wait.cvar != NULL) { + thread->wait.cvar = NULL; + _PR_THREAD_UNLOCK(thread); + } else { + /* The CVAR was notified just as the timeout + * occurred. This led to us being notified twice. + * call SemRequest() to clear the semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = DosWaitEventSem(thread->md.blocked_sema, 0); + DosResetEventSem(thread->md.blocked_sema, &count); + PR_ASSERT(rv == NO_ERROR); + } + } + return PR_SUCCESS; + break; + default: + break; + } + return PR_FAILURE; +} +PRStatus +_PR_MD_WAKEUP_WAITER(PRThread *thread) +{ + if ( _PR_IS_NATIVE_THREAD(thread) ) + { + if (DosPostEventSem(thread->md.blocked_sema) != NO_ERROR) + return PR_FAILURE; + else + return PR_SUCCESS; + } +} + + +/* --- FILE IO ----------------------------------------------------------- */ +/* + * _PR_MD_OPEN() -- Open a file + * + * returns: a fileHandle + * + * The NSPR open flags (osflags) are translated into flags for OS/2 + * + * Mode seems to be passed in as a unix style file permissions argument + * as in 0666, in the case of opening the logFile. + * + */ +PRInt32 +_PR_MD_OPEN(const char *name, PRIntn osflags, int mode) +{ + HFILE file; + PRInt32 access = OPEN_SHARE_DENYNONE; + PRInt32 flags = 0L; + APIRET rc = 0; + PRUword actionTaken; + +#ifdef MOZ_OS2_HIGH_MEMORY + /* + * All the pointer arguments (&file, &actionTaken and name) have to be in + * low memory for DosOpen to use them. + * The following moves name to low memory. + */ + if ((ULONG)name >= 0x20000000) + { + size_t len = strlen(name) + 1; + char *copy = (char *)alloca(len); + memcpy(copy, name, len); + name = copy; + } +#endif + + if (osflags & PR_SYNC) access |= OPEN_FLAGS_WRITE_THROUGH; + + if (osflags & PR_RDONLY) + access |= OPEN_ACCESS_READONLY; + else if (osflags & PR_WRONLY) + access |= OPEN_ACCESS_WRITEONLY; + else if(osflags & PR_RDWR) + access |= OPEN_ACCESS_READWRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + { + flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS; + } + else if (osflags & PR_CREATE_FILE) + { + if (osflags & PR_TRUNCATE) + flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS; + else + flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + } + else + { + if (osflags & PR_TRUNCATE) + flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS; + else + flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + } + + do { + if (isWSEB) + { + rc = myDosOpenL((char*)name, + &file, /* file handle if successful */ + &actionTaken, /* reason for failure */ + 0, /* initial size of new file */ + FILE_NORMAL, /* file system attributes */ + flags, /* Open flags */ + access, /* Open mode and rights */ + 0); /* OS/2 Extended Attributes */ + } + else + { + rc = DosOpen((char*)name, + &file, /* file handle if successful */ + &actionTaken, /* reason for failure */ + 0, /* initial size of new file */ + FILE_NORMAL, /* file system attributes */ + flags, /* Open flags */ + access, /* Open mode and rights */ + 0); /* OS/2 Extended Attributes */ + }; + if (rc == ERROR_TOO_MANY_OPEN_FILES) { + ULONG CurMaxFH = 0; + LONG ReqCount = 20; + APIRET rc2; + rc2 = DosSetRelMaxFH(&ReqCount, &CurMaxFH); + if (rc2 != NO_ERROR) { + break; + } + } + } while (rc == ERROR_TOO_MANY_OPEN_FILES); + + if (rc != NO_ERROR) { + _PR_MD_MAP_OPEN_ERROR(rc); + return -1; + } + + return (PRInt32)file; +} + +PRInt32 +_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) +{ + ULONG bytes; + int rv; + + rv = DosRead((HFILE)fd->secret->md.osfd, + (PVOID)buf, + len, + &bytes); + + if (rv != NO_ERROR) + { + /* ERROR_HANDLE_EOF can only be returned by async io */ + PR_ASSERT(rv != ERROR_HANDLE_EOF); + if (rv == ERROR_BROKEN_PIPE) + return 0; + else { + _PR_MD_MAP_READ_ERROR(rv); + return -1; + } + } + return (PRInt32)bytes; +} + +PRInt32 +_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) +{ + PRInt32 bytes; + int rv; + + rv = DosWrite((HFILE)fd->secret->md.osfd, + (PVOID)buf, + len, + (PULONG)&bytes); + + if (rv != NO_ERROR) + { + _PR_MD_MAP_WRITE_ERROR(rv); + return -1; + } + + if (len != bytes) { + rv = ERROR_DISK_FULL; + _PR_MD_MAP_WRITE_ERROR(rv); + return -1; + } + + return bytes; +} /* --- end _PR_MD_WRITE() --- */ + +PRInt32 +_PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) +{ + PRInt32 rv; + PRUword newLocation; + + rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation); + + if (rv != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(rv); + return -1; + } else + return newLocation; +} + +PRInt64 +_PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) +{ +#ifdef NO_LONG_LONG + PRInt64 result; + PRInt32 rv, low = offset.lo, hi = offset.hi; + PRUword newLocation; + + rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation); + rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation); + + if (rv != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(rv); + hi = newLocation = -1; + } + + result.lo = newLocation; + result.hi = hi; + return result; + +#else + PRInt32 where, rc, lo = (PRInt32)offset, hi = (PRInt32)(offset >> 32); + PRUint64 rv; + PRUint32 newLocation, uhi; + PRUint64 newLocationL; + + switch (whence) + { + case PR_SEEK_SET: + where = FILE_BEGIN; + break; + case PR_SEEK_CUR: + where = FILE_CURRENT; + break; + case PR_SEEK_END: + where = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (isWSEB) + { + rc = myDosSetFilePtrL((HFILE)fd->secret->md.osfd, offset, where, (PLONGLONG)&newLocationL); + } + else + { + rc = DosSetFilePtr((HFILE)fd->secret->md.osfd, lo, where, (PULONG)&newLocation); + } + + if (rc != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(rc); + return -1; + } + + if (isWSEB) + { + return newLocationL; + } + + uhi = (PRUint32)hi; + PR_ASSERT((PRInt32)uhi >= 0); + rv = uhi; + PR_ASSERT((PRInt64)rv >= 0); + rv = (rv << 32); + PR_ASSERT((PRInt64)rv >= 0); + rv += newLocation; + PR_ASSERT((PRInt64)rv >= 0); + return (PRInt64)rv; +#endif +} + +PRInt32 +_PR_MD_FSYNC(PRFileDesc *fd) +{ + PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd); + + if (rc != NO_ERROR) { + if (rc != ERROR_ACCESS_DENIED) { + _PR_MD_MAP_FSYNC_ERROR(rc); + return -1; + } + } + return 0; +} + +PRInt32 +_MD_CloseFile(PRInt32 osfd) +{ + PRInt32 rv; + + rv = DosClose((HFILE)osfd); + if (rv != NO_ERROR) + _PR_MD_MAP_CLOSE_ERROR(rv); + return rv; +} + + +/* --- DIR IO ------------------------------------------------------------ */ +#define GetFileFromDIR(d) (isWSEB?(d)->d_entry.large.achName:(d)->d_entry.small.achName) +#define GetFileAttr(d) (isWSEB?(d)->d_entry.large.attrFile:(d)->d_entry.small.attrFile) + +void FlipSlashes(char *cp, int len) +{ + while (--len >= 0) { + if (cp[0] == '/') { + cp[0] = PR_DIRECTORY_SEPARATOR; + } + cp++; + } +} + +/* +** +** Local implementations of standard Unix RTL functions which are not provided +** by the VAC RTL. +** +*/ + +PRInt32 +_PR_MD_CLOSE_DIR(_MDDir *d) +{ + PRInt32 rc; + + if ( d ) { + rc = DosFindClose(d->d_hdl); + if(rc == NO_ERROR){ + d->magic = (PRUint32)-1; + return PR_SUCCESS; + } else { + _PR_MD_MAP_CLOSEDIR_ERROR(rc); + return PR_FAILURE; + } + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; +} + + +PRStatus +_PR_MD_OPEN_DIR(_MDDir *d, const char *name) +{ + char filename[ CCHMAXPATH ]; + PRUword numEntries, rc; + + numEntries = 1; + + PR_snprintf(filename, CCHMAXPATH, "%s%s%s", + name, PR_DIRECTORY_SEPARATOR_STR, "*.*"); + FlipSlashes( filename, strlen(filename) ); + + d->d_hdl = HDIR_CREATE; + + if (isWSEB) + { + rc = DosFindFirst( filename, + &d->d_hdl, + FILE_DIRECTORY | FILE_HIDDEN, + &(d->d_entry.large), + sizeof(d->d_entry.large), + &numEntries, + FIL_STANDARDL); + } + else + { + rc = DosFindFirst( filename, + &d->d_hdl, + FILE_DIRECTORY | FILE_HIDDEN, + &(d->d_entry.small), + sizeof(d->d_entry.small), + &numEntries, + FIL_STANDARD); + } + if ( rc != NO_ERROR ) { + _PR_MD_MAP_OPENDIR_ERROR(rc); + return PR_FAILURE; + } + d->firstEntry = PR_TRUE; + d->magic = _MD_MAGIC_DIR; + return PR_SUCCESS; +} + +char * +_PR_MD_READ_DIR(_MDDir *d, PRIntn flags) +{ + PRUword numFiles = 1; + BOOL rv; + char *fileName; + USHORT fileAttr; + + if ( d ) { + while (1) { + if (d->firstEntry) { + d->firstEntry = PR_FALSE; + rv = NO_ERROR; + } else { + rv = DosFindNext(d->d_hdl, + &(d->d_entry), + sizeof(d->d_entry), + &numFiles); + } + if (rv != NO_ERROR) { + break; + } + fileName = GetFileFromDIR(d); + fileAttr = GetFileAttr(d); + if ( (flags & PR_SKIP_DOT) && + (fileName[0] == '.') && (fileName[1] == '\0')) + continue; + if ( (flags & PR_SKIP_DOT_DOT) && + (fileName[0] == '.') && (fileName[1] == '.') && + (fileName[2] == '\0')) + continue; + /* + * XXX + * Is this the correct definition of a hidden file on OS/2? + */ + if ((flags & PR_SKIP_NONE) && (fileAttr & FILE_HIDDEN)) + return fileName; + else if ((flags & PR_SKIP_HIDDEN) && (fileAttr & FILE_HIDDEN)) + continue; + return fileName; + } + PR_ASSERT(NO_ERROR != rv); + _PR_MD_MAP_READDIR_ERROR(rv); + return NULL; + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; +} + +PRInt32 +_PR_MD_DELETE(const char *name) +{ + PRInt32 rc = DosDelete((char*)name); + if(rc == NO_ERROR) { + return 0; + } else { + _PR_MD_MAP_DELETE_ERROR(rc); + return -1; + } +} + +PRInt32 +_PR_MD_STAT(const char *fn, struct stat *info) +{ + PRInt32 rv; + char filename[CCHMAXPATH]; + + PR_snprintf(filename, CCHMAXPATH, "%s", fn); + FlipSlashes(filename, strlen(filename)); + + rv = _stat((char*)filename, info); + if (-1 == rv) { + /* + * Check for MSVC runtime library _stat() bug. + * (It's really a bug in FindFirstFile().) + * If a pathname ends in a backslash or slash, + * e.g., c:\temp\ or c:/temp/, _stat() will fail. + * Note: a pathname ending in a slash (e.g., c:/temp/) + * can be handled by _stat() on NT but not on Win95. + * + * We remove the backslash or slash at the end and + * try again. + * + * Not sure if this happens on OS/2 or not, + * but it doesn't hurt to be careful. + */ + + int len = strlen(fn); + if (len > 0 && len <= _MAX_PATH + && (fn[len - 1] == '\\' || fn[len - 1] == '/')) { + char newfn[_MAX_PATH + 1]; + + strcpy(newfn, fn); + newfn[len - 1] = '\0'; + rv = _stat(newfn, info); + } + } + + if (-1 == rv) { + _PR_MD_MAP_STAT_ERROR(errno); + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) +{ + struct stat sb; + PRInt32 rv; + PRInt64 s, s2us; + + if ( (rv = _PR_MD_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; + 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; + } + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) +{ + PRFileInfo info32; + PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32); + if (rv != 0) + { + return rv; + } + info->type = info32.type; + LL_UI2L(info->size,info32.size); + info->modifyTime = info32.modifyTime; + info->creationTime = info32.creationTime; + + if (isWSEB) + { + APIRET rc ; + FILESTATUS3L fstatus; + + rc = DosQueryPathInfo(fn, FIL_STANDARDL, &fstatus, sizeof(fstatus)); + + if (NO_ERROR != rc) + { + _PR_MD_MAP_OPEN_ERROR(rc); + return -1; + } + + if (! (fstatus.attrFile & FILE_DIRECTORY)) + { + info->size = fstatus.cbFile; + } + } + + return rv; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) +{ + /* For once, the VAC compiler/library did a nice thing. + * The file handle used by the C runtime is the same one + * returned by the OS when you call DosOpen(). This means + * that you can take an OS HFILE and use it with C file + * functions. The only caveat is that you have to call + * _setmode() first to initialize some junk. This is + * immensely useful because I did not have a clue how to + * implement this function otherwise. The windows folks + * took the source from the Microsoft C library source, but + * IBM wasn't kind enough to ship the source with VAC. + * On second thought, the needed function could probably + * be gotten from the OS/2 GNU library source, but the + * point is now moot. + */ + struct stat hinfo; + PRInt64 s, s2us; + + _setmode(fd->secret->md.osfd, O_BINARY); + if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) { + _PR_MD_MAP_FSTAT_ERROR(errno); + return -1; + } + + if (hinfo.st_mode & S_IFDIR) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_FILE; + + info->size = hinfo.st_size; + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, hinfo.st_mtime); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, hinfo.st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; + + return 0; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + PRFileInfo info32; + PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32); + if (0 == rv) + { + info->type = info32.type; + LL_UI2L(info->size,info32.size); + + info->modifyTime = info32.modifyTime; + info->creationTime = info32.creationTime; + } + + if (isWSEB) + { + APIRET rc ; + FILESTATUS3L fstatus; + + rc = DosQueryFileInfo(fd->secret->md.osfd, FIL_STANDARDL, &fstatus, sizeof(fstatus)); + + if (NO_ERROR != rc) + { + _PR_MD_MAP_OPEN_ERROR(rc); + return -1; + } + + if (! (fstatus.attrFile & FILE_DIRECTORY)) + { + info->size = fstatus.cbFile; + } + } + + return rv; +} + + +PRInt32 +_PR_MD_RENAME(const char *from, const char *to) +{ + PRInt32 rc; + /* Does this work with dot-relative pathnames? */ + if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) { + return 0; + } else { + _PR_MD_MAP_RENAME_ERROR(rc); + return -1; + } +} + +PRInt32 +_PR_MD_ACCESS(const char *name, PRAccessHow how) +{ + PRInt32 rv; + switch (how) { + case PR_ACCESS_WRITE_OK: + rv = access(name, 02); + break; + case PR_ACCESS_READ_OK: + rv = access(name, 04); + break; + case PR_ACCESS_EXISTS: + return access(name, 00); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (rv < 0) + _PR_MD_MAP_ACCESS_ERROR(errno); + return rv; +} + +PRInt32 +_PR_MD_MKDIR(const char *name, PRIntn mode) +{ + PRInt32 rc; + /* XXXMB - how to translate the "mode"??? */ + if ((rc = DosCreateDir((char *)name, NULL))== NO_ERROR) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(rc); + return -1; + } +} + +PRInt32 +_PR_MD_RMDIR(const char *name) +{ + PRInt32 rc; + if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) { + return 0; + } else { + _PR_MD_MAP_RMDIR_ERROR(rc); + return -1; + } +} + +PRStatus +_PR_MD_LOCKFILE(PRInt32 f) +{ + PRInt32 rv; + FILELOCK lock, unlock; + FILELOCKL lockL, unlockL; + + lock.lOffset = 0; + lockL.lOffset = 0; + lock.lRange = 0xffffffff; + lockL.lRange = 0xffffffffffffffff; + unlock.lOffset = 0; + unlock.lRange = 0; + unlockL.lOffset = 0; + unlockL.lRange = 0; + + /* + * loop trying to DosSetFileLocks(), + * pause for a few miliseconds when can't get the lock + * and try again + */ + for( rv = FALSE; rv == FALSE; /* do nothing */ ) + { + if (isWSEB) + { + rv = myDosSetFileLocksL( (HFILE) f, + &unlockL, &lockL, + 0, 0); + } + else + { + rv = DosSetFileLocks( (HFILE) f, + &unlock, &lock, + 0, 0); + } + if ( rv != NO_ERROR ) + { + DosSleep( 50 ); /* Sleep() a few milisecs and try again. */ + } + } /* end for() */ + return PR_SUCCESS; +} /* end _PR_MD_LOCKFILE() */ + +PRStatus +_PR_MD_TLOCKFILE(PRInt32 f) +{ + return _PR_MD_LOCKFILE(f); +} /* end _PR_MD_TLOCKFILE() */ + + +PRStatus +_PR_MD_UNLOCKFILE(PRInt32 f) +{ + PRInt32 rv; + FILELOCK lock, unlock; + FILELOCKL lockL, unlockL; + + lock.lOffset = 0; + lockL.lOffset = 0; + lock.lRange = 0; + lockL.lRange = 0; + unlock.lOffset = 0; + unlockL.lOffset = 0; + unlock.lRange = 0xffffffff; + unlockL.lRange = 0xffffffffffffffff; + + if (isWSEB) + { + rv = myDosSetFileLocksL( (HFILE) f, + &unlockL, &lockL, + 0, 0); + } + else + { + rv = DosSetFileLocks( (HFILE) f, + &unlock, &lock, + 0, 0); + } + + if ( rv != NO_ERROR ) + { + return PR_SUCCESS; + } + else + { + return PR_FAILURE; + } +} /* end _PR_MD_UNLOCKFILE() */ + +PRStatus +_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) +{ + APIRET rc = 0; + ULONG flags; + switch (fd->methods->file_type) + { + case PR_DESC_PIPE: + case PR_DESC_FILE: + rc = DosQueryFHState((HFILE)fd->secret->md.osfd, &flags); + if (rc != NO_ERROR) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + + if (inheritable) + flags &= ~OPEN_FLAGS_NOINHERIT; + else + flags |= OPEN_FLAGS_NOINHERIT; + + /* Mask off flags DosSetFHState don't want. */ + flags &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT); + rc = DosSetFHState((HFILE)fd->secret->md.osfd, flags); + if (rc != NO_ERROR) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + break; + + case PR_DESC_LAYERED: + /* what to do here? */ + PR_SetError(PR_UNKNOWN_ERROR, 87 /*ERROR_INVALID_PARAMETER*/); + return PR_FAILURE; + + case PR_DESC_SOCKET_TCP: + case PR_DESC_SOCKET_UDP: + /* These are global on OS/2. */ + break; + } + + return PR_SUCCESS; +} + +void +_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) +{ + /* XXX this function needs to be implemented */ + fd->secret->inheritable = _PR_TRI_UNKNOWN; +} + +void +_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) +{ + /* XXX this function needs to be reviewed */ + ULONG flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + if (DosQueryFHState((HFILE)fd->secret->md.osfd, &flags) == 0) { + if (flags & OPEN_FLAGS_NOINHERIT) { + fd->secret->inheritable = _PR_TRI_FALSE; + } else { + fd->secret->inheritable = _PR_TRI_TRUE; + } + } +} diff --git a/nsprpub/pr/src/md/os2/os2misc.c b/nsprpub/pr/src/md/os2/os2misc.c new file mode 100644 index 00000000000..3021b23dafe --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2misc.c @@ -0,0 +1,588 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Davide Bresolin + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * os2misc.c + * + */ + +#ifdef MOZ_OS2_HIGH_MEMORY +/* os2safe.h has to be included before os2.h, needed for high mem */ +#include +#endif + +#include +#include "primpl.h" + +extern int _CRT_init(void); +extern void _CRT_term(void); +extern void __ctordtorInit(int flag); +extern void __ctordtorTerm(int flag); + +char * +_PR_MD_GET_ENV(const char *name) +{ + return getenv(name); +} + +PRIntn +_PR_MD_PUT_ENV(const char *name) +{ + return putenv(name); +} + + +/* + ************************************************************************** + ************************************************************************** + ** + ** Date and time routines + ** + ************************************************************************** + ************************************************************************** + */ + +#include +/* + *----------------------------------------------------------------------- + * + * PR_Now -- + * + * Returns the current time in microseconds since the epoch. + * The epoch is midnight January 1, 1970 GMT. + * The implementation is machine dependent. This is the + * implementation for OS/2. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRTime) +PR_Now(void) +{ + PRInt64 s, ms, ms2us, s2us; + struct timeb b; + + ftime(&b); + LL_I2L(ms2us, PR_USEC_PER_MSEC); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, b.time); + LL_I2L(ms, b.millitm); + LL_MUL(ms, ms, ms2us); + LL_MUL(s, s, s2us); + LL_ADD(s, s, ms); + return s; +} + + +/* + *********************************************************************** + *********************************************************************** + * + * Process creation routines + * + *********************************************************************** + *********************************************************************** + */ + +/* + * Assemble the command line by concatenating the argv array. + * Special characters intentionally do not get escaped, and it is + * expected that the caller wraps arguments in quotes if needed + * (e.g. for filename with spaces). + * + * On success, this function returns 0 and the resulting command + * line is returned in *cmdLine. On failure, it returns -1. + */ +static int assembleCmdLine(char *const *argv, char **cmdLine) +{ + char *const *arg; + int cmdLineSize; + + /* + * Find out how large the command line buffer should be. + */ + cmdLineSize = 1; /* final null */ + for (arg = argv+1; *arg; arg++) { + cmdLineSize += strlen(*arg) + 1; /* space in between */ + } + *cmdLine = PR_MALLOC(cmdLineSize); + if (*cmdLine == NULL) { + return -1; + } + + (*cmdLine)[0] = '\0'; + + for (arg = argv+1; *arg; arg++) { + if (arg > argv +1) { + strcat(*cmdLine, " "); + } + strcat(*cmdLine, *arg); + } + return 0; +} + +/* + * Assemble the environment block by concatenating the envp array + * (preserving the terminating null byte in each array element) + * and adding a null byte at the end. + * + * Returns 0 on success. The resulting environment block is returned + * in *envBlock. Note that if envp is NULL, a NULL pointer is returned + * in *envBlock. Returns -1 on failure. + */ +static int assembleEnvBlock(char **envp, char **envBlock) +{ + char *p; + char *q; + char **env; + char *curEnv; + char *cwdStart, *cwdEnd; + int envBlockSize; + + PPIB ppib = NULL; + PTIB ptib = NULL; + + if (envp == NULL) { + *envBlock = NULL; + return 0; + } + + if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) + return -1; + + curEnv = ppib->pib_pchenv; + + cwdStart = curEnv; + while (*cwdStart) { + if (cwdStart[0] == '=' && cwdStart[1] != '\0' + && cwdStart[2] == ':' && cwdStart[3] == '=') { + break; + } + cwdStart += strlen(cwdStart) + 1; + } + cwdEnd = cwdStart; + if (*cwdEnd) { + cwdEnd += strlen(cwdEnd) + 1; + while (*cwdEnd) { + if (cwdEnd[0] != '=' || cwdEnd[1] == '\0' + || cwdEnd[2] != ':' || cwdEnd[3] != '=') { + break; + } + cwdEnd += strlen(cwdEnd) + 1; + } + } + envBlockSize = cwdEnd - cwdStart; + + for (env = envp; *env; env++) { + envBlockSize += strlen(*env) + 1; + } + envBlockSize++; + + p = *envBlock = PR_MALLOC(envBlockSize); + if (p == NULL) { + return -1; + } + + q = cwdStart; + while (q < cwdEnd) { + *p++ = *q++; + } + + for (env = envp; *env; env++) { + q = *env; + while (*q) { + *p++ = *q++; + } + *p++ = '\0'; + } + *p = '\0'; + return 0; +} + +/* + * For qsort. We sort (case-insensitive) the environment strings + * before generating the environment block. + */ +static int compare(const void *arg1, const void *arg2) +{ + return stricmp(* (char**)arg1, * (char**)arg2); +} + +PRProcess * _PR_CreateOS2Process( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + PRProcess *proc = NULL; + char *cmdLine = NULL; + char **newEnvp = NULL; + char *envBlock = NULL; + + STARTDATA startData = {0}; + APIRET rc; + ULONG ulAppType = 0; + PID pid = 0; + char *pszComSpec; + char pszEXEName[CCHMAXPATH] = ""; + char pszFormatString[CCHMAXPATH]; + char pszObjectBuffer[CCHMAXPATH]; + char *pszFormatResult = NULL; + + /* + * Variables for DosExecPgm + */ + char szFailed[CCHMAXPATH]; + char *pszCmdLine = NULL; + RESULTCODES procInfo; + HFILE hStdIn = 0, + hStdOut = 0, + hStdErr = 0; + HFILE hStdInSave = -1, + hStdOutSave = -1, + hStdErrSave = -1; + + proc = PR_NEW(PRProcess); + if (!proc) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + if (assembleCmdLine(argv, &cmdLine) == -1) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + +#ifdef MOZ_OS2_HIGH_MEMORY + /* + * DosQueryAppType() fails if path (the char* in the first argument) is in + * high memory. If that is the case, the following moves it to low memory. + */ + if ((ULONG)path >= 0x20000000) { + size_t len = strlen(path) + 1; + char *copy = (char *)alloca(len); + memcpy(copy, path, len); + path = copy; + } +#endif + + if (envp == NULL) { + newEnvp = NULL; + } else { + int i; + int numEnv = 0; + while (envp[numEnv]) { + numEnv++; + } + newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *)); + for (i = 0; i <= numEnv; i++) { + newEnvp[i] = envp[i]; + } + qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare); + } + if (assembleEnvBlock(newEnvp, &envBlock) == -1) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + rc = DosQueryAppType(path, &ulAppType); + if (rc != NO_ERROR) { + char *pszDot = strrchr(path, '.'); + if (pszDot) { + /* If it is a CMD file, launch the users command processor */ + if (!stricmp(pszDot, ".cmd")) { + rc = DosScanEnv("COMSPEC", (PSZ *)&pszComSpec); + if (!rc) { + strcpy(pszFormatString, "/C %s %s"); + strcpy(pszEXEName, pszComSpec); + ulAppType = FAPPTYP_WINDOWCOMPAT; + } + } + } + } + if (ulAppType == 0) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + goto errorExit; + } + + if ((ulAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) { + startData.SessionType = SSF_TYPE_PM; + } + else if (ulAppType & FAPPTYP_WINDOWCOMPAT) { + startData.SessionType = SSF_TYPE_WINDOWABLEVIO; + } + else { + startData.SessionType = SSF_TYPE_DEFAULT; + } + + if (ulAppType & (FAPPTYP_WINDOWSPROT31 | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSREAL)) + { + strcpy(pszEXEName, "WINOS2.COM"); + startData.SessionType = PROG_31_STDSEAMLESSVDM; + strcpy(pszFormatString, "/3 %s %s"); + } + + startData.InheritOpt = SSF_INHERTOPT_SHELL; + + if (pszEXEName[0]) { + pszFormatResult = PR_MALLOC(strlen(pszFormatString)+strlen(path)+strlen(cmdLine)); + sprintf(pszFormatResult, pszFormatString, path, cmdLine); + startData.PgmInputs = pszFormatResult; + } else { + strcpy(pszEXEName, path); + startData.PgmInputs = cmdLine; + } + startData.PgmName = pszEXEName; + + startData.Length = sizeof(startData); + startData.Related = SSF_RELATED_INDEPENDENT; + startData.ObjectBuffer = pszObjectBuffer; + startData.ObjectBuffLen = CCHMAXPATH; + startData.Environment = envBlock; + + if (attr) { + /* On OS/2, there is really no way to pass file handles for stdin, + * stdout, and stderr to a new process. Instead, we can make it + * a child process and make the given file handles a copy of our + * stdin, stdout, and stderr. The child process then inherits + * ours, and we set ours back. Twisted and gross I know. If you + * know a better way, please use it. + */ + if (attr->stdinFd) { + hStdIn = 0; + DosDupHandle(hStdIn, &hStdInSave); + DosDupHandle((HFILE) attr->stdinFd->secret->md.osfd, &hStdIn); + } + + if (attr->stdoutFd) { + hStdOut = 1; + DosDupHandle(hStdOut, &hStdOutSave); + DosDupHandle((HFILE) attr->stdoutFd->secret->md.osfd, &hStdOut); + } + + if (attr->stderrFd) { + hStdErr = 2; + DosDupHandle(hStdErr, &hStdErrSave); + DosDupHandle((HFILE) attr->stderrFd->secret->md.osfd, &hStdErr); + } + /* + * Build up the Command Line for DosExecPgm + */ + pszCmdLine = PR_MALLOC(strlen(pszEXEName) + + strlen(startData.PgmInputs) + 3); + sprintf(pszCmdLine, "%s%c%s%c", pszEXEName, '\0', + startData.PgmInputs, '\0'); + rc = DosExecPgm(szFailed, + CCHMAXPATH, + EXEC_ASYNCRESULT, + pszCmdLine, + envBlock, + &procInfo, + pszEXEName); + PR_DELETE(pszCmdLine); + + /* Restore our old values. Hope this works */ + if (hStdInSave != -1) { + DosDupHandle(hStdInSave, &hStdIn); + DosClose(hStdInSave); + } + + if (hStdOutSave != -1) { + DosDupHandle(hStdOutSave, &hStdOut); + DosClose(hStdOutSave); + } + + if (hStdErrSave != -1) { + DosDupHandle(hStdErrSave, &hStdErr); + DosClose(hStdErrSave); + } + + if (rc != NO_ERROR) { + /* XXX what error code? */ + PR_SetError(PR_UNKNOWN_ERROR, rc); + goto errorExit; + } + + proc->md.pid = procInfo.codeTerminate; + } else { + /* + * If no STDIN/STDOUT redirection is not needed, use DosStartSession + * to create a new, independent session + */ + rc = DosStartSession(&startData, &ulAppType, &pid); + + if ((rc != NO_ERROR) && (rc != ERROR_SMG_START_IN_BACKGROUND)) { + PR_SetError(PR_UNKNOWN_ERROR, rc); + goto errorExit; + } + + proc->md.pid = pid; + } + + if (pszFormatResult) { + PR_DELETE(pszFormatResult); + } + + PR_DELETE(cmdLine); + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (envBlock) { + PR_DELETE(envBlock); + } + return proc; + +errorExit: + if (cmdLine) { + PR_DELETE(cmdLine); + } + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (envBlock) { + PR_DELETE(envBlock); + } + if (proc) { + PR_DELETE(proc); + } + return NULL; +} /* _PR_CreateOS2Process */ + +PRStatus _PR_DetachOS2Process(PRProcess *process) +{ + /* On OS/2, a process is either created as a child or not. + * You can't 'detach' it later on. + */ + PR_DELETE(process); + return PR_SUCCESS; +} + +/* + * XXX: This will currently only work on a child process. + */ +PRStatus _PR_WaitOS2Process(PRProcess *process, + PRInt32 *exitCode) +{ + ULONG ulRetVal; + RESULTCODES results; + PID pidEnded = 0; + + ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, + &results, + &pidEnded, process->md.pid); + + if (ulRetVal != NO_ERROR) { + printf("\nDosWaitChild rc = %lu\n", ulRetVal); + PR_SetError(PR_UNKNOWN_ERROR, ulRetVal); + return PR_FAILURE; + } + PR_DELETE(process); + return PR_SUCCESS; +} + +PRStatus _PR_KillOS2Process(PRProcess *process) +{ + ULONG ulRetVal; + if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) { + return PR_SUCCESS; + } + PR_SetError(PR_UNKNOWN_ERROR, ulRetVal); + return PR_FAILURE; +} + +PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen) +{ + PRIntn rv; + + rv = gethostname(name, (PRInt32) namelen); + if (0 == rv) { + return PR_SUCCESS; + } + _PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno()); + return PR_FAILURE; +} + +void +_PR_MD_WAKEUP_CPUS( void ) +{ + return; +} + + +/* + ********************************************************************** + * + * Memory-mapped files are not supported on OS/2 (or Win16). + * + ********************************************************************** + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRInt32 _MD_GetMemMapAlignment(void) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +void * _MD_MemMap( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + diff --git a/nsprpub/pr/src/md/os2/os2poll.c b/nsprpub/pr/src/md/os2/os2poll.c new file mode 100644 index 00000000000..9151b9c6705 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2poll.c @@ -0,0 +1,382 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file implements _PR_MD_PR_POLL for OS/2. + */ + +#ifdef XP_OS2_EMX + #include /* For timeval. */ +#endif + +#include "primpl.h" + +#ifndef BSD_SELECT +/* Utility functions called when using OS/2 select */ + +PRBool IsSocketSet( PRInt32 osfd, int* socks, int start, int count ) +{ + int i; + PRBool isSet = PR_FALSE; + + for( i = start; i < start+count; i++ ) + { + if( socks[i] == osfd ) + isSet = PR_TRUE; + } + + return isSet; +} +#endif + +PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ +#ifdef BSD_SELECT + fd_set rd, wt, ex; +#else + int rd, wt, ex; + int* socks; + unsigned long msecs; + int i, j; +#endif + PRFileDesc *bottom; + PRPollDesc *pd, *epd; + PRInt32 maxfd = -1, ready, err; + PRIntervalTime remaining, elapsed, start; + +#ifdef BSD_SELECT + struct timeval tv, *tvp = NULL; + + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); +#else + rd = 0; + wt = 0; + ex = 0; + socks = (int) PR_MALLOC( npds * 3 * sizeof(int) ); + + if (!socks) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } +#endif + + 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; +#ifdef BSD_SELECT + FD_SET(osfd, &rd); +#else + socks[rd] = osfd; + rd++; +#endif + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; +#ifdef BSD_SELECT + FD_SET(osfd, &wt); +#else + socks[npds+wt] = osfd; + wt++; +#endif + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; +#ifdef BSD_SELECT + FD_SET(osfd, &rd); +#else + socks[rd] = osfd; + rd++; +#endif + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; +#ifdef BSD_SELECT + FD_SET(osfd, &wt); +#else + socks[npds+wt] = osfd; + wt++; +#endif + } + if (pd->in_flags & PR_POLL_EXCEPT) + { +#ifdef BSD_SELECT + FD_SET(osfd, &ex); +#else + socks[npds*2+ex] = osfd; + ex++; +#endif + } + } + } + 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 */ + } + } + } + else + { + pd->out_flags = 0; + } + } + + if (0 != ready) + { +#ifndef BSD_SELECT + PR_Free(socks); +#endif + return ready; /* no need to block */ + } + + remaining = timeout; + start = PR_IntervalNow(); + +retry: +#ifdef BSD_SELECT + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = remaining / ticksPerSecond; + tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); + tvp = &tv; + } + + ready = bsdselect(maxfd + 1, &rd, &wt, &ex, tvp); +#else + switch (timeout) + { + case PR_INTERVAL_NO_WAIT: + msecs = 0; + break; + case PR_INTERVAL_NO_TIMEOUT: + msecs = -1; + break; + default: + msecs = PR_IntervalToMilliseconds(remaining); + } + + /* compact array */ + for( i = rd, j = npds; j < npds+wt; i++,j++ ) + socks[i] = socks[j]; + for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ ) + socks[i] = socks[j]; + + ready = os2_select(socks, rd, wt, ex, msecs); +#endif + + 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; + +#ifdef BSD_SELECT + if (FD_ISSET(osfd, &rd)) +#else + if( IsSocketSet(osfd, socks, 0, rd) ) +#endif + { + 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; + } + +#ifdef BSD_SELECT + if (FD_ISSET(osfd, &wt)) +#else + if( IsSocketSet(osfd, socks, rd, wt) ) +#endif + { + 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; + } + +#ifdef BSD_SELECT + if (FD_ISSET(osfd, &ex)) +#else + if( IsSocketSet(osfd, socks, rd+wt, ex) ) +#endif + { + 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 */ + int optval; + int optlen = sizeof(optval); + 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 (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, + SO_TYPE, (char *) &optval, &optlen) == -1) + { + PR_ASSERT(sock_errno() == ENOTSOCK); + if (sock_errno() == ENOTSOCK) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } + } + } + } + PR_ASSERT(ready > 0); + } + else + _PR_MD_MAP_SELECT_ERROR(err); + } + +#ifndef BSD_SELECT + PR_Free(socks); +#endif + return ready; +} + diff --git a/nsprpub/pr/src/md/os2/os2rng.c b/nsprpub/pr/src/md/os2/os2rng.c new file mode 100644 index 00000000000..1c3a7b7abe8 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2rng.c @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#define INCL_DOS +#define INCL_DOSERRORS +#include +#include +#include +#include "primpl.h" + +static BOOL clockTickTime(unsigned long *phigh, unsigned long *plow) +{ + APIRET rc = NO_ERROR; + QWORD qword = {0,0}; + + rc = DosTmrQueryTime(&qword); + if (rc != NO_ERROR) + return FALSE; + + *phigh = qword.ulHi; + *plow = qword.ulLo; + + return TRUE; +} + +extern PRSize _PR_MD_GetRandomNoise(void *buf, PRSize size ) +{ + unsigned long high = 0; + unsigned long low = 0; + clock_t val = 0; + int n = 0; + int nBytes = 0; + time_t sTime; + + if (size <= 0) + return 0; + + clockTickTime(&high, &low); + + /* get the maximally changing bits first */ + nBytes = sizeof(low) > size ? size : sizeof(low); + memcpy(buf, &low, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + nBytes = sizeof(high) > size ? size : sizeof(high); + memcpy(((char *)buf) + n, &high, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + /* get the number of milliseconds that have elapsed since application started */ + val = clock(); + + nBytes = sizeof(val) > size ? size : sizeof(val); + memcpy(((char *)buf) + n, &val, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + /* get the time in seconds since midnight Jan 1, 1970 */ + time(&sTime); + nBytes = sizeof(sTime) > size ? size : sizeof(sTime); + memcpy(((char *)buf) + n, &sTime, nBytes); + n += nBytes; + + return n; +} diff --git a/nsprpub/pr/src/md/os2/os2sem.c b/nsprpub/pr/src/md/os2/os2sem.c new file mode 100644 index 00000000000..20b57a828cd --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2sem.c @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * OS/2-specific semaphore handling code. + * + */ + +#include "primpl.h" + + +void +_PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value) +{ + int rv; + + /* Our Sems don't support a value > 1 */ + PR_ASSERT(value <= 1); + + rv = DosCreateEventSem(NULL, &md->sem, 0, 0); + PR_ASSERT(rv == NO_ERROR); +} + +void +_PR_MD_DESTROY_SEM(_MDSemaphore *md) +{ + int rv; + rv = DosCloseEventSem(md->sem); + PR_ASSERT(rv == NO_ERROR); + +} + +PRStatus +_PR_MD_TIMED_WAIT_SEM(_MDSemaphore *md, PRIntervalTime ticks) +{ + int rv; + rv = DosWaitEventSem(md->sem, PR_IntervalToMilliseconds(ticks)); + + if (rv == NO_ERROR) + return PR_SUCCESS; + else + return PR_FAILURE; +} + +PRStatus +_PR_MD_WAIT_SEM(_MDSemaphore *md) +{ + return _PR_MD_TIMED_WAIT_SEM(md, PR_INTERVAL_NO_TIMEOUT); +} + +void +_PR_MD_POST_SEM(_MDSemaphore *md) +{ + int rv; + rv = DosPostEventSem(md->sem); + PR_ASSERT(rv == NO_ERROR); +} + + diff --git a/nsprpub/pr/src/md/os2/os2sock.c b/nsprpub/pr/src/md/os2/os2sock.c new file mode 100644 index 00000000000..3e8d8286ff3 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2sock.c @@ -0,0 +1,684 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* OS/2 Sockets module + * + */ + +/*Note from DSR111297 - it should be noted that there are two flavors of select() on OS/2 */ +/*There is standard BSD (which is kind of slow) and a new flavor of select() that takes */ +/*an integer list of sockets, the number of read sockets, write sockets, except sockets, and */ +/*a millisecond count for timeout. In the interest of performance I have choosen the OS/2 */ +/*specific version of select(). See OS/2 TCP/IP Programmer's Toolkit for more info. */ + +#include "primpl.h" + +#ifdef XP_OS2_EMX + #include /* For timeval. */ +#endif + +#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 +#define READ_FD 1 +#define WRITE_FD 2 + +#ifdef XP_OS2_VACPP +#define _OS2_WRITEV writev +#define _OS2_IOCTL ioctl +#else +#define _OS2_WRITEV so_writev +#define _OS2_IOCTL so_ioctl +#endif + +/* --- SOCKET IO --------------------------------------------------------- */ + + +PRInt32 +_PR_MD_SOCKET(int domain, int type, int flags) +{ + PRInt32 osfd, err; + + osfd = socket(domain, type, flags); + + if (osfd == -1) + { + err = sock_errno(); + _PR_MD_MAP_SOCKET_ERROR(err); + } + + return(osfd); +} + +/* +** _MD_CloseSocket() -- Close a socket +** +*/ +PRInt32 +_MD_CloseSocket(PRInt32 osfd) +{ + PRInt32 rv, err; + + rv = soclose(osfd); + if (rv == -1) { + err = sock_errno(); + _PR_MD_MAP_CLOSE_ERROR(err); + } + return rv; +} + +PRInt32 +_MD_SocketAvailable(PRFileDesc *fd) +{ + PRInt32 result; + + if (_OS2_IOCTL(fd->secret->md.osfd, FIONREAD, (char *) &result, sizeof(result)) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, sock_errno()); + return -1; + } + return result; +} + +static PRInt32 +socket_io_wait( PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout ) +{ + PRInt32 rv = -1; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRInt32 syserror; +#ifdef BSD_SELECT + struct timeval tv; + fd_set rd_wr; +#else + int socks[1]; + long lTimeout; +#endif + + 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. + */ +#ifdef BSD_SELECT + 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 = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv); +#else + lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + do { + socks[0] = osfd; + if (fd_type == READ_FD) + rv = os2_select(socks, 1, 0, 0, lTimeout); + else + rv = os2_select(socks, 0, 1, 0, lTimeout); +#endif + if (rv == -1 && (syserror = sock_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; +#ifdef BSD_SELECT + FD_ZERO(&rd_wr); +#endif + do { + /* + * We block in 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. + */ +#ifdef BSD_SELECT + wait_for_remaining = PR_TRUE; + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + wait_for_remaining = PR_FALSE; + 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 = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv); +#else + wait_for_remaining = PR_TRUE; + lTimeout = PR_IntervalToMilliseconds(remaining); + if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { + wait_for_remaining = PR_FALSE; + lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + } + socks[0] = osfd; + if (fd_type == READ_FD) + rv = os2_select(socks, 1, 0, 0, lTimeout); + else + rv = os2_select(socks, 0, 1, 0, lTimeout); +#endif + /* + * we don't consider EINTR a real error + */ + if (rv == -1 && (syserror = sock_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 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 select timed out, we know how much time + * we spent in blocking, so we can avoid a + * PR_IntervalNow() call. + */ + if (rv == 0) { + if (wait_for_remaining) { + now += remaining; + } else { +#ifdef BSD_SELECT + now += PR_SecondsToInterval(tv.tv_sec) + + PR_MicrosecondsToInterval(tv.tv_usec); +#else + now += PR_MillisecondsToInterval(lTimeout); +#endif + } + } 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 +_MD_Accept(PRFileDesc *fd, PRNetAddr *addr, + 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, (int*)addrlen)) == -1) + { + err = sock_errno(); + if ((err == EWOULDBLOCK) || (err == ECONNABORTED)) + { + if (fd->secret->nonblocking) { + break; + } + 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: + return(rv); +} + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 osfd = fd->secret->md.osfd; + PRNetAddr addrCopy = *addr; /* Work around a bug in OS/2 where connect + * modifies the sockaddr structure. + * See Bugzilla bug 100776. */ + + /* + * We initiate the connection setup by making a nonblocking connect() + * call. If the connect() call fails, there are two cases we handle + * specially: + * 1. The connect() call was interrupted by a signal. In this case + * we simply retry connect(). + * 2. The NSPR socket is nonblocking and connect() fails with + * EINPROGRESS. We first wait until the socket becomes writable. + * Then we try to find out whether the connection setup succeeded + * or failed. + */ + +retry: + if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) + { + err = sock_errno(); + + if (err == EINTR) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + goto retry; + } + + if (!fd->secret->nonblocking && (err == EINPROGRESS)) + { + /* + * socket_io_wait() may return -1 or 1. + */ + + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv == -1) { + return -1; + } + + PR_ASSERT(rv == 1); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + err = _MD_os2_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; + } + return 0; + } + + _PR_MD_MAP_CONNECT_ERROR(err); + } + + return rv; +} /* _MD_connect */ + +PRInt32 +_PR_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 = sock_errno(); + _PR_MD_MAP_BIND_ERROR(err); + } + return(rv); +} + + +PRInt32 +_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv, err; + rv = listen(fd->secret->md.osfd, backlog); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_DEFAULT_ERROR(err); + } + return(rv); +} + + +PRInt32 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((rv = recv(osfd,buf,amount,flags)) == -1) + { + err = sock_errno(); + if ((err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + 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); +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((rv = send(osfd,buf,amount,flags)) == -1) + { + err = sock_errno(); + if ((err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + 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 (socket_io_wait(osfd, WRITE_FD, timeout)< 0) { + rv = -1; + goto done; + } + } + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_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(); + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) + { + err = sock_errno(); + if ((err == EWOULDBLOCK)) + { + if (fd->secret->nonblocking) { + break; + } + 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 +_PR_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, (int *)addrlen)) == -1)) + { + err = sock_errno(); + if ((err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + 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: + return(rv); +} + +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, const 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; indexsecret->nonblocking) { + break; + } + 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 (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; + } + } + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how) +{ + PRInt32 rv; + + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) + _PR_MD_MAP_SHUTDOWN_ERROR(sock_errno()); + return rv; +} + +#ifndef XP_OS2_VACPP +PRInt32 +_PR_MD_SOCKETPAIR(int af, int type, int flags, 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; +} +#endif + +PRStatus +_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getsockname(fd->secret->md.osfd, + (struct sockaddr *) addr, (int *)addrlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETSOCKNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getpeername(fd->secret->md.osfd, + (struct sockaddr *) addr, (int *)addrlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETPEERNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, + char* optval, PRInt32* optlen) +{ + PRInt32 rv, err; + + rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (int *)optlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETSOCKOPT_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, + const char* optval, PRInt32 optlen) +{ + PRInt32 rv, err; + + rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_SETSOCKOPT_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +void +_MD_MakeNonblock(PRFileDesc *fd) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 err; + PRUint32 one = 1; + + if (osfd <= 2) { + /* Don't mess around with stdin, stdout or stderr */ + return; + } + + err = _OS2_IOCTL( osfd, FIONBIO, (char *) &one, sizeof(one)); + if ( err != 0 ) + { + err = sock_errno(); + _PR_MD_MAP_SOCKET_ERROR(err); + } +} diff --git a/nsprpub/pr/src/md/os2/os2thred.c b/nsprpub/pr/src/md/os2/os2thred.c new file mode 100644 index 00000000000..48aab74b094 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2thred.c @@ -0,0 +1,405 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include /* for _beginthread() */ + +#ifdef XP_OS2_VACPP +#include /* for _tzset() */ +#endif + +#ifdef XP_OS2_EMX +#include +#endif + +#include + +/* --- globals ------------------------------------------------ */ +_NSPR_TLS* pThreadLocalStorage = 0; +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; +APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD); + +void +_PR_MD_ENSURE_TLS(void) +{ + if(!pThreadLocalStorage) + { + /* Allocate thread local storage (TLS). Note, that only 32 bytes can + * be allocated at a time. + */ + int rc = DosAllocThreadLocalMemory(sizeof(_NSPR_TLS) / 4, (PULONG*)&pThreadLocalStorage); + PR_ASSERT(rc == NO_ERROR); + memset(pThreadLocalStorage, 0, sizeof(_NSPR_TLS)); + } +} + +void +_PR_MD_EARLY_INIT() +{ + HMODULE hmod; + + if (DosLoadModule(NULL, 0, "DOSCALL1", &hmod) == 0) + DosQueryProcAddr(hmod, 877, "DOSQUERYTHREADCONTEXT", + (PFN *)&QueryThreadContext); + +#ifdef XP_OS2_VACPP + _tzset(); +#endif +} + +static void +_pr_SetThreadMDHandle(PRThread *thread) +{ + PTIB ptib; + PPIB ppib; + PRUword rc; + + rc = DosGetInfoBlocks(&ptib, &ppib); + + thread->md.handle = ptib->tib_ptib2->tib2_ultid; +} + +/* On OS/2, some system function calls seem to change the FPU control word, + * such that we crash with a floating underflow exception. The FIX_FPU() call + * in jsnum.c does not always work, as sometimes FIX_FPU() is called BEFORE the + * OS/2 system call that horks the FPU control word. So, we set an exception + * handler that covers any floating point exceptions and resets the FPU CW to + * the required value. + */ +static ULONG +_System OS2_FloatExcpHandler(PEXCEPTIONREPORTRECORD p1, + PEXCEPTIONREGISTRATIONRECORD p2, + PCONTEXTRECORD p3, + PVOID pv) +{ +#ifdef DEBUG_pedemonte + printf("Entering exception handler; ExceptionNum = %x\n", p1->ExceptionNum); + switch(p1->ExceptionNum) { + case XCPT_FLOAT_DENORMAL_OPERAND: + printf("got XCPT_FLOAT_DENORMAL_OPERAND\n"); + break; + case XCPT_FLOAT_DIVIDE_BY_ZERO: + printf("got XCPT_FLOAT_DIVIDE_BY_ZERO\n"); + break; + case XCPT_FLOAT_INEXACT_RESULT: + printf("got XCPT_FLOAT_INEXACT_RESULT\n"); + break; + case XCPT_FLOAT_INVALID_OPERATION: + printf("got XCPT_FLOAT_INVALID_OPERATION\n"); + break; + case XCPT_FLOAT_OVERFLOW: + printf("got XCPT_FLOAT_OVERFLOW\n"); + break; + case XCPT_FLOAT_STACK_CHECK: + printf("got XCPT_FLOAT_STACK_CHECK\n"); + break; + case XCPT_FLOAT_UNDERFLOW: + printf("got XCPT_FLOAT_UNDERFLOW\n"); + break; + } +#endif + + switch(p1->ExceptionNum) { + case XCPT_FLOAT_DENORMAL_OPERAND: + case XCPT_FLOAT_DIVIDE_BY_ZERO: + case XCPT_FLOAT_INEXACT_RESULT: + case XCPT_FLOAT_INVALID_OPERATION: + case XCPT_FLOAT_OVERFLOW: + case XCPT_FLOAT_STACK_CHECK: + case XCPT_FLOAT_UNDERFLOW: + { + unsigned cw = p3->ctx_env[0]; + if ((cw & MCW_EM) != MCW_EM) { + /* Mask out all floating point exceptions */ + p3->ctx_env[0] |= MCW_EM; + /* Following two lines set precision to 53 bit mantissa. See jsnum.c */ + p3->ctx_env[0] &= ~MCW_PC; + p3->ctx_env[0] |= PC_53; + return XCPT_CONTINUE_EXECUTION; + } + } + } + return XCPT_CONTINUE_SEARCH; +} + +PR_IMPLEMENT(void) +PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg) +{ + /* setup the exception handler for the thread */ + APIRET rv; + excpreg->ExceptionHandler = OS2_FloatExcpHandler; + excpreg->prev_structure = NULL; + rv = DosSetExceptionHandler(excpreg); + PR_ASSERT(rv == NO_ERROR); +} + +PR_IMPLEMENT(void) +PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg) +{ + /* unset exception handler */ + APIRET rv = DosUnsetExceptionHandler(excpreg); + PR_ASSERT(rv == NO_ERROR); +} + +PRStatus +_PR_MD_INIT_THREAD(PRThread *thread) +{ + APIRET rv; + + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + _pr_SetThreadMDHandle(thread); + } + + /* Create the blocking IO semaphore */ + rv = DosCreateEventSem(NULL, &(thread->md.blocked_sema), 0, 0); + return (rv == NO_ERROR) ? PR_SUCCESS : PR_FAILURE; +} + +typedef struct param_store +{ + void (*start)(void *); + PRThread* thread; +} PARAMSTORE; + +/* This is a small intermediate function that sets/unsets the exception + handler before calling the initial thread function */ +static void +ExcpStartFunc(void* arg) +{ + EXCEPTIONREGISTRATIONRECORD excpreg; + PARAMSTORE params, *pParams = arg; + + PR_OS2_SetFloatExcpHandler(&excpreg); + + params = *pParams; + PR_Free(pParams); + params.start(params.thread); + + PR_OS2_UnsetFloatExcpHandler(&excpreg); +} + +PRStatus +_PR_MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PARAMSTORE* params = PR_Malloc(sizeof(PARAMSTORE)); + params->start = start; + params->thread = thread; +#ifdef XP_OS2_VACPP /* No exception handler for VACPP */ + thread->md.handle = thread->id = (TID) _beginthread( + (void(* _Optlink)(void*))start, + NULL, + thread->stack->stackSize, + thread); +#else + thread->md.handle = thread->id = (TID) _beginthread(ExcpStartFunc, + NULL, + thread->stack->stackSize, + params); +#endif + if(thread->md.handle == -1) { + return PR_FAILURE; + } + + /* + * On OS/2, a thread is created with a thread priority of + * THREAD_PRIORITY_NORMAL + */ + + if (priority != PR_PRIORITY_NORMAL) { + _PR_MD_SET_PRIORITY(&(thread->md), priority); + } + + return PR_SUCCESS; +} + +void +_PR_MD_YIELD(void) +{ + /* Isn't there some problem with DosSleep(0) on OS/2? */ + DosSleep(0); +} + +void +_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) +{ + int nativePri = PRTYC_NOCHANGE; + BOOL rv; + + if (newPri < PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } else if (newPri > PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } + switch (newPri) { + case PR_PRIORITY_LOW: + case PR_PRIORITY_NORMAL: + nativePri = PRTYC_REGULAR; + break; + case PR_PRIORITY_HIGH: + nativePri = PRTYC_FOREGROUNDSERVER; + break; + case PR_PRIORITY_URGENT: + nativePri = PRTYC_TIMECRITICAL; + } + rv = DosSetPriority(PRTYS_THREAD, nativePri, 0, thread->handle); + PR_ASSERT(rv == NO_ERROR); + if (rv != NO_ERROR) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: can't set thread priority\n")); + } + return; +} + +void +_PR_MD_CLEAN_THREAD(PRThread *thread) +{ + APIRET rv; + + if (thread->md.blocked_sema) { + rv = DosCloseEventSem(thread->md.blocked_sema); + PR_ASSERT(rv == NO_ERROR); + thread->md.blocked_sema = 0; + } + + if (thread->md.handle) { + thread->md.handle = 0; + } +} + +void +_PR_MD_EXIT_THREAD(PRThread *thread) +{ + _PR_MD_CLEAN_THREAD(thread); + _PR_MD_SET_CURRENT_THREAD(NULL); +} + + +void +_PR_MD_EXIT(PRIntn status) +{ + _exit(status); +} + +#ifdef HAVE_THREAD_AFFINITY +PR_EXTERN(PRInt32) +_PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) +{ + /* Can we do this on OS/2? Only on SMP versions? */ + PR_ASSERT(!"Not implemented"); + return 0; + + /* This is what windows does: + int rv; + + rv = SetThreadAffinityMask(thread->md.handle, mask); + + return rv?0:-1; + */ +} + +PR_EXTERN(PRInt32) +_PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) +{ + /* Can we do this on OS/2? Only on SMP versions? */ + PR_ASSERT(!"Not implemented"); + return 0; + + /* This is what windows does: + PRInt32 rv, system_mask; + + rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask); + + return rv?0:-1; + */ +} +#endif /* HAVE_THREAD_AFFINITY */ + +void +_PR_MD_SUSPEND_CPU(_PRCPU *cpu) +{ + _PR_MD_SUSPEND_THREAD(cpu->thread); +} + +void +_PR_MD_RESUME_CPU(_PRCPU *cpu) +{ + _PR_MD_RESUME_THREAD(cpu->thread); +} + +void +_PR_MD_SUSPEND_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + APIRET rc; + + /* XXXMB - DosSuspendThread() is not a blocking call; how do we + * know when the thread is *REALLY* suspended? + */ + rc = DosSuspendThread(thread->md.handle); + PR_ASSERT(rc == NO_ERROR); + } +} + +void +_PR_MD_RESUME_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + DosResumeThread(thread->md.handle); + } +} + + +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/nsprpub/pr/src/md/os2/os2vaclegacy.s b/nsprpub/pr/src/md/os2/os2vaclegacy.s new file mode 100644 index 00000000000..3bf8e80c8ea --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2vaclegacy.s @@ -0,0 +1,78 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ ***** BEGIN LICENSE BLOCK ***** +/ Version: MPL 1.1/GPL 2.0/LGPL 2.1 +/ +/ The contents of this file are subject to the Mozilla Public License Version +/ 1.1 (the "License"); you may not use this file except in compliance with +/ the License. You may obtain a copy of the License at +/ http://www.mozilla.org/MPL/ +/ +/ Software distributed under the License is distributed on an "AS IS" basis, +/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +/ for the specific language governing rights and limitations under the +/ License. +/ +/ The Original Code is the Netscape Portable Runtime (NSPR). +/ +/ The Initial Developer of the Original Code is +/ InnoTek Systemberatung GmbH. +/ Portions created by the Initial Developer are Copyright (C) 2003 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ InnoTek Systemberatung GmbH / Knut St. Osmundsen +/ +/ Alternatively, the contents of this file may be used under the terms of +/ either the GNU General Public License Version 2 or later (the "GPL"), or +/ the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +/ in which case the provisions of the GPL or the LGPL are applicable instead +/ of those above. If you wish to allow use of your version of this file only +/ under the terms of either the GPL or the LGPL, and not to allow others to +/ use your version of this file under the terms of the MPL, indicate your +/ decision by deleting the provisions above and replace them with the notice +/ and other provisions required by the GPL or the LGPL. If you do not delete +/ the provisions above, a recipient may use your version of this file under +/ the terms of any one of the MPL, the GPL or the LGPL. +/ +/ ***** END LICENSE BLOCK ***** + + .text + .align 4 + .globl PR_NewMonitor +PR_NewMonitor: + jmp _PR_NewMonitor + + .align 4 + .globl PR_EnterMonitor +PR_EnterMonitor: + mov %eax, 4(%esp) + jmp _PR_EnterMonitor + + .align 4 + .globl PR_ExitMonitor +PR_ExitMonitor: + mov %eax, 4(%esp) + jmp _PR_ExitMonitor + + + + .align 4 + .globl PR_AttachThread +PR_AttachThread: + mov %eax, 4(%esp) + mov %edx, 8(%esp) + mov %ecx, 12(%esp) + jmp _PR_AttachThread + + .align 4 + .globl PR_DetachThread +PR_DetachThread: + jmp _PR_DetachThread + + .align 4 + .globl PR_GetCurrentThread +PR_GetCurrentThread: + jmp _PR_GetCurrentThread + + diff --git a/nsprpub/pr/src/md/os2/os2vacpp.asm b/nsprpub/pr/src/md/os2/os2vacpp.asm new file mode 100644 index 00000000000..58cbbf691b2 --- /dev/null +++ b/nsprpub/pr/src/md/os2/os2vacpp.asm @@ -0,0 +1,266 @@ +; -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- + +; ***** BEGIN LICENSE BLOCK ***** +; Version: MPL 1.1/GPL 2.0/LGPL 2.1 +; +; The contents of this file are subject to the Mozilla Public License Version +; 1.1 (the "License"); you may not use this file except in compliance with +; the License. You may obtain a copy of the License at +; http://www.mozilla.org/MPL/ +; +; Software distributed under the License is distributed on an "AS IS" basis, +; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +; for the specific language governing rights and limitations under the +; License. +; +; The Original Code is the Netscape Portable Runtime (NSPR). +; +; The Initial Developer of the Original Code is +; IBM Corporation. +; Portions created by the Initial Developer are Copyright (C) 2001 +; the Initial Developer. All Rights Reserved. +; +; Contributor(s): +; +; Alternatively, the contents of this file may be used under the terms of +; either the GNU General Public License Version 2 or later (the "GPL"), or +; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +; in which case the provisions of the GPL or the LGPL are applicable instead +; of those above. If you wish to allow use of your version of this file only +; under the terms of either the GPL or the LGPL, and not to allow others to +; use your version of this file under the terms of the MPL, indicate your +; decision by deleting the provisions above and replace them with the notice +; and other provisions required by the GPL or the LGPL. If you do not delete +; the provisions above, a recipient may use your version of this file under +; the terms of any one of the MPL, the GPL or the LGPL. +; +; ***** END LICENSE BLOCK ***** + +; Windows uses inline assembly for their atomic functions, so we have +; created an assembly file for VACPP on OS/2. +; +; This assembly file also contains an implementation of RAM semaphores. +; +; Notes: +; The ulTIDPID element of the RAMSEM structure is overloaded in the 386 +; implementation to hold the TID:PID in the lower 31 bits and the lock +; bit in the high bit + + page ,132 + + .486P + ASSUME CS:FLAT, DS:FLAT, SS:FLAT, ES:FLAT, FS:FLAT + + EXTRN Dos32PostEventSem:PROC + EXTRN Dos32WaitEventSem:PROC + EXTRN Dos32ResetEventSem:PROC + +ramsem STRUC + ramsem_ulTIDPID DD ? + ramsem_hevSem DD ? + ramsem_cLocks DD ? + ramsem_cWaiting DW ? + ramsem_cPosts DW ? +ramsem ENDS + +ERROR_SEM_TIMEOUT equ 121 +ERROR_NOT_OWNER equ 288 +SEM_RELEASE_UNOWNED equ 1 +SEM_RELEASE_ALL equ 2 +TS_LOCKBIT equ 31 + + +DATA SEGMENT DWORD USE32 PUBLIC 'DATA' + + EXTRN plisCurrent:DWORD + +DATA ENDS + +CODE32 SEGMENT USE32 PUBLIC 'CODE' + + PUBLIC SemRequest486 + PUBLIC SemReleasex86 + + PUBLIC _PR_MD_ATOMIC_SET + PUBLIC _PR_MD_ATOMIC_ADD + PUBLIC _PR_MD_ATOMIC_INCREMENT + PUBLIC _PR_MD_ATOMIC_DECREMENT + +;;;--------------------------------------------------------------------------- +;;; APIRET _Optlink SemRequest(PRAMSEM pramsem, ULONG ulTimeout); +;;; +;;; Registers: +;;; EAX - packed TID:PID word +;;; ECX - address of RAMSEM structure +;;; EDX - length of timeout in milli-seconds +;;;--------------------------------------------------------------------------- + + ALIGN 10H +SemRequest486 PROC + push ebx ; Save ebx (volatile) + mov ecx, eax ; PRAMSEM must be in ecx, + ; not eax, for cmpxchg + + mov ebx, dword ptr [plisCurrent] + mov eax, dword ptr [ebx+4] ; Place thread id in high + ; word, process id in low + mov ax, word ptr [ebx] ; word + mov ebx,eax + +req486_test: + xor eax,eax + cmp (ramsem PTR [ecx]).ramsem_ulTIDPID, ebx ; If we own the sem, just + jz short req486_inc_exit ; increment the use count + + lock inc (ramsem PTR [ecx]).ramsem_cWaiting ; inc waiting flag + +; lock ; Uncomment for SMP + DB 0F0h +; cmpxchg (ramsem PTR [ecx]).ramsem_ulTIDPID, ebx +; (byte 3 is the offset of ulProcessThread into the RAMSEM structure) + DB 00Fh + DB 0B1h + DB 019h + jnz short req486_sleep + +req486_inc_exit: + lock inc (ramsem PTR [ecx]).ramsem_cLocks + +req486_exit: + pop ebx ; Restore ebx + ret + +req486_sleep: + push ecx ; Save ecx (volatile) + push edx ; Save edx (volatile) + push edx ; timeout + push (ramsem PTR [ecx]).ramsem_hevSem + call Dos32WaitEventSem + add esp, 8 + pop edx ; restore edx + pop ecx ; restore ecx + or eax, eax + jne req486_exit ; Exit, if error + + push ecx ; Save ecx (volatile) + push edx ; Save edx (volatile) + sub esp, 4 ; Use stack space for + push esp ; dummy pulPostCt + push (ramsem PTR [ecx]).ramsem_hevSem + call Dos32ResetEventSem + add esp, 12 + pop edx ; restore edx + pop ecx ; restore ecx + jmp req486_test ; Retry the semaphore + +SemRequest486 ENDP + +;;;--------------------------------------------------------------------- +;;; APIRET _Optlink SemReleasex86(PRAMSEM pramsem, ULONG flFlags); +;;; +;;; Registers: +;;; EAX - address of RAMSEM structure +;;; ECX - temporary variable +;;; EDX - flags +;;;--------------------------------------------------------------------- + + ALIGN 10H +SemReleasex86 PROC + test edx, SEM_RELEASE_UNOWNED ; If set, don't bother + jnz short rel_ownerok ; getting/checking PID/TID + + push ebx ; Save ebx (volatile) + mov ebx, dword ptr [plisCurrent] + mov ecx, dword ptr [ebx+4] ; Place thread id in high + ; word, process id in low + mov cx, word ptr [ebx] ; word + pop ebx ; Restore ebx + + sub ecx, (ramsem PTR [eax]).ramsem_ulTIDPID ; This thread the owner? + shl ecx,1 ; Don't compare top bit + jnz short rel_notowner + +rel_ownerok: + test edx, SEM_RELEASE_ALL + jnz short rel_clear + + lock dec (ramsem PTR [eax]).ramsem_cLocks + jnz short rel_exit + +rel_disown: + mov (ramsem PTR [eax]).ramsem_ulTIDPID, 0 + + lock inc (ramsem PTR [eax]).ramsem_cPosts + mov cx, (ramsem PTR [eax]).ramsem_cWaiting + cmp (ramsem PTR [eax]).ramsem_cPosts, cx + jne short rel_post + +rel_exit: + xor eax, eax + ret + +rel_clear: + lock mov (ramsem PTR [eax]).ramsem_cLocks,0 + jmp rel_disown + +rel_notowner: + mov eax, ERROR_NOT_OWNER + ret + +rel_post: + mov (ramsem PTR [eax]).ramsem_cPosts, cx + push (ramsem PTR [eax]).ramsem_hevSem + call Dos32PostEventSem + add esp,4 + xor eax,eax + ret +SemReleasex86 ENDP + +;;;--------------------------------------------------------------------- +;;; PRInt32 _Optlink _PR_MD_ATOMIC_SET(PRInt32* val, PRInt32 newval) +;;;--------------------------------------------------------------------- + ALIGN 10H +_PR_MD_ATOMIC_SET proc + xchg dword ptr [eax],edx + mov eax, edx; + ret +_PR_MD_ATOMIC_SET endp + +;;;--------------------------------------------------------------------- +;;; PRInt32 _Optlink _PR_MD_ATOMIC_ADD(PRInt32* ptr, PRInt32 val) +;;;--------------------------------------------------------------------- + ALIGN 10H +_PR_MD_ATOMIC_ADD proc + mov ecx, edx + lock xadd dword ptr [eax], edx + mov eax, edx + add eax, ecx + ret +_PR_MD_ATOMIC_ADD endp + +;;;--------------------------------------------------------------------- +;;; PRInt32 _Optlink _PR_MD_ATOMIC_INCREMENT(PRInt32* val) +;;;--------------------------------------------------------------------- + ALIGN 10H +_PR_MD_ATOMIC_INCREMENT proc + mov edx, 1 + lock xadd dword ptr [eax], edx + mov eax, edx + inc eax + ret +_PR_MD_ATOMIC_INCREMENT endp + +;;;--------------------------------------------------------------------- +;;; PRInt32 _Optlink _PR_MD_ATOMIC_DECREMENT(PRInt32* val) +;;;--------------------------------------------------------------------- + ALIGN 10H +_PR_MD_ATOMIC_DECREMENT proc + mov edx, 0ffffffffh + lock xadd dword ptr [eax], edx + mov eax, edx + dec eax + ret +_PR_MD_ATOMIC_DECREMENT endp + +CODE32 ENDS +END diff --git a/nsprpub/pr/src/md/prosdep.c b/nsprpub/pr/src/md/prosdep.c new file mode 100644 index 00000000000..0f01b84c719 --- /dev/null +++ b/nsprpub/pr/src/md/prosdep.c @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prbit.h" +#include "prsystem.h" + +#ifdef XP_UNIX +#include +#endif +#ifdef SUNOS4 +#include "md/sunos4.h" +#endif +#ifdef _WIN32 +#include +#endif +#ifdef XP_BEOS +#include +#endif + +PRInt32 _pr_pageShift; +PRInt32 _pr_pageSize; + +/* +** Get system page size +*/ +static void GetPageSize(void) +{ + PRInt32 pageSize; + + /* Get page size */ +#ifdef XP_UNIX +#if defined SUNOS4 || defined BSDI || defined AIX \ + || defined LINUX || defined __GNU__ || defined __GLIBC__ \ + || defined FREEBSD || defined NETBSD || defined OPENBSD \ + || defined DARWIN || defined NEXTSTEP + _pr_pageSize = getpagesize(); +#elif defined(HPUX) + /* I have no idea. Don't get me started. --Rob */ + _pr_pageSize = sysconf(_SC_PAGE_SIZE); +#else + _pr_pageSize = sysconf(_SC_PAGESIZE); +#endif +#endif /* XP_UNIX */ + +#ifdef XP_MAC + _pr_pageSize = 4096; +#endif /* XP_MAC */ + +#ifdef XP_BEOS + _pr_pageSize = B_PAGE_SIZE; +#endif + +#ifdef XP_PC +#ifdef _WIN32 + SYSTEM_INFO info; + GetSystemInfo(&info); + _pr_pageSize = info.dwPageSize; +#else + _pr_pageSize = 4096; +#endif +#endif /* XP_PC */ + + pageSize = _pr_pageSize; + PR_CEILING_LOG2(_pr_pageShift, pageSize); +} + +PR_IMPLEMENT(PRInt32) PR_GetPageShift(void) +{ + if (!_pr_pageSize) { + GetPageSize(); + } + return _pr_pageShift; +} + +PR_IMPLEMENT(PRInt32) PR_GetPageSize(void) +{ + if (!_pr_pageSize) { + GetPageSize(); + } + return _pr_pageSize; +} diff --git a/nsprpub/pr/src/md/unix/.cvsignore b/nsprpub/pr/src/md/unix/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/md/unix/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/md/unix/Makefile.in b/nsprpub/pr/src/md/unix/Makefile.in new file mode 100644 index 00000000000..1c4c071cec3 --- /dev/null +++ b/nsprpub/pr/src/md/unix/Makefile.in @@ -0,0 +1,135 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +CSRCS = \ + unix.c \ + unix_errors.c \ + uxproces.c \ + uxrng.c \ + uxshm.c \ + uxwrap.c \ + $(NULL) + +ifneq ($(USE_PTHREADS),1) +CSRCS += uxpoll.c +endif + +ifeq ($(PTHREADS_USER),1) +CSRCS += pthreads_user.c +endif + +CSRCS += $(PR_MD_CSRCS) +ASFILES += $(PR_MD_ASFILES) + +TARGETS = $(OBJS) + +ifeq ($(OS_ARCH),SunOS) + ifneq ($(OS_RELEASE),4.1.3_U1) + ifeq ($(OS_TEST),sun4u) + ifdef USE_64 + ULTRASPARC_ASFILES = os_SunOS_sparcv9.s + ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX))) + else + LIBRARY_NAME = $(ULTRASPARC_LIBRARY) + LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + ULTRASPARC_ASFILES = os_SunOS_ultrasparc.s + ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX))) + TARGETS += $(ULTRASPARC_ASOBJS) $(SHARED_LIBRARY) + RELEASE_LIBS = $(SHARED_LIBRARY) + RELEASE_LIBS_DEST = $(RELEASE_LIB_DIR)/cpu/sparcv8plus + lib_subdir = cpu/sparcv8plus + endif + endif + endif +endif + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + +ifeq ($(OS_ARCH),SunOS) +ifneq ($(OS_RELEASE),4.1.3_U1) +ifeq ($(OS_TEST),sun4u) + +ifdef USE_64 +$(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES) + /usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v9 $< +else +$(SHARED_LIBRARY): $(ULTRASPARC_ASOBJS) + $(LD) -G -z text -z endfiltee -o $@ $(ULTRASPARC_ASOBJS) + $(INSTALL) -m 444 $@ $(dist_libdir)/cpu/sparcv8plus + $(INSTALL) -m 444 $@ $(dist_bindir)/cpu/sparcv8plus +# +# The -f $(ORIGIN)/... linker flag uses the real file, after symbolic links +# are resolved, as the origin. If NSDISTMODE is not "copy", libnspr4.so +# will be installed as a symbolic link in $(dist_libdir), pointing to the +# real libnspr4.so file in pr/src. Therefore we need to install an +# additional copy of libnspr_flt4.so in pr/src/cpu/sparcv8plus. +# +ifneq ($(NSDISTMODE),copy) + $(INSTALL) -m 444 $@ ../../cpu/sparcv8plus +endif + +ifneq ($(NSDISTMODE),copy) +clobber realclean clobber_all distclean:: + rm -rf ../../cpu +endif + +$(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES) + /usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v8plus $< + +clean:: + rm -rf $(ULTRASPARC_ASOBJS) +endif + +endif +endif +endif diff --git a/nsprpub/pr/src/md/unix/aix.c b/nsprpub/pr/src/md/unix/aix.c new file mode 100644 index 00000000000..ae945b1bd8e --- /dev/null +++ b/nsprpub/pr/src/md/unix/aix.c @@ -0,0 +1,333 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#ifdef AIX_HAVE_ATOMIC_OP_H +#include + +PRInt32 _AIX_AtomicSet(PRInt32 *val, PRInt32 newval) +{ + PRIntn oldval; + boolean_t stored; + oldval = fetch_and_add((atomic_p)val, 0); + do + { + stored = compare_and_swap((atomic_p)val, &oldval, newval); + } while (!stored); + return oldval; +} /* _AIX_AtomicSet */ +#endif /* AIX_HAVE_ATOMIC_OP_H */ + +#if defined(AIX_TIMERS) + +#include + +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) + +#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 + +int (*_PT_aix_yield_fcn)() = NULL; +int _pr_aix_send_file_use_disabled = 0; + +void _MD_EarlyInit(void) +{ + void *main_app_handle; + char *evp; + + main_app_handle = dlopen(NULL, RTLD_NOW); + PR_ASSERT(NULL != main_app_handle); + + _PT_aix_yield_fcn = (int(*)())dlsym(main_app_handle, "sched_yield"); + if (!_PT_aix_yield_fcn) { + _PT_aix_yield_fcn = (int(*)())dlsym(main_app_handle,"pthread_yield"); + PR_ASSERT(NULL != _PT_aix_yield_fcn); + } + dlclose(main_app_handle); + + if (evp = getenv("NSPR_AIX_SEND_FILE_USE_DISABLED")) { + if (1 == atoi(evp)) + _pr_aix_send_file_use_disabled = 1; + } + +#if defined(AIX_TIMERS) + _MD_AixIntervalInit(); +#endif +} + +#else /* _PR_PTHREADS */ + +void _MD_EarlyInit(void) +{ +#if defined(AIX_TIMERS) + _MD_AixIntervalInit(); +#endif +} + +#endif /* _PR_PTHREADS */ + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +PR_IMPLEMENT(void) +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PR_IMPLEMENT(PRStatus) +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PR_IMPLEMENT(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 AIX */ +PR_IMPLEMENT(void) +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for AIX."); +} + +PR_IMPLEMENT(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 AIX."); +} +#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(AIX_RENAME_SELECT) + +#include +#include +#include + +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 +void _pr_aix_dummy() +{ + poll(0,0,0); +} + +#endif /* !defined(AIX_RENAME_SELECT) */ + +#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; + + /* Is it safe to cast a pointer to an int? */ + PR_ASSERT(sizeof(int) == sizeof(PRStackElem *)); + 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; + + /* Is it safe to cast a pointer to an int? */ + PR_ASSERT(sizeof(int) == sizeof(PRStackElem *)); + 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/nsprpub/pr/src/md/unix/aixwrap.c b/nsprpub/pr/src/md/unix/aixwrap.c new file mode 100644 index 00000000000..d829710af9a --- /dev/null +++ b/nsprpub/pr/src/md/unix/aixwrap.c @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: aixwrap.c + * Description: + * This file contains a single function, _MD_SELECT(), which simply + * invokes the select() function. This file is used in an ugly + * hack to override the system select() function on AIX releases + * prior to 4.2. (On AIX 4.2, we use a different mechanism to + * override select().) + */ + +#ifndef AIX_RENAME_SELECT +#error aixwrap.c should only be used on AIX 3.2 or 4.1 +#else + +#include +#include + +int _MD_SELECT(int width, fd_set *r, fd_set *w, fd_set *e, struct timeval *t) +{ + return select(width, r, w, e, t); +} + +int _MD_POLL(void *listptr, unsigned long nfds, long timeout) +{ + return poll(listptr, nfds, timeout); +} + +#endif /* AIX_RENAME_SELECT */ diff --git a/nsprpub/pr/src/md/unix/bsdi.c b/nsprpub/pr/src/md/unix/bsdi.c new file mode 100644 index 00000000000..646766335b3 --- /dev/null +++ b/nsprpub/pr/src/md/unix/bsdi.c @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +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) setjmp(CONTEXT(t)); + } + *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 BSDI */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for BSDI."); +} + +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 BSDI."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/nsprpub/pr/src/md/unix/darwin.c b/nsprpub/pr/src/md/unix/darwin.c new file mode 100644 index 00000000000..3a1329e709b --- /dev/null +++ b/nsprpub/pr/src/md/unix/darwin.c @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#if !defined(_PR_PTHREADS) + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#if !defined(_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 Darwin */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Darwin."); +} + +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 Darwin."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ + +/* darwin.c */ + diff --git a/nsprpub/pr/src/md/unix/dgux.c b/nsprpub/pr/src/md/unix/dgux.c new file mode 100644 index 00000000000..2874d9ea9f4 --- /dev/null +++ b/nsprpub/pr/src/md/unix/dgux.c @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/* + * using only NSPR threads here + * + * Copied from the UnixWare implementation. Should be kept in sync + * with ../../../include/md/_dgux.h. + */ + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +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 DG/UX */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for DG/UX."); +} + +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 DG/UX."); +} + diff --git a/nsprpub/pr/src/md/unix/freebsd.c b/nsprpub/pr/src/md/unix/freebsd.c new file mode 100644 index 00000000000..dce244a3dba --- /dev/null +++ b/nsprpub/pr/src/md/unix/freebsd.c @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +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 FreeBSD */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for FreeBSD."); +} + +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 FreeBSD."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/nsprpub/pr/src/md/unix/hpux.c b/nsprpub/pr/src/md/unix/hpux.c new file mode 100644 index 00000000000..cf43e05ed83 --- /dev/null +++ b/nsprpub/pr/src/md/unix/hpux.c @@ -0,0 +1,261 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include + +#if defined(HPUX_LW_TIMER) + +#include +#include +#include +#include +#include + +int __lw_get_thread_times(int which, int64_t *sample, int64_t *time); + +static double msecond_per_itick; + +void _PR_HPUX_LW_IntervalInit(void) +{ + struct pst_processor psp; + int iticksperclktick, clk_tck; + int rv; + + rv = pstat_getprocessor(&psp, sizeof(psp), 1, 0); + PR_ASSERT(rv != -1); + + iticksperclktick = psp.psp_iticksperclktick; + clk_tck = sysconf(_SC_CLK_TCK); + msecond_per_itick = (1000.0)/(double)(iticksperclktick * clk_tck); +} + +PRIntervalTime _PR_HPUX_LW_GetInterval(void) +{ + int64_t time, sample; + + __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) +{ +#ifndef _PR_PTHREADS + /* + * The following piece of code is taken from ns/nspr/src/md_HP-UX.c. + * In the comment for revision 1.6, dated 1995/09/11 23:33:34, + * robm says: + * This version has some problems which need to be addressed. + * First, intercept all system calls and prevent them from + * executing the library code which performs stack switches + * before normal system call invocation. In order for library + * calls which make system calls to work (like stdio), however, + * we must also allocate our own stack and switch the primordial + * stack to use it. This isn't so bad, except that I fudged the + * backtrace length when copying the old stack to the new one. + * + * This is the original comment of robm in the code: + * XXXrobm Horrific. To avoid a problem with HP's system call + * code, we allocate a new stack for the primordial thread and + * use it. However, we don't know how far back the original stack + * goes. We should create a routine that performs a backtrace and + * finds out just how much we need to copy. As a temporary measure, + * I just copy an arbitrary guess. + * + * In an email to servereng dated 2 Jan 1997, Mike Patnode (mikep) + * suggests that this only needs to be done for HP-UX 9. + */ +#ifdef HPUX9 +#define PIDOOMA_STACK_SIZE 524288 +#define BACKTRACE_SIZE 8192 + { + jmp_buf jb; + char *newstack; + char *oldstack; + + if(!setjmp(jb)) { + newstack = (char *) PR_MALLOC(PIDOOMA_STACK_SIZE); + oldstack = (char *) (*(((int *) jb) + 1) - BACKTRACE_SIZE); + memcpy(newstack, oldstack, BACKTRACE_SIZE); + *(((int *) jb) + 1) = (int) (newstack + BACKTRACE_SIZE); + longjmp(jb, 1); + } + } +#endif /* HPUX9 */ +#endif /* !_PR_PTHREADS */ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *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 HP-UX */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for HP-UX."); +} + +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 HP-UX."); +} +#endif /* _PR_PTHREADS */ + +void +_MD_suspend_thread(PRThread *thread) +{ +#ifdef _PR_PTHREADS +#endif +} + +void +_MD_resume_thread(PRThread *thread) +{ +#ifdef _PR_PTHREADS +#endif +} +#endif /* PTHREADS_USER */ + +/* + * 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. + * + * A better solution might be to put a cushion in our malloc just in + * case HP's version of strchr somehow gets used instead of this one. + */ +char * +strchr(const char *s, int c) +{ + char ch; + + if (!s) { + return NULL; + } + + ch = (char) c; + + while ((*s) && ((*s) != ch)) { + s++; + } + + if ((*s) == ch) { + return (char *) s; + } + + return NULL; +} + +/* + * Implemementation of memcmp in HP-UX (verified on releases A.09.03, + * A.09.07, and B.10.10) dumps core if called with: + * 1. First operand with address = 1(mod 4). + * 2. Size = 1(mod 4) + * 3. Last byte of the second operand is the last byte of the page and + * next page is not accessible(not mapped or protected) + * Thus, using the following naive version (tons of optimizations are + * possible;^) + */ + +int memcmp(const void *s1, const void *s2, size_t n) +{ + register unsigned char *p1 = (unsigned char *) s1, + *p2 = (unsigned char *) s2; + + while (n-- > 0) { + register int r = ((int) ((unsigned int) *p1)) + - ((int) ((unsigned int) *p2)); + if (r) return r; + p1++; p2++; + } + return 0; +} diff --git a/nsprpub/pr/src/md/unix/irix.c b/nsprpub/pr/src/md/unix/irix.c new file mode 100644 index 00000000000..758e54d2cd2 --- /dev/null +++ b/nsprpub/pr/src/md/unix/irix.c @@ -0,0 +1,1680 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +typedef struct nspr_arena { + PRCList links; + usptr_t *usarena; +} nspr_arena; + +#define ARENA_PTR(qp) \ + ((nspr_arena *) ((char*) (qp) - offsetof(nspr_arena , links))) + +static usptr_t *alloc_new_arena(void); + +PRCList arena_list = PR_INIT_STATIC_CLIST(&arena_list); +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; + +usptr_t *_pr_usArena; +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; +static void *libc_handle = NULL; + +#define _NSPR_DEF_INITUSERS 100 /* default value of CONF_INITUSERS */ +#define _NSPR_DEF_INITSIZE (4 * 1024 * 1024) /* 4 MB */ + +int _irix_initusers = _NSPR_DEF_INITUSERS; +int _irix_initsize = _NSPR_DEF_INITSIZE; + +PRIntn _pr_io_in_progress, _pr_clock_in_progress; + +PRInt32 _pr_md_irix_sprocs_created, _pr_md_irix_sprocs_failed; +PRInt32 _pr_md_irix_sprocs = 1; +PRCList _pr_md_irix_sproc_list = +PR_INIT_STATIC_CLIST(&_pr_md_irix_sproc_list); + +sigset_t ints_off; +extern sigset_t timer_set; + +#if !defined(PR_SETABORTSIG) +#define PR_SETABORTSIG 18 +#endif +/* + * terminate the entire application if any sproc exits abnormally + */ +PRBool _nspr_terminate_on_error = PR_TRUE; + +/* + * exported interface to set the shared arena parameters + */ +void _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize) +{ + _irix_initusers = initusers; + _irix_initsize = initsize; +} + +static usptr_t *alloc_new_arena() +{ + return(usinit("/dev/zero")); +} + +static PRStatus new_poll_sem(struct _MDThread *mdthr, int val) +{ +PRIntn _is; +PRStatus rv = PR_SUCCESS; +usema_t *sem = NULL; +PRCList *qp; +nspr_arena *arena; +usptr_t *irix_arena; +PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + _PR_LOCK(arena_list_lock); + for (qp = arena_list.next; qp != &arena_list; qp = qp->next) { + arena = ARENA_PTR(qp); + sem = usnewpollsema(arena->usarena, val); + if (sem != NULL) { + mdthr->cvar_pollsem = sem; + mdthr->pollsem_arena = arena->usarena; + break; + } + } + if (sem == NULL) { + /* + * If no space left in the arena allocate a new one. + */ + if (errno == ENOMEM) { + arena = PR_NEWZAP(nspr_arena); + if (arena != NULL) { + irix_arena = alloc_new_arena(); + if (irix_arena) { + PR_APPEND_LINK(&arena->links, &arena_list); + _nspr_irix_arena_cnt++; + arena->usarena = irix_arena; + sem = usnewpollsema(arena->usarena, val); + if (sem != NULL) { + mdthr->cvar_pollsem = sem; + mdthr->pollsem_arena = arena->usarena; + } else + rv = PR_FAILURE; + } else { + PR_DELETE(arena); + rv = PR_FAILURE; + } + + } else + rv = PR_FAILURE; + } else + rv = PR_FAILURE; + } + _PR_UNLOCK(arena_list_lock); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); + if (rv == PR_SUCCESS) + _MD_ATOMIC_INCREMENT(&_nspr_irix_pollsem_cnt); + return rv; +} + +static void free_poll_sem(struct _MDThread *mdthr) +{ +PRIntn _is; +PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + usfreepollsema(mdthr->cvar_pollsem, mdthr->pollsem_arena); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); + _MD_ATOMIC_DECREMENT(&_nspr_irix_pollsem_cnt); +} + +static PRStatus new_lock(struct _MDLock *lockp) +{ +PRIntn _is; +PRStatus rv = PR_SUCCESS; +ulock_t lock = NULL; +PRCList *qp; +nspr_arena *arena; +usptr_t *irix_arena; +PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + _PR_LOCK(arena_list_lock); + for (qp = arena_list.next; qp != &arena_list; qp = qp->next) { + arena = ARENA_PTR(qp); + lock = usnewlock(arena->usarena); + if (lock != NULL) { + lockp->lock = lock; + lockp->arena = arena->usarena; + break; + } + } + if (lock == NULL) { + /* + * If no space left in the arena allocate a new one. + */ + if (errno == ENOMEM) { + arena = PR_NEWZAP(nspr_arena); + if (arena != NULL) { + irix_arena = alloc_new_arena(); + if (irix_arena) { + PR_APPEND_LINK(&arena->links, &arena_list); + _nspr_irix_arena_cnt++; + arena->usarena = irix_arena; + lock = usnewlock(irix_arena); + if (lock != NULL) { + lockp->lock = lock; + lockp->arena = arena->usarena; + } else + rv = PR_FAILURE; + } else { + PR_DELETE(arena); + rv = PR_FAILURE; + } + + } else + rv = PR_FAILURE; + } else + rv = PR_FAILURE; + } + _PR_UNLOCK(arena_list_lock); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); + if (rv == PR_SUCCESS) + _MD_ATOMIC_INCREMENT(&_nspr_irix_lock_cnt); + return rv; +} + +static void free_lock(struct _MDLock *lockp) +{ +PRIntn _is; +PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + usfreelock(lockp->lock, lockp->arena); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); + _MD_ATOMIC_DECREMENT(&_nspr_irix_lock_cnt); +} + +void _MD_FREE_LOCK(struct _MDLock *lockp) +{ + PRIntn _is; + PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + free_lock(lockp); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); +} + +/* + * _MD_get_attached_thread + * Return the thread pointer of the current thread if it is attached. + * + * This function is needed for Irix because the thread-local-storage is + * implemented by mmapin'g a page with the MAP_LOCAL flag. This causes the + * sproc-private page to inherit contents of the page of the caller of sproc(). + */ +PRThread *_MD_get_attached_thread(void) +{ + + 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 = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + rv = new_lock(lockp); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return rv; +} + +static void +sigchld_handler(int sig) +{ + pid_t pid; + int status; + + /* + * If an sproc exited abnormally send a SIGKILL signal to all the + * sprocs in the process to terminate the application + */ + while ((pid = waitpid(0, &status, WNOHANG)) > 0) { + if (WIFSIGNALED(status) && ((WTERMSIG(status) == SIGSEGV) || + (WTERMSIG(status) == SIGBUS) || + (WTERMSIG(status) == SIGABRT) || + (WTERMSIG(status) == SIGILL))) { + + prctl(PR_SETEXITSIG, SIGKILL); + _exit(status); + } + } +} + +static void save_context_and_block(int sig) +{ +PRThread *me = _PR_MD_CURRENT_THREAD(); +_PRCPU *cpu = _PR_MD_CURRENT_CPU(); + + /* + * save context + */ + (void) setjmp(me->md.jb); + /* + * unblock the suspending thread + */ + if (me->cpu) { + /* + * I am a cpu thread, not a user-created GLOBAL thread + */ + unblockproc(cpu->md.suspending_id); + } else { + unblockproc(me->md.suspending_id); + } + /* + * now, block current thread + */ + blockproc(getpid()); +} + +/* +** The irix kernel has a bug in it which causes async connect's which are +** interrupted by a signal to fail terribly (EADDRINUSE is returned). +** We work around the bug by blocking signals during the async connect +** attempt. +*/ +PRInt32 _MD_irix_connect( + PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout) +{ + PRInt32 rv; + sigset_t oldset; + + sigprocmask(SIG_BLOCK, &ints_off, &oldset); + rv = connect(osfd, addr, addrlen); + sigprocmask(SIG_SETMASK, &oldset, 0); + + return(rv); +} + +#include "prprf.h" + +/********************************************************************/ +/********************************************************************/ +/*************** Various thread like things for IRIX ****************/ +/********************************************************************/ +/********************************************************************/ + +void *_MD_GetSP(PRThread *t) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + void *sp; + + if (me == t) + (void) setjmp(t->md.jb); + + sp = (void *)(t->md.jb[JB_SP]); + PR_ASSERT((sp >= (void *) t->stack->stackBottom) && + (sp <= (void *) (t->stack->stackBottom + t->stack->stackSize))); + return(sp); +} + +void _MD_InitLocks() +{ + char buf[200]; + char *init_users, *init_size; + + PR_snprintf(buf, sizeof(buf), "/dev/zero"); + + if (init_users = getenv("_NSPR_IRIX_INITUSERS")) + _irix_initusers = atoi(init_users); + + if (init_size = getenv("_NSPR_IRIX_INITSIZE")) + _irix_initsize = atoi(init_size); + + usconfig(CONF_INITUSERS, _irix_initusers); + usconfig(CONF_INITSIZE, _irix_initsize); + usconfig(CONF_AUTOGROW, 1); + usconfig(CONF_AUTORESV, 1); + if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) { + perror("PR_Init: unable to config mutex arena"); + exit(-1); + } + + _pr_usArena = usinit(buf); + if (!_pr_usArena) { + fprintf(stderr, + "PR_Init: Error - unable to create lock/monitor arena\n"); + exit(-1); + } + _pr_heapLock = usnewlock(_pr_usArena); + _nspr_irix_lock_cnt++; + + arena_list_lock = usnewlock(_pr_usArena); + _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; + + first_arena.usarena = _pr_usArena; + PR_INIT_CLIST(&first_arena.links); + PR_APPEND_LINK(&first_arena.links, &arena_list); +} + +/* _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_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) +{ + int rv; + +#ifdef _PR_USE_POLL + struct pollfd pfd; + int msecs; + + if (timeout == PR_INTERVAL_NO_TIMEOUT) + msecs = -1; + else + msecs = PR_IntervalToMilliseconds(timeout); +#else + struct timeval tv, *tvp; + fd_set 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; + } + FD_ZERO(&rd); + FD_SET(thread->md.cvar_pollsemfd, &rd); +#endif + + /* + * call uspsema only if a previous select call on this semaphore + * did not timeout + */ + if (!thread->md.cvar_pollsem_select) { + rv = _PR_WAIT_SEM(thread->md.cvar_pollsem); + PR_ASSERT(rv >= 0); + } else + rv = 0; +again: + if(!rv) { +#ifdef _PR_USE_POLL + pfd.events = POLLIN; + pfd.fd = thread->md.cvar_pollsemfd; + rv = _MD_POLL(&pfd, 1, msecs); +#else + rv = _MD_SELECT(thread->md.cvar_pollsemfd + 1, &rd, NULL,NULL,tvp); +#endif + if ((rv == -1) && (errno == EINTR)) { + rv = 0; + goto again; + } + PR_ASSERT(rv >= 0); + } + + if (rv > 0) { + /* + * acquired the semaphore, call uspsema next time + */ + thread->md.cvar_pollsem_select = 0; + return PR_SUCCESS; + } else { + /* + * select timed out; must call select, not uspsema, when trying + * to acquire the semaphore the next time + */ + thread->md.cvar_pollsem_select = 1; + return PR_FAILURE; + } +} + +PRStatus _MD_wait(PRThread *thread, PRIntervalTime ticks) +{ + if ( thread->flags & _PR_GLOBAL_SCOPE ) { + _MD_CHECK_FOR_EXIT(); + if (pr_cvar_wait_sem(thread, ticks) == PR_FAILURE) { + _MD_CHECK_FOR_EXIT(); + /* + * wait timed out + */ + _PR_THREAD_LOCK(thread); + if (thread->wait.cvar) { + /* + * The thread will remove itself from the waitQ + * of the cvar in _PR_WaitCondVar + */ + thread->wait.cvar = NULL; + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + } else { + _PR_THREAD_UNLOCK(thread); + /* + * This thread was woken up by a notifying thread + * at the same time as a timeout; so, consume the + * extra post operation on the semaphore + */ + _MD_CHECK_FOR_EXIT(); + pr_cvar_wait_sem(thread, PR_INTERVAL_NO_TIMEOUT); + } + _MD_CHECK_FOR_EXIT(); + } + } else { + _PR_MD_SWITCH_CONTEXT(thread); + } + return PR_SUCCESS; +} + +PRStatus _MD_WakeupWaiter(PRThread *thread) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntn is; + + PR_ASSERT(_pr_md_idle_cpus >= 0); + if (thread == NULL) { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } else if (!_PR_IS_NATIVE_THREAD(thread)) { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } else { + PR_ASSERT(_PR_IS_NATIVE_THREAD(thread)); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _MD_CVAR_POST_SEM(thread); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + } + 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, +PRThreadScope scope, +PRThreadState state, +PRUint32 stackSize) +{ + typedef void (*SprocEntry) (void *, size_t); + SprocEntry spentry = (SprocEntry)start; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 pid; + PRStatus rv; + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + thread->md.cvar_pollsem_select = 0; + thread->flags |= _PR_GLOBAL_SCOPE; + + 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) { + _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); + return PR_FAILURE; + } +} + +void _MD_CleanThread(PRThread *thread) +{ + if (thread->flags & _PR_GLOBAL_SCOPE) { + close(thread->md.cvar_pollsemfd); + thread->md.cvar_pollsemfd = -1; + free_poll_sem(&thread->md); + thread->md.cvar_pollsem = NULL; + } +} + +void _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri) +{ + return; +} + +extern void _MD_unix_terminate_waitpid_daemon(void); + +void +_MD_CleanupBeforeExit(void) +{ + extern PRInt32 _pr_cpus_exit; + + _MD_unix_terminate_waitpid_daemon(); + + _pr_irix_exit_now = 1; + if (_pr_numCPU > 1) { + /* + * Set a global flag, and wakeup all cpus which will notice the flag + * and exit. + */ + _pr_cpus_exit = getpid(); + _MD_Wakeup_CPUs(); + while(_pr_numCPU > 1) { + _PR_WAIT_SEM(_pr_irix_exit_sem); + _pr_numCPU--; + } + } + /* + * cause global threads on the recycle list to exit + */ + _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; + } + } + _PR_DEADQ_UNLOCK; + while(_PR_NUM_DEADNATIVE > 1) { + _PR_WAIT_SEM(_pr_irix_exit_sem); + _PR_DEC_DEADNATIVE; + } +} + +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK +extern void __sgi_prda_procmask(int); +#endif + +PRStatus +_MD_InitAttachedThread(PRThread *thread, PRBool wakeup_parent) +{ + PRStatus rv = PR_SUCCESS; + + if (thread->flags & _PR_GLOBAL_SCOPE) { + if (new_poll_sem(&thread->md,0) == PR_FAILURE) { + 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); + 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()); +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK + /* + * enable user-level processing of sigprocmask(); this is an + * undocumented feature available in Irix 6.2, 6.3, 6.4 and 6.5 + */ + __sgi_prda_procmask(USER_LEVEL); +#endif + /* + * set up SIGUSR1 handler; this is used to save state + */ + sigact.sa_handler = save_context_and_block; + sigact.sa_flags = SA_RESTART; + /* + * Must mask clock interrupts + */ + sigact.sa_mask = timer_set; + sigaction(SIGUSR1, &sigact, 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 (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 and for reaping sprocs + */ + 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(); + + /* + * the exit code of the process is the exit code of the primordial + * sproc + */ + 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; + + if (!_pr_initialized) { + if (!libc_exit) { + + if (!libc_handle) + libc_handle = dlopen("libc.so",RTLD_NOW); + if (libc_handle) + libc_exit = (void (*)(int)) dlsym(libc_handle, "exit"); + } + if (libc_exit) + (*libc_exit)(status); + else + _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) +{ + extern int _pr_md_pipefd[2]; + + _MD_unix_init_running_cpu(cpu); + cpu->md.id = getpid(); + _MD_SET_SPROC_PID(getpid()); + 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 + } +} + +void +_MD_ExitThread(PRThread *thread) +{ + if (thread->flags & _PR_GLOBAL_SCOPE) { + _MD_ATOMIC_DECREMENT(&_pr_md_irix_sprocs); + _MD_CLEAN_THREAD(thread); + _MD_SET_CURRENT_THREAD(NULL); + } +} + +void +_MD_SuspendCPU(_PRCPU *cpu) +{ + PRInt32 rv; + + cpu->md.suspending_id = getpid(); + rv = kill(cpu->md.id, SIGUSR1); + PR_ASSERT(rv == 0); + /* + * now, block the current thread/cpu until woken up by the suspended + * thread from it's SIGUSR1 signal handler + */ + blockproc(getpid()); + +} + +void +_MD_ResumeCPU(_PRCPU *cpu) +{ + unblockproc(cpu->md.id); +} + +#if 0 +/* + * save the register context of a suspended sproc + */ +void get_context(PRThread *thr) +{ + int len, fd; + char pidstr[24]; + char path[24]; + + /* + * open the file corresponding to this process in procfs + */ + sprintf(path,"/proc/%s","00000"); + len = strlen(path); + sprintf(pidstr,"%d",thr->md.id); + len -= strlen(pidstr); + sprintf(path + len,"%s",pidstr); + fd = open(path,O_RDONLY); + if (fd >= 0) { + (void) ioctl(fd, PIOCGREG, thr->md.gregs); + close(fd); + } + return; +} +#endif /* 0 */ + +void +_MD_SuspendThread(PRThread *thread) +{ + PRInt32 rv; + + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && + _PR_IS_GCABLE_THREAD(thread)); + + thread->md.suspending_id = getpid(); + rv = kill(thread->md.id, SIGUSR1); + PR_ASSERT(rv == 0); + /* + * now, block the current thread/cpu until woken up by the suspended + * thread from it's SIGUSR1 signal handler + */ + blockproc(getpid()); +} + +void +_MD_ResumeThread(PRThread *thread) +{ + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && + _PR_IS_GCABLE_THREAD(thread)); + (void)unblockproc(thread->md.id); +} + +/* + * return the set of processors available for scheduling procs in the + * "mask" argument + */ +PRInt32 _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask) +{ + PRInt32 nprocs, rv; + struct pda_stat *pstat; +#define MAX_PROCESSORS 32 + + nprocs = sysmp(MP_NPROCS); + if (nprocs < 0) + return(-1); + pstat = (struct pda_stat*)PR_MALLOC(sizeof(struct pda_stat) * nprocs); + if (pstat == NULL) + return(-1); + rv = sysmp(MP_STAT, pstat); + if (rv < 0) { + PR_DELETE(pstat); + return(-1); + } + /* + * look at the first 32 cpus + */ + nprocs = (nprocs > MAX_PROCESSORS) ? MAX_PROCESSORS : nprocs; + *mask = 0; + while (nprocs) { + if ((pstat->p_flags & PDAF_ENABLED) && + !(pstat->p_flags & PDAF_ISOLATED)) { + *mask |= (1 << pstat->p_cpuid); + } + nprocs--; + pstat++; + } + return 0; +} + +static char *_thr_state[] = { + "UNBORN", + "RUNNABLE", + "RUNNING", + "LOCK_WAIT", + "COND_WAIT", + "JOIN_WAIT", + "IO_WAIT", + "SUSPENDED", + "DEAD" +}; + +void _PR_List_Threads() +{ + PRThread *thr; + void *handle; + struct _PRCPU *cpu; + PRCList *qp; + int len, fd; + char pidstr[24]; + char path[24]; + prpsinfo_t pinfo; + + + printf("\n%s %-s\n"," ","LOCAL Threads"); + printf("%s %-s\n"," ","----- -------"); + printf("%s %-14s %-10s %-12s %-3s %-10s %-10s %-12s\n\n"," ", + "Thread", "State", "Wait-Handle", + "Cpu","Stk-Base","Stk-Sz","SP"); + for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; + qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { + thr = _PR_ACTIVE_THREAD_PTR(qp); + printf("%s 0x%-12x %-10s "," ",thr,_thr_state[thr->state]); + if (thr->state == _PR_LOCK_WAIT) + handle = thr->wait.lock; + else if (thr->state == _PR_COND_WAIT) + handle = thr->wait.cvar; + else + handle = NULL; + if (handle) + printf("0x%-10x ",handle); + else + printf("%-12s "," "); + printf("%-3d ",thr->cpu->id); + printf("0x%-8x ",thr->stack->stackBottom); + printf("0x%-8x ",thr->stack->stackSize); + printf("0x%-10x\n",thr->md.jb[JB_SP]); + } + + printf("\n%s %-s\n"," ","GLOBAL Threads"); + printf("%s %-s\n"," ","------ -------"); + printf("%s %-14s %-6s %-12s %-12s %-12s %-12s\n\n"," ","Thread", + "Pid","State","Wait-Handle", + "Stk-Base","Stk-Sz"); + + for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; + qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { + thr = _PR_ACTIVE_THREAD_PTR(qp); + if (thr->cpu != NULL) + continue; /* it is a cpu thread */ + printf("%s 0x%-12x %-6d "," ",thr,thr->md.id); + /* + * check if the sproc is still running + * first call prctl(PR_GETSHMASK,pid) to check if + * the process is part of the share group (the pid + * could have been recycled by the OS) + */ + if (prctl(PR_GETSHMASK,thr->md.id) < 0) { + printf("%-12s\n","TERMINATED"); + continue; + } + /* + * Now, check if the sproc terminated and is in zombie + * state + */ + sprintf(path,"/proc/pinfo/%s","00000"); + len = strlen(path); + sprintf(pidstr,"%d",thr->md.id); + len -= strlen(pidstr); + sprintf(path + len,"%s",pidstr); + fd = open(path,O_RDONLY); + if (fd >= 0) { + if (ioctl(fd, PIOCPSINFO, &pinfo) < 0) + printf("%-12s ","TERMINATED"); + else if (pinfo.pr_zomb) + printf("%-12s ","TERMINATED"); + else + printf("%-12s ",_thr_state[thr->state]); + close(fd); + } else { + printf("%-12s ","TERMINATED"); + } + + if (thr->state == _PR_LOCK_WAIT) + handle = thr->wait.lock; + else if (thr->state == _PR_COND_WAIT) + handle = thr->wait.cvar; + else + handle = NULL; + if (handle) + printf("%-12x ",handle); + else + printf("%-12s "," "); + printf("0x%-10x ",thr->stack->stackBottom); + printf("0x%-10x\n",thr->stack->stackSize); + } + + printf("\n%s %-s\n"," ","CPUs"); + printf("%s %-s\n"," ","----"); + printf("%s %-14s %-6s %-12s \n\n"," ","Id","Pid","State"); + + + for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) { + cpu = _PR_CPU_PTR(qp); + printf("%s %-14d %-6d "," ",cpu->id,cpu->md.id); + /* + * check if the sproc is still running + * first call prctl(PR_GETSHMASK,pid) to check if + * the process is part of the share group (the pid + * could have been recycled by the OS) + */ + if (prctl(PR_GETSHMASK,cpu->md.id) < 0) { + printf("%-12s\n","TERMINATED"); + continue; + } + /* + * Now, check if the sproc terminated and is in zombie + * state + */ + sprintf(path,"/proc/pinfo/%s","00000"); + len = strlen(path); + sprintf(pidstr,"%d",cpu->md.id); + len -= strlen(pidstr); + sprintf(path + len,"%s",pidstr); + fd = open(path,O_RDONLY); + if (fd >= 0) { + if (ioctl(fd, PIOCPSINFO, &pinfo) < 0) + printf("%-12s\n","TERMINATED"); + else if (pinfo.pr_zomb) + printf("%-12s\n","TERMINATED"); + else + printf("%-12s\n","RUNNING"); + close(fd); + } else { + printf("%-12s\n","TERMINATED"); + } + + } + fflush(stdout); +} +#endif /* defined(_PR_PTHREADS) */ + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#if !defined(_PR_PTHREADS) + if (isCurrent) { + (void) setjmp(t->md.jb); + } + *np = sizeof(t->md.jb) / sizeof(PRWord); + return (PRWord *) (t->md.jb); +#else + *np = 0; + return NULL; +#endif +} + +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); + sigaddset(&ints_off, SIGIO); + sigaddset(&ints_off, SIGCLD); + + if (eval = getenv("_NSPR_TERMINATE_ON_ERROR")) + _nspr_terminate_on_error = (0 == atoi(eval) == 0) ? PR_FALSE : PR_TRUE; + + fd = open("/dev/zero",O_RDWR , 0); + if (fd < 0) { + perror("open /dev/zero failed"); + exit(1); + } + /* + * Set up the sproc private data area. + * 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 = (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_IrixIntervalInit(); +} /* _MD_EarlyInit */ + +void _MD_IrixInit(void) +{ +#if !defined(_PR_PTHREADS) + struct sigaction sigact; + PRThread *me = _PR_MD_CURRENT_THREAD(); + int rv; + +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK + /* + * enable user-level processing of sigprocmask(); this is an undocumented + * feature available in Irix 6.2, 6.3, 6.4 and 6.5 + */ + __sgi_prda_procmask(USER_LEVEL); +#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; + sigact.sa_mask = ints_off; + sigaction(SIGUSR1, &sigact, 0); + + /* + * Change the name of the core file from core to core.pid, + * This is inherited by the sprocs created by this process + */ +#ifdef PR_COREPID + prctl(PR_COREPID, 0, 1); +#endif + /* + * Irix-specific terminate on error processing + */ + /* + * 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) { + /* + * 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); + + /* + * 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(); +} + +/**************************************************************************/ +/************** code and such for NSPR 2.0's interval times ***************/ +/**************************************************************************/ + +#define PR_PSEC_PER_SEC 1000000000000ULL /* 10^12 */ + +#ifndef SGI_CYCLECNTR_SIZE +#define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ +#endif + +static PRIntn mmem_fd = -1; +static PRIntn clock_width = 0; +static void *iotimer_addr = NULL; +static PRUint32 pr_clock_mask = 0; +static PRUint32 pr_clock_shift = 0; +static PRIntervalTime pr_ticks = 0; +static PRUint32 pr_clock_granularity = 1; +static PRUint32 pr_previous = 0, pr_residual = 0; +static PRUint32 pr_ticks_per_second = 0; + +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +static void _MD_IrixIntervalInit(void) +{ + /* + * As much as I would like, the service available through this + * interface on R3000's (aka, IP12) just isn't going to make it. + * The register is only 24 bits wide, and rolls over at a verocious + * rate. + */ + PRUint32 one_tick = 0; + struct utsname utsinfo; + uname(&utsinfo); + if ((strncmp("IP12", utsinfo.machine, 4) != 0) + && ((mmem_fd = open("/dev/mmem", O_RDONLY)) != -1)) + { + int poffmask = getpagesize() - 1; + __psunsigned_t phys_addr, raddr, cycleval; + + phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); + raddr = phys_addr & ~poffmask; + iotimer_addr = mmap( + 0, poffmask, PROT_READ, MAP_PRIVATE, mmem_fd, (__psint_t)raddr); + + clock_width = syssgi(SGI_CYCLECNTR_SIZE); + if (clock_width < 0) + { + /* + * We must be executing on a 6.0 or earlier system, since the + * SGI_CYCLECNTR_SIZE call is not supported. + * + * The only pre-6.1 platforms with 64-bit counters are + * IP19 and IP21 (Challenge, PowerChallenge, Onyx). + */ + if (!strncmp(utsinfo.machine, "IP19", 4) || + !strncmp(utsinfo.machine, "IP21", 4)) + clock_width = 64; + else + clock_width = 32; + } + + /* + * 'cycleval' is picoseconds / increment of the counter. + * I'm pushing for a tick to be 100 microseconds, 10^(-4). + * That leaves 10^(-8) left over, or 10^8 / cycleval. + * Did I do that right? + */ + + one_tick = 100000000UL / cycleval ; /* 100 microseconds */ + + while (0 != one_tick) + { + pr_clock_shift += 1; + one_tick = one_tick >> 1; + pr_clock_granularity = pr_clock_granularity << 1; + } + pr_clock_mask = pr_clock_granularity - 1; /* to make a mask out of it */ + pr_ticks_per_second = PR_PSEC_PER_SEC + / ((PRUint64)pr_clock_granularity * (PRUint64)cycleval); + + iotimer_addr = (void*) + ((__psunsigned_t)iotimer_addr + (phys_addr & poffmask)); + } + else + { + pr_ticks_per_second = _PR_UNIX_TicksPerSecond(); + } +} /* _MD_IrixIntervalInit */ + +PRIntervalTime _MD_IrixIntervalPerSec(void) +{ + return pr_ticks_per_second; +} + +PRIntervalTime _MD_IrixGetInterval(void) +{ + if (mmem_fd != -1) + { + if (64 == clock_width) + { + PRUint64 temp = *(PRUint64*)iotimer_addr; + pr_ticks = (PRIntervalTime)(temp >> pr_clock_shift); + } + else + { + PRIntervalTime ticks = pr_ticks; + PRUint32 now = *(PRUint32*)iotimer_addr, temp; + PRUint32 residual = pr_residual, previous = pr_previous; + + temp = now - previous + residual; + residual = temp & pr_clock_mask; + ticks += temp >> pr_clock_shift; + + pr_previous = now; + pr_residual = residual; + pr_ticks = ticks; + } + } + else + { + /* + * No fast access. Use the time of day clock. This isn't the + * right answer since this clock can get set back, tick at odd + * rates, and it's expensive to acqurie. + */ + pr_ticks = _PR_UNIX_GetInterval(); + } + return pr_ticks; +} /* _MD_IrixGetInterval */ + diff --git a/nsprpub/pr/src/md/unix/linux.c b/nsprpub/pr/src/md/unix/linux.c new file mode 100644 index 00000000000..c22618d7e0d --- /dev/null +++ b/nsprpub/pr/src/md/unix/linux.c @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifdef _PR_PTHREADS + +extern void _MD_unix_terminate_waitpid_daemon(void); + +void _MD_CleanupBeforeExit(void) +{ + _MD_unix_terminate_waitpid_daemon(); +} + +#else /* ! _PR_PTHREADS */ + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + /* + * set the pointers to the stack-pointer and frame-pointer words in the + * context structure; this is for debugging use. + */ + thread->md.sp = _MD_GET_SP_PTR(thread); + thread->md.fp = _MD_GET_FP_PTR(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 Linux */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Linux."); +} + +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 Linux."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/nsprpub/pr/src/md/unix/ncr.c b/nsprpub/pr/src/md/unix/ncr.c new file mode 100644 index 00000000000..909b09e63b7 --- /dev/null +++ b/nsprpub/pr/src/md/unix/ncr.c @@ -0,0 +1,395 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * NCR 3.0 - cloned from UnixWare by ruslan + */ +#include "primpl.h" + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ + +PRInt32 _MD_connect(PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _connect(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); +} + +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _accept(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); + return(rv); +} +#endif + +/* + * These are also implemented in pratom.c using NSPR locks. Any reason + * this might be better or worse? If you like this better, define + * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h + */ +#ifdef _PR_HAVE_ATOMIC_OPS +/* Atomic operations */ +#include +static FILE *_uw_semf; + +void +_MD_INIT_ATOMIC(void) +{ + /* Sigh. Sure wish SYSV semaphores weren't such a pain to use */ + if ((_uw_semf = tmpfile()) == NULL) + PR_ASSERT(0); + + return; +} + +void +_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)++; + unflockfile(_uw_semf); +} + +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); + (*val)--; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + flockfile(_uw_semf); + *val = newval; + unflockfile(_uw_semf); +} +#endif + +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 Unixware */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Unixware."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRUintn priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware."); + return PR_FAILURE; +} + +/* + This is temp. replacement for localtime_r. Normally PR_ExplodeTime should + be used as to my understanding +*/ + +/* +** $$$$$ THEN WHY ARE WE DOING THIS? - AOF $$$$$ +*/ + +#define NEED_LOCALTIME_R +#define NEED_GMTIME_R +#define NEED_ASCTIME_R +#define NEED_STRTOK_R +#define NEED_CTIME_R + +#if defined (NEED_LOCALTIME_R) || defined (NEED_CTIME_R) || defined (NEED_ASCTIME_R) || defined (NEED_GMTIME_R) || defined (NEED_STRTOK_R) +#include "prlock.h" +#endif + +#if defined (NEED_LOCALTIME_R) + +static PRLock *localtime_r_monitor = NULL; + +struct tm *localtime_r (const time_t *clock, struct tm *result) +{ + struct tm *tmPtr; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + if (localtime_r_monitor == NULL) { + + localtime_r_monitor = PR_NewLock(); + } + PR_Lock(localtime_r_monitor); + } + + /* + * On Windows, localtime() returns a NULL pointer if 'clock' + * represents a time before midnight January 1, 1970. In + * that case, we also return a NULL pointer and the struct tm + * object pointed to by 'result' is not modified. + */ + + tmPtr = localtime(clock); + if (tmPtr) { + *result = *tmPtr; + } else { + result = NULL; + } + + if (needLock) PR_Unlock(localtime_r_monitor); + + return result; +} + +#endif + +#if defined (NEED_GMTIME_R) + +static PRLock *gmtime_r_monitor = NULL; + +struct tm *gmtime_r (const time_t *clock, struct tm *result) +{ + struct tm *tmPtr; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + if (gmtime_r_monitor == NULL) { + gmtime_r_monitor = PR_NewLock(); + } + PR_Lock(gmtime_r_monitor); + } + + tmPtr = gmtime(clock); + if (tmPtr) { + *result = *tmPtr; + } else { + result = NULL; + } + + if (needLock) PR_Unlock(gmtime_r_monitor); + + return result; +} + +#endif + +#if defined (NEED_CTIME_R) + +static PRLock *ctime_r_monitor = NULL; + +char *ctime_r (const time_t *clock, char *buf, int buflen) +{ + char *cbuf; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + + if (ctime_r_monitor == NULL) { + ctime_r_monitor = PR_NewLock(); + } + PR_Lock(ctime_r_monitor); + } + + cbuf = ctime (clock); + if (cbuf) { + strncpy (buf, cbuf, buflen - 1); + buf[buflen - 1] = 0; + } + + if (needLock) PR_Unlock(ctime_r_monitor); + + return cbuf; +} + +#endif + +#if defined (NEED_ASCTIME_R) + +static PRLock *asctime_r_monitor = NULL; + + +char *asctime_r (const struct tm *tm, char *buf, int buflen) +{ + char *cbuf; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + if (asctime_r_monitor == NULL) { + asctime_r_monitor = PR_NewLock(); + } + PR_Lock(asctime_r_monitor); + } + + cbuf = asctime (tm); + if (cbuf) { + strncpy (buf, cbuf, buflen - 1); + buf[buflen - 1] = 0; + } + + if (needLock) PR_Unlock(asctime_r_monitor); + + return cbuf; + +} +#endif + +#if defined (NEED_STRTOK_R) + +char * +strtok_r (s, delim, last) + register char *s; + register const char *delim; + register char **last; +{ + register char *spanp; + register int c, sc; + char *tok; + + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + + else + s[-1] = 0; + *last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +#endif diff --git a/nsprpub/pr/src/md/unix/nec.c b/nsprpub/pr/src/md/unix/nec.c new file mode 100644 index 00000000000..8c97b757d15 --- /dev/null +++ b/nsprpub/pr/src/md/unix/nec.c @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +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 NEC */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for NEC."); +} + +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 NEC."); + return PR_FAILURE; +} diff --git a/nsprpub/pr/src/md/unix/netbsd.c b/nsprpub/pr/src/md/unix/netbsd.c new file mode 100644 index 00000000000..fdef8d7bb43 --- /dev/null +++ b/nsprpub/pr/src/md/unix/netbsd.c @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include +#include + +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 NetBSD */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for NetBSD."); +} + +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 NetBSD."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/nsprpub/pr/src/md/unix/nextstep.c b/nsprpub/pr/src/md/unix/nextstep.c new file mode 100644 index 00000000000..3f87815a778 --- /dev/null +++ b/nsprpub/pr/src/md/unix/nextstep.c @@ -0,0 +1,284 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#import +#import +#import +#include +#include +#include +#include +#include + + + +/* These functions are hidden in NEXTSTEP, but beacuse they have syscall() +** entries I can wrap these into their corresponding missing function. +*/ +caddr_t +mmap(caddr_t addr, size_t len, int prot, int flags, + int fildes, off_t off) +{ + return (caddr_t) syscall (SYS_mmap, addr, len, prot, flags, fildes, off); +} + +int +munmap(caddr_t addr, size_t len) +{ + return syscall (SYS_munmap, addr, len); +} + +int +mprotect(caddr_t addr, size_t len, int prot) +{ + return syscall (SYS_mprotect, addr, len, prot); +} + + +/* If found the brk() symbol in the sahred libraries but no syscall() entry ... +** I don't know whether it will work ... +int brk(void *endds) +{ + return syscall (); +} +*/ + +void *sbrk(int incr) +{ + return (void *) syscall (SYS_sbrk, incr); +} + +/* These are my mach based versions, untested and probably bad ... +*/ +caddr_t my_mmap(caddr_t addr, size_t len, int prot, int flags, + int fildes, off_t off) +{ + kern_return_t ret_val; + + /* First map ... + */ + ret_val = map_fd ( fildes, /* fd */ + (vm_offset_t) off, /* offset */ + (vm_offset_t*)&addr, /* address */ + TRUE, /* find_space */ + (vm_size_t) len); /* size */ + + if (ret_val != KERN_SUCCESS) { + mach_error("Error calling map_fd() in mmap", ret_val ); + return (caddr_t)0; + } + + /* ... then protect (this is probably bad) + */ + ret_val = vm_protect( task_self(), /* target_task */ + (vm_address_t)addr, /* address */ + (vm_size_t) len, /* size */ + FALSE, /* set_maximum */ + (vm_prot_t) prot); /* new_protection */ + if (ret_val != KERN_SUCCESS) { + mach_error("vm_protect in mmap()", ret_val ); + return (caddr_t)0; + } + + return addr; +} + +int my_munmap(caddr_t addr, size_t len) +{ + kern_return_t ret_val; + + ret_val = vm_deallocate(task_self(), + (vm_address_t) addr, + (vm_size_t) len); + + if (ret_val != KERN_SUCCESS) { + mach_error("vm_deallocate in munmap()", ret_val); + return -1; + } + + return 0; +} + +int my_mprotect(caddr_t addr, size_t len, int prot) +{ + vm_prot_t mach_prot; + kern_return_t ret_val; + + switch (prot) { + case PROT_READ: mach_prot = VM_PROT_READ; break; + case PROT_WRITE: mach_prot = VM_PROT_WRITE; break; + case PROT_EXEC: mach_prot = VM_PROT_EXECUTE; break; + case PROT_NONE: mach_prot = VM_PROT_NONE; break; + } + + ret_val = vm_protect(task_self(), /* target_task */ + (vm_address_t)addr, /* address */ + (vm_size_t) len, /* size */ + FALSE, /* set_maximum */ + (vm_prot_t) prot); /* new_protection */ + + if (ret_val != KERN_SUCCESS) { + mach_error("vm_protect in mprotect()", ret_val); + return -1; + } + + return 0; +} + +char *strdup(const char *s1) +{ + int len = strlen (s1); + char *copy = (char*) malloc (len+1); + + if (copy == (char*)0) + return (char*)0; + + strcpy (copy, s1); + + return copy; +} + +/* Stub rld functions +*/ +extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile( + const char *pathName, + NSObjectFileImage *objectFileImage) +{ + return NSObjectFileImageFailure; +} + +extern void * NSAddressOfSymbol( + NSSymbol symbol) +{ + return NULL; +} + +extern NSModule NSLinkModule( + NSObjectFileImage objectFileImage, + const char *moduleName, /* can be NULL */ + enum bool bindNow) +{ + return NULL; +} + +extern NSSymbol NSLookupAndBindSymbol( + const char *symbolName) +{ + return NULL; +} + +extern enum bool NSUnLinkModule( + NSModule module, + enum bool keepMemoryMapped) +{ + return 0; +} + + + +void _MD_EarlyInit(void) +{ +} + +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 NEXTSTEP */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for NEXTSTEP."); +} + +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 NEXTSTEP."); + return PR_FAILURE; +} + +#endif diff --git a/nsprpub/pr/src/md/unix/nto.c b/nsprpub/pr/src/md/unix/nto.c new file mode 100644 index 00000000000..352d93e9a09 --- /dev/null +++ b/nsprpub/pr/src/md/unix/nto.c @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +/* Fake this out */ +int socketpair (int foo, int foo2, int foo3, int sv[2]) +{ + printf("error in socketpair\n"); + exit (-1); +} + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} diff --git a/nsprpub/pr/src/md/unix/objs.mk b/nsprpub/pr/src/md/unix/objs.mk new file mode 100644 index 00000000000..13f2d7d230f --- /dev/null +++ b/nsprpub/pr/src/md/unix/objs.mk @@ -0,0 +1,63 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# This makefile appends to the variable OBJS the platform-dependent +# object modules that will be part of the nspr20 library. + +CSRCS = \ + unix.c \ + unix_errors.c \ + uxproces.c \ + uxrng.c \ + uxshm.c \ + uxwrap.c \ + $(NULL) + +ifneq ($(USE_PTHREADS),1) +CSRCS += uxpoll.c +endif + +ifeq ($(PTHREADS_USER),1) +CSRCS += pthreads_user.c +endif + +CSRCS += $(PR_MD_CSRCS) +ASFILES += $(PR_MD_ASFILES) + +OBJS += $(addprefix md/unix/$(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix md/unix/$(OBJDIR)/,$(ASFILES:.s=.$(OBJ_SUFFIX))) + diff --git a/nsprpub/pr/src/md/unix/openbsd.c b/nsprpub/pr/src/md/unix/openbsd.c new file mode 100644 index 00000000000..1103377fadf --- /dev/null +++ b/nsprpub/pr/src/md/unix/openbsd.c @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include +#include + +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/nsprpub/pr/src/md/unix/openvms.c b/nsprpub/pr/src/md/unix/openvms.c new file mode 100644 index 00000000000..20b4f70880e --- /dev/null +++ b/nsprpub/pr/src/md/unix/openvms.c @@ -0,0 +1,286 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *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 OSF1 */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for OSF1."); +} + +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 OSF1."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ + +#ifdef _PR_HAVE_ATOMIC_CAS + +#include + +#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 */ + + +/* +** thread_suspend and thread_resume are used by the gc code +** in nsprpub/pr/src/pthreads/ptthread.c +** +** These routines are never called for the current thread, and +** there is no check for that - so beware! +*/ +int thread_suspend(PRThread *thr_id) { + + extern int pthread_suspend_np ( + pthread_t thread, + __pthreadLongUint_t *regs, + void *spare); + + __pthreadLongUint_t regs[34]; + int res; + + /* + ** A return res < 0 indicates that the thread was suspended + ** but register information could not be obtained + */ + + res = pthread_suspend_np(thr_id->id,®s[0],0); + if (res==0) + thr_id->sp = (void *) regs[30]; + + thr_id->suspend |= PT_THREAD_SUSPENDED; + + /* Always succeeds */ + return 0; +} + +int thread_resume(PRThread *thr_id) { + extern int pthread_resume_np(pthread_t thread); + int res; + + res = pthread_resume_np (thr_id->id); + + thr_id->suspend |= PT_THREAD_RESUMED; + + return 0; +} + +/* +** Stubs for nspr_symvec.opt +** +** PR_ResumeSet, PR_ResumeTest, and PR_SuspendAllSuspended +** (defined in ptthread.c) used to be exported by mistake +** (because they look like public functions). They have been +** converted into static functions. +** +** There is an existing third-party binary that uses NSPR: the +** Java plugin for Mozilla. Because it is part of the Java +** SDK, we have no control over its releases. So we need these +** stub functions to occupy the slots that used to be occupied +** by PR_ResumeSet, PR_ResumeTest, and PR_SuspendAllSuspended +** in the symbol vector so that LIBNSPR4 is backward compatible. +** +** The Java plugin was also using PR_CreateThread which we didn't +** realise and hadn't "nailed down". So we now need to nail it down +** to its Mozilla 1.1 position and have to insert 51 additional stubs +** in order to achive this (stubs 4-54). +** +** Over time some of these stubs will get reused by new symbols. +** - Stub54 is replaced by LL_MaxUint +*/ + +void PR_VMS_Stub1(void) { } +void PR_VMS_Stub2(void) { } +void PR_VMS_Stub3(void) { } +void PR_VMS_Stub4(void) { } +void PR_VMS_Stub5(void) { } +void PR_VMS_Stub6(void) { } +void PR_VMS_Stub7(void) { } +void PR_VMS_Stub8(void) { } +void PR_VMS_Stub9(void) { } +void PR_VMS_Stub10(void) { } +void PR_VMS_Stub11(void) { } +void PR_VMS_Stub12(void) { } +void PR_VMS_Stub13(void) { } +void PR_VMS_Stub14(void) { } +void PR_VMS_Stub15(void) { } +void PR_VMS_Stub16(void) { } +void PR_VMS_Stub17(void) { } +void PR_VMS_Stub18(void) { } +void PR_VMS_Stub19(void) { } +void PR_VMS_Stub20(void) { } +void PR_VMS_Stub21(void) { } +void PR_VMS_Stub22(void) { } +void PR_VMS_Stub23(void) { } +void PR_VMS_Stub24(void) { } +void PR_VMS_Stub25(void) { } +void PR_VMS_Stub26(void) { } +void PR_VMS_Stub27(void) { } +void PR_VMS_Stub28(void) { } +void PR_VMS_Stub29(void) { } +void PR_VMS_Stub30(void) { } +void PR_VMS_Stub31(void) { } +void PR_VMS_Stub32(void) { } +void PR_VMS_Stub33(void) { } +void PR_VMS_Stub34(void) { } +void PR_VMS_Stub35(void) { } +void PR_VMS_Stub36(void) { } +void PR_VMS_Stub37(void) { } +void PR_VMS_Stub38(void) { } +void PR_VMS_Stub39(void) { } +void PR_VMS_Stub40(void) { } +void PR_VMS_Stub41(void) { } +void PR_VMS_Stub42(void) { } +void PR_VMS_Stub43(void) { } +void PR_VMS_Stub44(void) { } +void PR_VMS_Stub45(void) { } +void PR_VMS_Stub46(void) { } +void PR_VMS_Stub47(void) { } +void PR_VMS_Stub48(void) { } +void PR_VMS_Stub49(void) { } +void PR_VMS_Stub50(void) { } +void PR_VMS_Stub51(void) { } +void PR_VMS_Stub52(void) { } +void PR_VMS_Stub53(void) { } diff --git a/nsprpub/pr/src/md/unix/os_AIX.s b/nsprpub/pr/src/md/unix/os_AIX.s new file mode 100644 index 00000000000..976349e20b8 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_AIX.s @@ -0,0 +1,123 @@ +# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +.set r0,0; .set SP,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.longjmp{TC},"longjmp" + + .lglobl H.10.NO_SYMBOL{PR} + .globl .longjmp + .globl longjmp{DS} + .extern .sigcleanup + .extern .jmprestfpr + +# .text section + + .csect H.10.NO_SYMBOL{PR} +.longjmp: + mr r13,r3 + mr r14,r4 + stu SP,-56(SP) + bl .sigcleanup + l RTOC,0x14(SP) + cal SP,0x38(SP) + mr r3,r13 + mr r4,r14 + l r5,0x8(r3) + l SP,0xc(r3) + l r7,0xf8(r3) + st r7,0x0(SP) + l RTOC,0x10(r3) + bl .jmprestfpr +# 1 == cr0 in disassembly + cmpi 1,r4,0x0 + mtlr r5 + lm r13,0x14(r3) + l r5,0x60(r3) + mtcrf 0x38,r5 + mr r3,r4 + bne __L1 + lil r3,0x1 +__L1: + br + +# traceback table + .long 0x00000000 + .byte 0x00 # VERSION=0 + .byte 0x00 # LANG=TB_C + .byte 0x20 # IS_GL=0,IS_EPROL=0,HAS_TBOFF=1 + # INT_PROC=0,HAS_CTL=0,TOCLESS=0 + # FP_PRESENT=0,LOG_ABORT=0 + .byte 0x40 # INT_HNDL=0,NAME_PRESENT=1 + # USES_ALLOCA=0,CL_DIS_INV=WALK_ONCOND + # SAVES_CR=0,SAVES_LR=0 + .byte 0x80 # STORES_BC=1,FPR_SAVED=0 + .byte 0x00 # GPR_SAVED=0 + .byte 0x02 # FIXEDPARMS=2 + .byte 0x01 # FLOATPARMS=0,PARMSONSTK=1 + .long 0x00000000 # + .long 0x00000014 # TB_OFFSET + .short 7 # NAME_LEN + .byte "longjmp" + .byte 0 # padding + .byte 0 # padding + .byte 0 # padding +# End of traceback table + .long 0x00000000 # "\0\0\0\0" + +# .data section + + .toc # 0x00000038 +T.18.longjmp: + .tc H.18.longjmp{TC},longjmp{DS} + + .csect longjmp{DS} + .long .longjmp # "\0\0\0\0" + .long TOC{TC0} # "\0\0\0008" + .long 0x00000000 # "\0\0\0\0" +# End csect longjmp{DS} + +# .bss section diff --git a/nsprpub/pr/src/md/unix/os_BSD_386_2.s b/nsprpub/pr/src/md/unix/os_BSD_386_2.s new file mode 100644 index 00000000000..1c21b91a0a6 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_BSD_386_2.s @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * os_BSD_386_2.s + * We need to define our own setjmp/longjmp on BSDI 2.x because libc's + * implementation does some sanity checking that defeats user level threads. + * This should no longer be necessary in BSDI 3.0. + */ + +.globl _setjmp +.align 2 +_setjmp: + movl 4(%esp),%eax + movl 0(%esp),%edx + movl %edx, 0(%eax) /* rta */ + movl %ebx, 4(%eax) + movl %esp, 8(%eax) + movl %ebp,12(%eax) + movl %esi,16(%eax) + movl %edi,20(%eax) + movl $0,%eax + ret + +.globl _longjmp +.align 2 +_longjmp: + movl 4(%esp),%edx + movl 8(%esp),%eax + movl 0(%edx),%ecx + movl 4(%edx),%ebx + movl 8(%edx),%esp + movl 12(%edx),%ebp + movl 16(%edx),%esi + movl 20(%edx),%edi + cmpl $0,%eax + jne 1f + movl $1,%eax +1: movl %ecx,0(%esp) + ret diff --git a/nsprpub/pr/src/md/unix/os_Darwin_ppc.s b/nsprpub/pr/src/md/unix/os_Darwin_ppc.s new file mode 100644 index 00000000000..4b61fb4f3bb --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_Darwin_ppc.s @@ -0,0 +1,96 @@ +# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Based on the programming examples in The PowerPC Architecture: +# A Specification for A New Family of RISC Processors, 2nd Ed., +# Book I, Section E.1, "Synchronization," pp. 249-256, May 1994. +# + +.text + +# +# PRInt32 __PR_DarwinPPC_AtomicIncrement(PRInt32 *val); +# + .align 2 + .globl __PR_DarwinPPC_AtomicIncrement +__PR_DarwinPPC_AtomicIncrement: + lwarx r4,0,r3 + addi r0,r4,1 + stwcx. r0,0,r3 + bne- __PR_DarwinPPC_AtomicIncrement + mr r3,r0 + blr + +# +# PRInt32 __PR_DarwinPPC_AtomicDecrement(PRInt32 *val); +# + .align 2 + .globl __PR_DarwinPPC_AtomicDecrement +__PR_DarwinPPC_AtomicDecrement: + lwarx r4,0,r3 + addi r0,r4,-1 + stwcx. r0,0,r3 + bne- __PR_DarwinPPC_AtomicDecrement + mr r3,r0 + blr + +# +# PRInt32 __PR_DarwinPPC_AtomicSet(PRInt32 *val, PRInt32 newval); +# + .align 2 + .globl __PR_DarwinPPC_AtomicSet +__PR_DarwinPPC_AtomicSet: + lwarx r5,0,r3 + stwcx. r4,0,r3 + bne- __PR_DarwinPPC_AtomicSet + mr r3,r5 + blr + +# +# PRInt32 __PR_DarwinPPC_AtomicAdd(PRInt32 *ptr, PRInt32 val); +# + .align 2 + .globl __PR_DarwinPPC_AtomicAdd +__PR_DarwinPPC_AtomicAdd: + lwarx r5,0,r3 + add r0,r4,r5 + stwcx. r0,0,r3 + bne- __PR_DarwinPPC_AtomicAdd + mr r3,r0 + blr diff --git a/nsprpub/pr/src/md/unix/os_Darwin_x86.s b/nsprpub/pr/src/md/unix/os_Darwin_x86.s new file mode 100644 index 00000000000..276b16e032a --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_Darwin_x86.s @@ -0,0 +1,109 @@ +# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Josh Aas +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Based on os_Linux_x86.s +# + +# +# PRInt32 __PR_Darwin_x86_AtomicIncrement(PRInt32 *val); +# +# Atomically increment the integer pointed to by 'val' and return +# the result of the increment. +# + .text + .globl __PR_Darwin_x86_AtomicIncrement + .align 4 +__PR_Darwin_x86_AtomicIncrement: + movl 4(%esp), %ecx + movl $1, %eax + lock + xaddl %eax, (%ecx) + incl %eax + ret + +# +# PRInt32 __PR_Darwin_x86_AtomicDecrement(PRInt32 *val); +# +# Atomically decrement the integer pointed to by 'val' and return +# the result of the decrement. +# + .text + .globl __PR_Darwin_x86_AtomicDecrement + .align 4 +__PR_Darwin_x86_AtomicDecrement: + movl 4(%esp), %ecx + movl $-1, %eax + lock + xaddl %eax, (%ecx) + decl %eax + ret + +# +# PRInt32 __PR_Darwin_x86_AtomicSet(PRInt32 *val, PRInt32 newval); +# +# Atomically set the integer pointed to by 'val' to the new +# value 'newval' and return the old value. +# + .text + .globl __PR_Darwin_x86_AtomicSet + .align 4 +__PR_Darwin_x86_AtomicSet: + movl 4(%esp), %ecx + movl 8(%esp), %eax + xchgl %eax, (%ecx) + ret + +# +# PRInt32 __PR_Darwin_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val); +# +# Atomically add 'val' to the integer pointed to by 'ptr' +# and return the result of the addition. +# + .text + .globl __PR_Darwin_x86_AtomicAdd + .align 4 +__PR_Darwin_x86_AtomicAdd: + movl 4(%esp), %ecx + movl 8(%esp), %eax + movl %eax, %edx + lock + xaddl %eax, (%ecx) + addl %edx, %eax + ret diff --git a/nsprpub/pr/src/md/unix/os_HPUX.s b/nsprpub/pr/src/md/unix/os_HPUX.s new file mode 100644 index 00000000000..ef07db03252 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_HPUX.s @@ -0,0 +1,58 @@ +; +; ***** BEGIN LICENSE BLOCK ***** +; Version: MPL 1.1/GPL 2.0/LGPL 2.1 +; +; The contents of this file are subject to the Mozilla Public License Version +; 1.1 (the "License"); you may not use this file except in compliance with +; the License. You may obtain a copy of the License at +; http://www.mozilla.org/MPL/ +; +; Software distributed under the License is distributed on an "AS IS" basis, +; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +; for the specific language governing rights and limitations under the +; License. +; +; The Original Code is the Netscape Portable Runtime (NSPR). +; +; The Initial Developer of the Original Code is +; Netscape Communications Corporation. +; Portions created by the Initial Developer are Copyright (C) 1998-2000 +; the Initial Developer. All Rights Reserved. +; +; Contributor(s): +; +; Alternatively, the contents of this file may be used under the terms of +; either the GNU General Public License Version 2 or later (the "GPL"), or +; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +; in which case the provisions of the GPL or the LGPL are applicable instead +; of those above. If you wish to allow use of your version of this file only +; under the terms of either the GPL or the LGPL, and not to allow others to +; use your version of this file under the terms of the MPL, indicate your +; decision by deleting the provisions above and replace them with the notice +; and other provisions required by the GPL or the LGPL. If you do not delete +; the provisions above, a recipient may use your version of this file under +; the terms of any one of the MPL, the GPL or the LGPL. +; +; ***** END LICENSE BLOCK ***** + +#ifdef __LP64__ + .LEVEL 2.0W +#else + .LEVEL 1.1 +#endif + + .CODE ; equivalent to the following two lines +; .SPACE $TEXT$,SORT=8 +; .SUBSPA $CODE$,QUAD=0,ALIGN=4,ACCESS=0x2c,CODE_ONLY,SORT=24 + +ret_cr16 + .PROC + .CALLINFO FRAME=0, NO_CALLS + .EXPORT ret_cr16,ENTRY + .ENTER +; BV %r0(%rp) + BV 0(%rp) + MFCTL %cr16,%ret0 + .LEAVE + .PROCEND + .END diff --git a/nsprpub/pr/src/md/unix/os_HPUX_ia64.s b/nsprpub/pr/src/md/unix/os_HPUX_ia64.s new file mode 100644 index 00000000000..9c147936fa3 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_HPUX_ia64.s @@ -0,0 +1,112 @@ +// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// +// ***** BEGIN LICENSE BLOCK ***** +// Version: MPL 1.1/GPL 2.0/LGPL 2.1 +// +// The contents of this file are subject to the Mozilla Public License Version +// 1.1 (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, +// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +// for the specific language governing rights and limitations under the +// License. +// +// The Original Code is the Netscape Portable Runtime (NSPR). +// +// The Initial Developer of the Original Code is +// Netscape Communications Corporation. +// Portions created by the Initial Developer are Copyright (C) 2000 +// the Initial Developer. All Rights Reserved. +// +// Contributor(s): +// +// Alternatively, the contents of this file may be used under the terms of +// either the GNU General Public License Version 2 or later (the "GPL"), or +// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +// in which case the provisions of the GPL or the LGPL are applicable instead +// of those above. If you wish to allow use of your version of this file only +// under the terms of either the GPL or the LGPL, and not to allow others to +// use your version of this file under the terms of the MPL, indicate your +// decision by deleting the provisions above and replace them with the notice +// and other provisions required by the GPL or the LGPL. If you do not delete +// the provisions above, a recipient may use your version of this file under +// the terms of any one of the MPL, the GPL or the LGPL. +// +// ***** END LICENSE BLOCK ***** + +.text + +// PRInt32 _PR_ia64_AtomicIncrement(PRInt32 *val) +// +// Atomically increment the integer pointed to by 'val' and return +// the result of the increment. +// + .align 16 + .global _PR_ia64_AtomicIncrement# + .proc _PR_ia64_AtomicIncrement# +_PR_ia64_AtomicIncrement: +#ifndef _LP64 + addp4 r32 = 0, r32 ;; +#endif + fetchadd4.acq r8 = [r32], 1 ;; + adds r8 = 1, r8 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicIncrement# + +// PRInt32 _PR_ia64_AtomicDecrement(PRInt32 *val) +// +// Atomically decrement the integer pointed to by 'val' and return +// the result of the decrement. +// + .align 16 + .global _PR_ia64_AtomicDecrement# + .proc _PR_ia64_AtomicDecrement# +_PR_ia64_AtomicDecrement: +#ifndef _LP64 + addp4 r32 = 0, r32 ;; +#endif + fetchadd4.rel r8 = [r32], -1 ;; + adds r8 = -1, r8 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicDecrement# + +// PRInt32 _PR_ia64_AtomicAdd(PRInt32 *ptr, PRInt32 val) +// +// Atomically add 'val' to the integer pointed to by 'ptr' +// and return the result of the addition. +// + .align 16 + .global _PR_ia64_AtomicAdd# + .proc _PR_ia64_AtomicAdd# +_PR_ia64_AtomicAdd: +#ifndef _LP64 + addp4 r32 = 0, r32 ;; +#endif + ld4 r15 = [r32] ;; +.L3: + mov r14 = r15 + mov ar.ccv = r15 + add r8 = r15, r33 ;; + cmpxchg4.acq r15 = [r32], r8, ar.ccv ;; + cmp4.ne p6, p7 = r15, r14 + (p6) br.cond.dptk .L3 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicAdd# + +// PRInt32 _PR_ia64_AtomicSet(PRInt32 *val, PRInt32 newval) +// +// Atomically set the integer pointed to by 'val' to the new +// value 'newval' and return the old value. +// + .align 16 + .global _PR_ia64_AtomicSet# + .proc _PR_ia64_AtomicSet# +_PR_ia64_AtomicSet: +#ifndef _LP64 + addp4 r32 = 0, r32 ;; +#endif + xchg4 r8 = [r32], r33 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicSet# diff --git a/nsprpub/pr/src/md/unix/os_Irix.s b/nsprpub/pr/src/md/unix/os_Irix.s new file mode 100644 index 00000000000..e726194e915 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_Irix.s @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * 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 +#include + +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) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + 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 + nop + beq v0,t1,retry_pop + nop + + ll v0,0(a0) + beq v0,0,done + nop + 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: + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + jr ra + nop + +END(PR_StackPop) + +#endif /* _PR_HAVE_ATOMIC_CAS */ diff --git a/nsprpub/pr/src/md/unix/os_Linux_ia64.s b/nsprpub/pr/src/md/unix/os_Linux_ia64.s new file mode 100644 index 00000000000..a97412d15a5 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_Linux_ia64.s @@ -0,0 +1,103 @@ +// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// +// ***** BEGIN LICENSE BLOCK ***** +// Version: MPL 1.1/GPL 2.0/LGPL 2.1 +// +// The contents of this file are subject to the Mozilla Public License Version +// 1.1 (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, +// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +// for the specific language governing rights and limitations under the +// License. +// +// The Original Code is the Netscape Portable Runtime (NSPR). +// +// The Initial Developer of the Original Code is +// Netscape Communications Corporation. +// Portions created by the Initial Developer are Copyright (C) 2000 +// the Initial Developer. All Rights Reserved. +// +// Contributor(s): +// +// Alternatively, the contents of this file may be used under the terms of +// either the GNU General Public License Version 2 or later (the "GPL"), or +// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +// in which case the provisions of the GPL or the LGPL are applicable instead +// of those above. If you wish to allow use of your version of this file only +// under the terms of either the GPL or the LGPL, and not to allow others to +// use your version of this file under the terms of the MPL, indicate your +// decision by deleting the provisions above and replace them with the notice +// and other provisions required by the GPL or the LGPL. If you do not delete +// the provisions above, a recipient may use your version of this file under +// the terms of any one of the MPL, the GPL or the LGPL. +// +// ***** END LICENSE BLOCK ***** + +.text + +// PRInt32 _PR_ia64_AtomicIncrement(PRInt32 *val) +// +// Atomically increment the integer pointed to by 'val' and return +// the result of the increment. +// + .align 16 + .global _PR_ia64_AtomicIncrement# + .proc _PR_ia64_AtomicIncrement# +_PR_ia64_AtomicIncrement: + fetchadd4.acq r8 = [r32], 1 ;; + adds r8 = 1, r8 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicIncrement# + +// PRInt32 _PR_ia64_AtomicDecrement(PRInt32 *val) +// +// Atomically decrement the integer pointed to by 'val' and return +// the result of the decrement. +// + .align 16 + .global _PR_ia64_AtomicDecrement# + .proc _PR_ia64_AtomicDecrement# +_PR_ia64_AtomicDecrement: + fetchadd4.rel r8 = [r32], -1 ;; + adds r8 = -1, r8 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicDecrement# + +// PRInt32 _PR_ia64_AtomicAdd(PRInt32 *ptr, PRInt32 val) +// +// Atomically add 'val' to the integer pointed to by 'ptr' +// and return the result of the addition. +// + .align 16 + .global _PR_ia64_AtomicAdd# + .proc _PR_ia64_AtomicAdd# +_PR_ia64_AtomicAdd: + ld4 r15 = [r32] ;; +.L3: + mov r14 = r15 + mov ar.ccv = r15 + add r8 = r15, r33 ;; + cmpxchg4.acq r15 = [r32], r8, ar.ccv ;; + cmp4.ne p6, p7 = r15, r14 + (p6) br.cond.dptk .L3 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicAdd# + +// PRInt32 _PR_ia64_AtomicSet(PRInt32 *val, PRInt32 newval) +// +// Atomically set the integer pointed to by 'val' to the new +// value 'newval' and return the old value. +// + .align 16 + .global _PR_ia64_AtomicSet# + .proc _PR_ia64_AtomicSet# +_PR_ia64_AtomicSet: + xchg4 r8 = [r32], r33 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicSet# + +// Magic indicating no need for an executable stack +.section .note.GNU-stack, "", @progbits ; .previous diff --git a/nsprpub/pr/src/md/unix/os_Linux_ppc.s b/nsprpub/pr/src/md/unix/os_Linux_ppc.s new file mode 100644 index 00000000000..0e1c195d2f6 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_Linux_ppc.s @@ -0,0 +1,107 @@ +# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Based on the programming examples in The PowerPC Architecture: +# A Specification for A New Family of RISC Processors, 2nd Ed., +# Book I, Section E.1, "Synchronization," pp. 249-256, May 1994. +# + + .section ".text" + +# +# PRInt32 _PR_ppc_AtomicIncrement(PRInt32 *val); +# + .align 2 + .globl _PR_ppc_AtomicIncrement + .type _PR_ppc_AtomicIncrement,@function +_PR_ppc_AtomicIncrement: +.Lfd1: lwarx 4,0,3 + addi 0,4,1 + stwcx. 0,0,3 + bne- .Lfd1 + mr 3,0 + blr +.Lfe1: .size _PR_ppc_AtomicIncrement,.Lfe1-_PR_ppc_AtomicIncrement + +# +# PRInt32 _PR_ppc_AtomicDecrement(PRInt32 *val); +# + .align 2 + .globl _PR_ppc_AtomicDecrement + .type _PR_ppc_AtomicDecrement,@function +_PR_ppc_AtomicDecrement: +.Lfd2: lwarx 4,0,3 + addi 0,4,-1 + stwcx. 0,0,3 + bne- .Lfd2 + mr 3,0 + blr +.Lfe2: .size _PR_ppc_AtomicDecrement,.Lfe2-_PR_ppc_AtomicDecrement + +# +# PRInt32 _PR_ppc_AtomicSet(PRInt32 *val, PRInt32 newval); +# + .align 2 + .globl _PR_ppc_AtomicSet + .type _PR_ppc_AtomicSet,@function +_PR_ppc_AtomicSet: +.Lfd3: lwarx 5,0,3 + stwcx. 4,0,3 + bne- .Lfd3 + mr 3,5 + blr +.Lfe3: .size _PR_ppc_AtomicSet,.Lfe3-_PR_ppc_AtomicSet + +# +# PRInt32 _PR_ppc_AtomicAdd(PRInt32 *ptr, PRInt32 val); +# + .align 2 + .globl _PR_ppc_AtomicAdd + .type _PR_ppc_AtomicAdd,@function +_PR_ppc_AtomicAdd: +.Lfd4: lwarx 5,0,3 + add 0,4,5 + stwcx. 0,0,3 + bne- .Lfd4 + mr 3,0 + blr +.Lfe4: .size _PR_ppc_AtomicAdd,.Lfe4-_PR_ppc_AtomicAdd + +# Magic indicating no need for an executable stack +.section .note.GNU-stack, "", @progbits ; .previous diff --git a/nsprpub/pr/src/md/unix/os_Linux_x86.s b/nsprpub/pr/src/md/unix/os_Linux_x86.s new file mode 100644 index 00000000000..5ae21aa4074 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_Linux_x86.s @@ -0,0 +1,117 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ ***** BEGIN LICENSE BLOCK ***** +/ Version: MPL 1.1/GPL 2.0/LGPL 2.1 +/ +/ The contents of this file are subject to the Mozilla Public License Version +/ 1.1 (the "License"); you may not use this file except in compliance with +/ the License. You may obtain a copy of the License at +/ http://www.mozilla.org/MPL/ +/ +/ Software distributed under the License is distributed on an "AS IS" basis, +/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +/ for the specific language governing rights and limitations under the +/ License. +/ +/ The Original Code is the Netscape Portable Runtime (NSPR). +/ +/ The Initial Developer of the Original Code is +/ Netscape Communications Corporation. +/ Portions created by the Initial Developer are Copyright (C) 2000 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the terms of +/ either the GNU General Public License Version 2 or later (the "GPL"), or +/ the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +/ in which case the provisions of the GPL or the LGPL are applicable instead +/ of those above. If you wish to allow use of your version of this file only +/ under the terms of either the GPL or the LGPL, and not to allow others to +/ use your version of this file under the terms of the MPL, indicate your +/ decision by deleting the provisions above and replace them with the notice +/ and other provisions required by the GPL or the LGPL. If you do not delete +/ the provisions above, a recipient may use your version of this file under +/ the terms of any one of the MPL, the GPL or the LGPL. +/ +/ ***** END LICENSE BLOCK ***** + +/ PRInt32 _PR_x86_AtomicIncrement(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl _PR_x86_AtomicIncrement + .align 4 +_PR_x86_AtomicIncrement: + movl 4(%esp), %ecx + movl $1, %eax + lock + xaddl %eax, (%ecx) + incl %eax + ret + +/ PRInt32 _PR_x86_AtomicDecrement(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl _PR_x86_AtomicDecrement + .align 4 +_PR_x86_AtomicDecrement: + movl 4(%esp), %ecx + movl $-1, %eax + lock + xaddl %eax, (%ecx) + decl %eax + ret + +/ PRInt32 _PR_x86_AtomicSet(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ +/ An alternative implementation: +/ .text +/ .globl _PR_x86_AtomicSet +/ .align 4 +/_PR_x86_AtomicSet: +/ movl 4(%esp), %ecx +/ movl 8(%esp), %edx +/ movl (%ecx), %eax +/retry: +/ lock +/ cmpxchgl %edx, (%ecx) +/ jne retry +/ ret +/ + .text + .globl _PR_x86_AtomicSet + .align 4 +_PR_x86_AtomicSet: + movl 4(%esp), %ecx + movl 8(%esp), %eax + xchgl %eax, (%ecx) + ret + +/ PRInt32 _PR_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl _PR_x86_AtomicAdd + .align 4 +_PR_x86_AtomicAdd: + movl 4(%esp), %ecx + movl 8(%esp), %eax + movl %eax, %edx + lock + xaddl %eax, (%ecx) + addl %edx, %eax + ret + +/ Magic indicating no need for an executable stack +.section .note.GNU-stack, "", @progbits ; .previous diff --git a/nsprpub/pr/src/md/unix/os_Linux_x86_64.s b/nsprpub/pr/src/md/unix/os_Linux_x86_64.s new file mode 100644 index 00000000000..1a7b24a8005 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_Linux_x86_64.s @@ -0,0 +1,98 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ ***** BEGIN LICENSE BLOCK ***** +/ Version: MPL 1.1/GPL 2.0/LGPL 2.1 +/ +/ The contents of this file are subject to the Mozilla Public License Version +/ 1.1 (the "License"); you may not use this file except in compliance with +/ the License. You may obtain a copy of the License at +/ http://www.mozilla.org/MPL/ +/ +/ Software distributed under the License is distributed on an "AS IS" basis, +/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +/ for the specific language governing rights and limitations under the +/ License. +/ +/ The Original Code is the Netscape Portable Runtime (NSPR). +/ +/ The Initial Developer of the Original Code is +/ Netscape Communications Corporation. +/ Portions created by the Initial Developer are Copyright (C) 2004 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the terms of +/ either the GNU General Public License Version 2 or later (the "GPL"), or +/ the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +/ in which case the provisions of the GPL or the LGPL are applicable instead +/ of those above. If you wish to allow use of your version of this file only +/ under the terms of either the GPL or the LGPL, and not to allow others to +/ use your version of this file under the terms of the MPL, indicate your +/ decision by deleting the provisions above and replace them with the notice +/ and other provisions required by the GPL or the LGPL. If you do not delete +/ the provisions above, a recipient may use your version of this file under +/ the terms of any one of the MPL, the GPL or the LGPL. +/ +/ ***** END LICENSE BLOCK ***** + +/ PRInt32 _PR_x86_64_AtomicIncrement(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl _PR_x86_64_AtomicIncrement + .align 4 +_PR_x86_64_AtomicIncrement: + movl $1, %eax + lock + xaddl %eax, (%rdi) + incl %eax + ret + +/ PRInt32 _PR_x86_64_AtomicDecrement(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl _PR_x86_64_AtomicDecrement + .align 4 +_PR_x86_64_AtomicDecrement: + movl $-1, %eax + lock + xaddl %eax, (%rdi) + decl %eax + ret + +/ PRInt32 _PR_x86_64_AtomicSet(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ + .text + .globl _PR_x86_64_AtomicSet + .align 4 +_PR_x86_64_AtomicSet: + movl %esi, %eax + xchgl %eax, (%rdi) + ret + +/ PRInt32 _PR_x86_64_AtomicAdd(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl _PR_x86_64_AtomicAdd + .align 4 +_PR_x86_64_AtomicAdd: + movl %esi, %eax + lock + xaddl %eax, (%rdi) + addl %esi, %eax + ret + +/ Magic indicating no need for an executable stack +.section .note.GNU-stack, "", @progbits ; .previous diff --git a/nsprpub/pr/src/md/unix/os_ReliantUNIX.s b/nsprpub/pr/src/md/unix/os_ReliantUNIX.s new file mode 100644 index 00000000000..7aef248db00 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_ReliantUNIX.s @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* We want position independent code */ +#define PIC + +#include +#include +#include + + .file 1 "os_ReliantUNIX.s" + .option pic2 + .text + + .align 2 + .globl getcxt + .ent getcxt +getcxt: + .frame sp,0,$31 # vars= 0, regs= 0/0, args= 0, extra= 0 + # saved integer regs + sw ra,180(a0) # gpregs[CXT_EPC] + sw gp,152(a0) # gpregs[CXT_GP] + sw sp,156(a0) # gpregs[CXT_SP] + sw s8,160(a0) # gpregs[CXT_S8] + sw s0,104(a0) # gpregs[CXT_S0] + sw s1,108(a0) # gpregs[CXT_S1] + sw s2,112(a0) # gpregs[CXT_S2] + sw s3,116(a0) # gpregs[CXT_S3] + sw s4,120(a0) # gpregs[CXT_S4] + sw s5,124(a0) # gpregs[CXT_S5] + sw s6,128(a0) # gpregs[CXT_S6] + sw s7,132(a0) # gpregs[CXT_S7] + # csr + cfc1 v0,$31 + # saved float regs + s.d $f20,264(a0) # fpregs.fp_r.fp_dregs[10] + s.d $f22,272(a0) # fpregs.fp_r.fp_dregs[11] + s.d $f24,280(a0) # fpregs.fp_r.fp_dregs[12] + s.d $f26,288(a0) # fpregs.fp_r.fp_dregs[13] + s.d $f28,296(a0) # fpregs.fp_r.fp_dregs[14] + s.d $f30,304(a0) # fpregs.fp_r.fp_dregs[15] + sw v0,312(a0) # fpregs.fp_csr + + # give no illusions about the contents + li v0,0x0c # UC_CPU | UC_MAU + sw v0,0(a0) # uc_flags + + move v0,zero + j ra + .end getcxt + + .align 2 + .globl setcxt + .ent setcxt +setcxt: + .frame sp,0,$31 # vars= 0, regs= 0/0, args= 0, extra= 0 + lw v0,312(a0) # fpregs.fp_csr + li v1,0xfffc0fff # mask out exception cause bits + and v0,v0,v1 + # saved integer regs + lw t9,180(a0) # gpregs[CXT_EPC] + lw ra,180(a0) # gpregs[CXT_EPC] + lw gp,152(a0) # gpregs[CXT_GP] + lw sp,156(a0) # gpregs[CXT_SP] + ctc1 v0,$31 # fp_csr + lw s8,160(a0) # gpregs[CXT_S8] + lw s0,104(a0) # gpregs[CXT_S0] + lw s1,108(a0) # gpregs[CXT_S1] + lw s2,112(a0) # gpregs[CXT_S2] + lw s3,116(a0) # gpregs[CXT_S3] + lw s4,120(a0) # gpregs[CXT_S4] + lw s5,124(a0) # gpregs[CXT_S5] + lw s6,128(a0) # gpregs[CXT_S6] + lw s7,132(a0) # gpregs[CXT_S7] + # saved float regs + l.d $f20,264(a0) # fpregs.fp_r.fp_dregs[10] + l.d $f22,272(a0) # fpregs.fp_r.fp_dregs[11] + l.d $f24,280(a0) # fpregs.fp_r.fp_dregs[12] + l.d $f26,288(a0) # fpregs.fp_r.fp_dregs[13] + l.d $f28,296(a0) # fpregs.fp_r.fp_dregs[14] + l.d $f30,304(a0) # fpregs.fp_r.fp_dregs[15] + + # load these, too + # they were not saved, but maybe the user modified them... + lw v0,48(a0) + lw v1,52(a0) + lw a1,60(a0) + lw a2,64(a0) + lw a3,68(a0) + lw a0,56(a0) # there is no way back + + j ra + + .end setcxt diff --git a/nsprpub/pr/src/md/unix/os_SunOS.s b/nsprpub/pr/src/md/unix/os_SunOS.s new file mode 100644 index 00000000000..15aac59974e --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_SunOS.s @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + .text + +/* + * sol_getsp() + * + * Return the current sp (for debugging) + */ + .global sol_getsp +sol_getsp: + retl + mov %sp, %o0 + + +/* + * sol_curthread() + * + * Return a unique identifier for the currently active thread. + */ + .global sol_curthread +sol_curthread: + retl + mov %g7, %o0 + + + .global __MD_FlushRegisterWindows + .global _MD_FlushRegisterWindows + +__MD_FlushRegisterWindows: +_MD_FlushRegisterWindows: + + ta 3 + ret + restore + diff --git a/nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s b/nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s new file mode 100644 index 00000000000..d3f1e69eb93 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s @@ -0,0 +1,205 @@ +! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +! +! ***** BEGIN LICENSE BLOCK ***** +! Version: MPL 1.1/GPL 2.0/LGPL 2.1 +! +! The contents of this file are subject to the Mozilla Public License Version +! 1.1 (the "License"); you may not use this file except in compliance with +! the License. You may obtain a copy of the License at +! http://www.mozilla.org/MPL/ +! +! Software distributed under the License is distributed on an "AS IS" basis, +! WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +! for the specific language governing rights and limitations under the +! License. +! +! The Original Code is the Netscape Portable Runtime (NSPR). +! +! The Initial Developer of the Original Code is +! Netscape Communications Corporation. +! Portions created by the Initial Developer are Copyright (C) 1998-2000 +! the Initial Developer. All Rights Reserved. +! +! Contributor(s): +! +! Alternatively, the contents of this file may be used under the terms of +! either the GNU General Public License Version 2 or later (the "GPL"), or +! the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +! in which case the provisions of the GPL or the LGPL are applicable instead +! of those above. If you wish to allow use of your version of this file only +! under the terms of either the GPL or the LGPL, and not to allow others to +! use your version of this file under the terms of the MPL, indicate your +! decision by deleting the provisions above and replace them with the notice +! and other provisions required by the GPL or the LGPL. If you do not delete +! the provisions above, a recipient may use your version of this file under +! the terms of any one of the MPL, the GPL or the LGPL. +! +! ***** END LICENSE BLOCK ***** + +! +! atomic increment, decrement and swap routines for V8+ sparc (ultrasparc) +! using CAS (compare-and-swap) atomic instructions +! +! this MUST be compiled with an ultrasparc-aware assembler +! +! standard asm linkage macros; this module must be compiled +! with the -P option (use C preprocessor) + +#include + +! ====================================================================== +! +! Perform the sequence a = a + 1 atomically with respect to other +! fetch-and-adds to location a in a wait-free fashion. +! +! usage : val = PR_AtomicIncrement(address) +! return: current value (you'd think this would be old val) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [local] - work register +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(_MD_AtomicIncrement) ! standard assembler/ELF prologue + +retryAI: + ld [%o0], %o2 ! set o2 to the current value + add %o2, 0x1, %o3 ! calc the new value + mov %o3, %o1 ! 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 retryAI ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o1, %o0 ! set the return code to the new value + + SET_SIZE(_MD_AtomicIncrement) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = a - 1 atomically with respect to other +! fetch-and-decs to location a in a wait-free fashion. +! +! usage : val = PR_AtomicDecrement(address) +! return: current value (you'd think this would be old val) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [local] - work register +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(_MD_AtomicDecrement) ! standard assembler/ELF prologue + +retryAD: + ld [%o0], %o2 ! set o2 to the current value + sub %o2, 0x1, %o3 ! calc the new value + mov %o3, %o1 ! 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 retryAD ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o1, %o0 ! set the return code to the new value + + SET_SIZE(_MD_AtomicDecrement) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = b atomically with respect to other +! fetch-and-stores to location a in a wait-free fashion. +! +! usage : old_val = PR_AtomicSet(address, newval) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [input] - the new value to set for [%o0] +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(_MD_AtomicSet) ! standard assembler/ELF prologue + +retryAS: + ld [%o0], %o2 ! set o2 to the current value + mov %o1, %o3 ! set up the new value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAS ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o3, %o0 ! set the return code to the prev value + + SET_SIZE(_MD_AtomicSet) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! 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(_MD_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(_MD_AtomicAdd) ! standard assembler/ELF epilogue + +! +! end +! diff --git a/nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s b/nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s new file mode 100644 index 00000000000..08c8e072dfc --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s @@ -0,0 +1,205 @@ +! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +! +! ***** BEGIN LICENSE BLOCK ***** +! Version: MPL 1.1/GPL 2.0/LGPL 2.1 +! +! The contents of this file are subject to the Mozilla Public License Version +! 1.1 (the "License"); you may not use this file except in compliance with +! the License. You may obtain a copy of the License at +! http://www.mozilla.org/MPL/ +! +! Software distributed under the License is distributed on an "AS IS" basis, +! WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +! for the specific language governing rights and limitations under the +! License. +! +! The Original Code is the Netscape Portable Runtime (NSPR). +! +! The Initial Developer of the Original Code is +! Netscape Communications Corporation. +! Portions created by the Initial Developer are Copyright (C) 1998-2000 +! the Initial Developer. All Rights Reserved. +! +! Contributor(s): +! +! Alternatively, the contents of this file may be used under the terms of +! either the GNU General Public License Version 2 or later (the "GPL"), or +! the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +! in which case the provisions of the GPL or the LGPL are applicable instead +! of those above. If you wish to allow use of your version of this file only +! under the terms of either the GPL or the LGPL, and not to allow others to +! use your version of this file under the terms of the MPL, indicate your +! decision by deleting the provisions above and replace them with the notice +! and other provisions required by the GPL or the LGPL. If you do not delete +! the provisions above, a recipient may use your version of this file under +! the terms of any one of the MPL, the GPL or the LGPL. +! +! ***** END LICENSE BLOCK ***** + +! +! atomic increment, decrement and swap routines for V8+ sparc (ultrasparc) +! using CAS (compare-and-swap) atomic instructions +! +! this MUST be compiled with an ultrasparc-aware assembler +! +! standard asm linkage macros; this module must be compiled +! with the -P option (use C preprocessor) + +#include + +! ====================================================================== +! +! Perform the sequence a = a + 1 atomically with respect to other +! fetch-and-adds to location a in a wait-free fashion. +! +! usage : val = PR_AtomicIncrement(address) +! return: current value (you'd think this would be old val) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [local] - work register +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(PR_AtomicIncrement) ! standard assembler/ELF prologue + +retryAI: + ld [%o0], %o2 ! set o2 to the current value + add %o2, 0x1, %o3 ! calc the new value + mov %o3, %o1 ! 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 retryAI ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o1, %o0 ! set the return code to the new value + + SET_SIZE(PR_AtomicIncrement) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = a - 1 atomically with respect to other +! fetch-and-decs to location a in a wait-free fashion. +! +! usage : val = PR_AtomicDecrement(address) +! return: current value (you'd think this would be old val) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [local] - work register +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(PR_AtomicDecrement) ! standard assembler/ELF prologue + +retryAD: + ld [%o0], %o2 ! set o2 to the current value + sub %o2, 0x1, %o3 ! calc the new value + mov %o3, %o1 ! 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 retryAD ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o1, %o0 ! set the return code to the new value + + SET_SIZE(PR_AtomicDecrement) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = b atomically with respect to other +! fetch-and-stores to location a in a wait-free fashion. +! +! usage : old_val = PR_AtomicSet(address, newval) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [input] - the new value to set for [%o0] +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(PR_AtomicSet) ! standard assembler/ELF prologue + +retryAS: + ld [%o0], %o2 ! set o2 to the current value + mov %o1, %o3 ! set up the new value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAS ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o3, %o0 ! set the return code to the prev value + + SET_SIZE(PR_AtomicSet) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! 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/nsprpub/pr/src/md/unix/os_SunOS_x86.s b/nsprpub/pr/src/md/unix/os_SunOS_x86.s new file mode 100644 index 00000000000..75ddfa61d4b --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_SunOS_x86.s @@ -0,0 +1,158 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ ***** BEGIN LICENSE BLOCK ***** +/ Version: MPL 1.1/GPL 2.0/LGPL 2.1 +/ +/ The contents of this file are subject to the Mozilla Public License Version +/ 1.1 (the "License"); you may not use this file except in compliance with +/ the License. You may obtain a copy of the License at +/ http://www.mozilla.org/MPL/ +/ +/ Software distributed under the License is distributed on an "AS IS" basis, +/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +/ for the specific language governing rights and limitations under the +/ License. +/ +/ The Original Code is the Netscape Portable Runtime (NSPR). +/ +/ The Initial Developer of the Original Code is +/ Netscape Communications Corporation. +/ Portions created by the Initial Developer are Copyright (C) 1998-2000 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the terms of +/ either the GNU General Public License Version 2 or later (the "GPL"), or +/ the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +/ in which case the provisions of the GPL or the LGPL are applicable instead +/ of those above. If you wish to allow use of your version of this file only +/ under the terms of either the GPL or the LGPL, and not to allow others to +/ use your version of this file under the terms of the MPL, indicate your +/ decision by deleting the provisions above and replace them with the notice +/ and other provisions required by the GPL or the LGPL. If you do not delete +/ the provisions above, a recipient may use your version of this file under +/ the terms of any one of the MPL, the GPL or the LGPL. +/ +/ ***** END LICENSE BLOCK ***** + + .text + + .globl getedi +getedi: + movl %edi,%eax + ret + .type getedi,@function + .size getedi,.-getedi + + .globl setedi +setedi: + movl 4(%esp),%edi + ret + .type setedi,@function + .size setedi,.-setedi + + .globl __MD_FlushRegisterWindows + .globl _MD_FlushRegisterWindows + +__MD_FlushRegisterWindows: +_MD_FlushRegisterWindows: + + ret + +/ +/ sol_getsp() +/ +/ Return the current sp (for debugging) +/ + .globl sol_getsp +sol_getsp: + movl %esp, %eax + ret + +/ +/ sol_curthread() +/ +/ Return a unique identifier for the currently active thread. +/ + .globl sol_curthread +sol_curthread: + movl %ecx, %eax + ret + +/ PRInt32 _MD_AtomicIncrement(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl _MD_AtomicIncrement + .align 4 +_MD_AtomicIncrement: + movl 4(%esp), %ecx + movl $1, %eax + lock + xaddl %eax, (%ecx) + incl %eax + ret + +/ PRInt32 _MD_AtomicDecrement(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl _MD_AtomicDecrement + .align 4 +_MD_AtomicDecrement: + movl 4(%esp), %ecx + movl $-1, %eax + lock + xaddl %eax, (%ecx) + decl %eax + ret + +/ PRInt32 _MD_AtomicSet(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ +/ An alternative implementation: +/ .text +/ .globl _MD_AtomicSet +/ .align 4 +/_MD_AtomicSet: +/ movl 4(%esp), %ecx +/ movl 8(%esp), %edx +/ movl (%ecx), %eax +/retry: +/ lock +/ cmpxchgl %edx, (%ecx) +/ jne retry +/ ret +/ + .text + .globl _MD_AtomicSet + .align 4 +_MD_AtomicSet: + movl 4(%esp), %ecx + movl 8(%esp), %eax + xchgl %eax, (%ecx) + ret + +/ PRInt32 _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl _MD_AtomicAdd + .align 4 +_MD_AtomicAdd: + movl 4(%esp), %ecx + movl 8(%esp), %eax + movl %eax, %edx + lock + xaddl %eax, (%ecx) + addl %edx, %eax + ret diff --git a/nsprpub/pr/src/md/unix/os_SunOS_x86_64.s b/nsprpub/pr/src/md/unix/os_SunOS_x86_64.s new file mode 100644 index 00000000000..3c5ac393ab8 --- /dev/null +++ b/nsprpub/pr/src/md/unix/os_SunOS_x86_64.s @@ -0,0 +1,95 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ ***** BEGIN LICENSE BLOCK ***** +/ Version: MPL 1.1/GPL 2.0/LGPL 2.1 +/ +/ The contents of this file are subject to the Mozilla Public License Version +/ 1.1 (the "License"); you may not use this file except in compliance with +/ the License. You may obtain a copy of the License at +/ http://www.mozilla.org/MPL/ +/ +/ Software distributed under the License is distributed on an "AS IS" basis, +/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +/ for the specific language governing rights and limitations under the +/ License. +/ +/ The Original Code is the Netscape Portable Runtime (NSPR). +/ +/ The Initial Developer of the Original Code is +/ Netscape Communications Corporation. +/ Portions created by the Initial Developer are Copyright (C) 2004 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the terms of +/ either the GNU General Public License Version 2 or later (the "GPL"), or +/ the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +/ in which case the provisions of the GPL or the LGPL are applicable instead +/ of those above. If you wish to allow use of your version of this file only +/ under the terms of either the GPL or the LGPL, and not to allow others to +/ use your version of this file under the terms of the MPL, indicate your +/ decision by deleting the provisions above and replace them with the notice +/ and other provisions required by the GPL or the LGPL. If you do not delete +/ the provisions above, a recipient may use your version of this file under +/ the terms of any one of the MPL, the GPL or the LGPL. +/ +/ ***** END LICENSE BLOCK ***** + +/ PRInt32 _MD_AtomicIncrement(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl _MD_AtomicIncrement + .align 4 +_MD_AtomicIncrement: + movl $1, %eax + lock + xaddl %eax, (%rdi) + incl %eax + ret + +/ PRInt32 _MD_AtomicDecrement(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl _MD_AtomicDecrement + .align 4 +_MD_AtomicDecrement: + movl $-1, %eax + lock + xaddl %eax, (%rdi) + decl %eax + ret + +/ PRInt32 _MD_AtomicSet(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ + .text + .globl _MD_AtomicSet + .align 4 +_MD_AtomicSet: + movl %esi, %eax + xchgl %eax, (%rdi) + ret + +/ PRInt32 _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl _MD_AtomicAdd + .align 4 +_MD_AtomicAdd: + movl %esi, %eax + lock + xaddl %eax, (%rdi) + addl %esi, %eax + ret diff --git a/nsprpub/pr/src/md/unix/osf1.c b/nsprpub/pr/src/md/unix/osf1.c new file mode 100644 index 00000000000..a4cd6a5123b --- /dev/null +++ b/nsprpub/pr/src/md/unix/osf1.c @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *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 OSF1 */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for OSF1."); +} + +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 OSF1."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/nsprpub/pr/src/md/unix/pthreads_user.c b/nsprpub/pr/src/md/unix/pthreads_user.c new file mode 100644 index 00000000000..21e5f0b8b90 --- /dev/null +++ b/nsprpub/pr/src/md/unix/pthreads_user.c @@ -0,0 +1,480 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include +#include +#include +#include + + +sigset_t ints_off; +pthread_mutex_t _pr_heapLock; +pthread_key_t current_thread_key; +pthread_key_t current_cpu_key; +pthread_key_t last_thread_key; +pthread_key_t intsoff_key; + + +PRInt32 _pr_md_pthreads_created, _pr_md_pthreads_failed; +PRInt32 _pr_md_pthreads = 1; + +void _MD_EarlyInit(void) +{ +extern PRInt32 _nspr_noclock; + + if (pthread_key_create(¤t_thread_key, NULL) != 0) { + perror("pthread_key_create failed"); + exit(1); + } + if (pthread_key_create(¤t_cpu_key, NULL) != 0) { + perror("pthread_key_create failed"); + exit(1); + } + if (pthread_key_create(&last_thread_key, NULL) != 0) { + perror("pthread_key_create failed"); + exit(1); + } + if (pthread_key_create(&intsoff_key, NULL) != 0) { + perror("pthread_key_create failed"); + exit(1); + } + + sigemptyset(&ints_off); + sigaddset(&ints_off, SIGALRM); + sigaddset(&ints_off, SIGIO); + sigaddset(&ints_off, SIGCLD); + + /* + * disable clock interrupts + */ + _nspr_noclock = 1; + +} + +void _MD_InitLocks() +{ + if (pthread_mutex_init(&_pr_heapLock, NULL) != 0) { + perror("pthread_mutex_init failed"); + exit(1); + } +} + +PR_IMPLEMENT(void) _MD_FREE_LOCK(struct _MDLock *lockp) +{ + PRIntn _is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + pthread_mutex_destroy(&lockp->mutex); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); +} + + + +PR_IMPLEMENT(PRStatus) _MD_NEW_LOCK(struct _MDLock *lockp) +{ + PRStatus rv; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + rv = pthread_mutex_init(&lockp->mutex, NULL); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return (rv == 0) ? PR_SUCCESS : PR_FAILURE; +} + + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +PR_IMPLEMENT(void) +_MD_SetPriority(_MDThread *thread, PRThreadPriority newPri) +{ + /* + * XXX - to be implemented + */ + return; +} + +PR_IMPLEMENT(PRStatus) _MD_InitThread(struct PRThread *thread) +{ + struct sigaction sigact; + + if (thread->flags & _PR_GLOBAL_SCOPE) { + thread->md.pthread = pthread_self(); +#if 0 + /* + * 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; + /* + * Must mask clock interrupts + */ + sigact.sa_mask = timer_set; + sigaction(SIGUSR1, &sigact, 0); +#endif + } + + return PR_SUCCESS; +} + +PR_IMPLEMENT(void) _MD_ExitThread(struct PRThread *thread) +{ + if (thread->flags & _PR_GLOBAL_SCOPE) { + _MD_CLEAN_THREAD(thread); + _MD_SET_CURRENT_THREAD(NULL); + } +} + +PR_IMPLEMENT(void) _MD_CleanThread(struct PRThread *thread) +{ + if (thread->flags & _PR_GLOBAL_SCOPE) { + pthread_mutex_destroy(&thread->md.pthread_mutex); + pthread_cond_destroy(&thread->md.pthread_cond); + } +} + +PR_IMPLEMENT(void) _MD_SuspendThread(struct PRThread *thread) +{ + PRInt32 rv; + + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && + _PR_IS_GCABLE_THREAD(thread)); +#if 0 + thread->md.suspending_id = getpid(); + rv = kill(thread->md.id, SIGUSR1); + PR_ASSERT(rv == 0); + /* + * now, block the current thread/cpu until woken up by the suspended + * thread from it's SIGUSR1 signal handler + */ + blockproc(getpid()); +#endif +} + +PR_IMPLEMENT(void) _MD_ResumeThread(struct PRThread *thread) +{ + PRInt32 rv; + + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && + _PR_IS_GCABLE_THREAD(thread)); +#if 0 + rv = unblockproc(thread->md.id); +#endif +} + +PR_IMPLEMENT(void) _MD_SuspendCPU(struct _PRCPU *thread) +{ + PRInt32 rv; + +#if 0 + cpu->md.suspending_id = getpid(); + rv = kill(cpu->md.id, SIGUSR1); + PR_ASSERT(rv == 0); + /* + * now, block the current thread/cpu until woken up by the suspended + * thread from it's SIGUSR1 signal handler + */ + blockproc(getpid()); +#endif +} + +PR_IMPLEMENT(void) _MD_ResumeCPU(struct _PRCPU *thread) +{ +#if 0 + unblockproc(cpu->md.id); +#endif +} + + +#define PT_NANOPERMICRO 1000UL +#define PT_BILLION 1000000000UL + +PR_IMPLEMENT(PRStatus) +_pt_wait(PRThread *thread, PRIntervalTime timeout) +{ +int rv; +struct timeval now; +struct timespec tmo; +PRUint32 ticks = PR_TicksPerSecond(); + + + if (timeout != PR_INTERVAL_NO_TIMEOUT) { + tmo.tv_sec = timeout / ticks; + tmo.tv_nsec = timeout - (tmo.tv_sec * ticks); + tmo.tv_nsec = PR_IntervalToMicroseconds(PT_NANOPERMICRO * + tmo.tv_nsec); + + /* pthreads wants this in absolute time, off we go ... */ + (void)GETTIMEOFDAY(&now); + /* that one's usecs, this one's nsecs - grrrr! */ + tmo.tv_sec += now.tv_sec; + tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec); + tmo.tv_sec += tmo.tv_nsec / PT_BILLION; + tmo.tv_nsec %= PT_BILLION; + } + + pthread_mutex_lock(&thread->md.pthread_mutex); + thread->md.wait--; + if (thread->md.wait < 0) { + if (timeout != PR_INTERVAL_NO_TIMEOUT) { + rv = pthread_cond_timedwait(&thread->md.pthread_cond, + &thread->md.pthread_mutex, &tmo); + } + else + rv = pthread_cond_wait(&thread->md.pthread_cond, + &thread->md.pthread_mutex); + if (rv != 0) { + thread->md.wait++; + } + } else + rv = 0; + pthread_mutex_unlock(&thread->md.pthread_mutex); + + return (rv == 0) ? PR_SUCCESS : PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_wait(PRThread *thread, PRIntervalTime ticks) +{ + if ( thread->flags & _PR_GLOBAL_SCOPE ) { + _MD_CHECK_FOR_EXIT(); + if (_pt_wait(thread, ticks) == PR_FAILURE) { + _MD_CHECK_FOR_EXIT(); + /* + * wait timed out + */ + _PR_THREAD_LOCK(thread); + if (thread->wait.cvar) { + /* + * The thread will remove itself from the waitQ + * of the cvar in _PR_WaitCondVar + */ + thread->wait.cvar = NULL; + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + } else { + _pt_wait(thread, PR_INTERVAL_NO_TIMEOUT); + _PR_THREAD_UNLOCK(thread); + } + } + } else { + _PR_MD_SWITCH_CONTEXT(thread); + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) +_MD_WakeupWaiter(PRThread *thread) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 pid, rv; + PRIntn is; + + PR_ASSERT(_pr_md_idle_cpus >= 0); + if (thread == NULL) { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } else if (!_PR_IS_NATIVE_THREAD(thread)) { + /* + * If the thread is on my cpu's runq there is no need to + * wakeup any cpus + */ + if (!_PR_IS_NATIVE_THREAD(me)) { + if (me->cpu != thread->cpu) { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } + } else { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } + } else { + PR_ASSERT(_PR_IS_NATIVE_THREAD(thread)); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + pthread_mutex_lock(&thread->md.pthread_mutex); + thread->md.wait++; + rv = pthread_cond_signal(&thread->md.pthread_cond); + PR_ASSERT(rv == 0); + pthread_mutex_unlock(&thread->md.pthread_mutex); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + } + return PR_SUCCESS; +} + +/* These functions should not be called for AIX */ +PR_IMPLEMENT(void) +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for AIX."); +} + +PR_IMPLEMENT(PRStatus) +_MD_CreateThread( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PRIntn is; + int rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + pthread_attr_t attr; + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + if (pthread_mutex_init(&thread->md.pthread_mutex, NULL) != 0) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + + if (pthread_cond_init(&thread->md.pthread_cond, NULL) != 0) { + pthread_mutex_destroy(&thread->md.pthread_mutex); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + thread->flags |= _PR_GLOBAL_SCOPE; + + pthread_attr_init(&attr); /* initialize attr with default attributes */ + if (pthread_attr_setstacksize(&attr, (size_t) stackSize) != 0) { + pthread_mutex_destroy(&thread->md.pthread_mutex); + pthread_cond_destroy(&thread->md.pthread_cond); + pthread_attr_destroy(&attr); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + + thread->md.wait = 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)) + _PR_FAST_INTSON(is); + return PR_SUCCESS; + } else { + pthread_mutex_destroy(&thread->md.pthread_mutex); + pthread_cond_destroy(&thread->md.pthread_cond); + pthread_attr_destroy(&attr); + _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; + } +} + +PR_IMPLEMENT(void) +_MD_InitRunningCPU(struct _PRCPU *cpu) +{ + extern int _pr_md_pipefd[2]; + + _MD_unix_init_running_cpu(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 + } +} + + +void +_MD_CleanupBeforeExit(void) +{ +#if 0 + extern PRInt32 _pr_cpus_exit; + + _pr_irix_exit_now = 1; + if (_pr_numCPU > 1) { + /* + * Set a global flag, and wakeup all cpus which will notice the flag + * and exit. + */ + _pr_cpus_exit = getpid(); + _MD_Wakeup_CPUs(); + while(_pr_numCPU > 1) { + _PR_WAIT_SEM(_pr_irix_exit_sem); + _pr_numCPU--; + } + } + /* + * cause global threads on the recycle list to exit + */ + _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; + } + } + _PR_DEADQ_UNLOCK; + while(_PR_NUM_DEADNATIVE > 1) { + _PR_WAIT_SEM(_pr_irix_exit_sem); + _PR_DEC_DEADNATIVE; + } +#endif +} diff --git a/nsprpub/pr/src/md/unix/qnx.c b/nsprpub/pr/src/md/unix/qnx.c new file mode 100644 index 00000000000..be86e5b9c2b --- /dev/null +++ b/nsprpub/pr/src/md/unix/qnx.c @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +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 Unixware */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Unixware."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRUintn priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware."); + return PR_FAILURE; +} diff --git a/nsprpub/pr/src/md/unix/reliantunix.c b/nsprpub/pr/src/md/unix/reliantunix.c new file mode 100644 index 00000000000..efe21086a76 --- /dev/null +++ b/nsprpub/pr/src/md/unix/reliantunix.c @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * SINIX (ReliantUNIX) 5.4 - copied from unixware.c by chrisk 040497 + */ +#include "primpl.h" + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) _GETCONTEXT(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ + +PRInt32 _MD_connect(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _connect(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); +} + +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _accept(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); + return(rv); +} +#endif + +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 SINIX */ +/* Why? Just copied it from UNIXWARE... flying-by-night, chrisk 040497 */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for SINIX."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRUintn priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for SINIX."); +#if defined(SNI) && !defined(__GNUC__) + /* make compiler happy */ + return (PRStatus)NULL; +#endif +} diff --git a/nsprpub/pr/src/md/unix/riscos.c b/nsprpub/pr/src/md/unix/riscos.c new file mode 100644 index 00000000000..eee94d3d2e8 --- /dev/null +++ b/nsprpub/pr/src/md/unix/riscos.c @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): Peter Naulls + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifdef _PR_PTHREADS + +void _MD_CleanupBeforeExit(void) +{ +} + +#else /* ! _PR_PTHREADS */ + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + /* + * set the pointers to the stack-pointer and frame-pointer words in the + * context structure; this is for debugging use. + */ + thread->md.sp = _MD_GET_SP_PTR(thread); + thread->md.fp = _MD_GET_FP_PTR(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 RISC OS */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for RISC OS."); +} + +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 RISC OS."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/nsprpub/pr/src/md/unix/scoos.c b/nsprpub/pr/src/md/unix/scoos.c new file mode 100644 index 00000000000..766bf91703f --- /dev/null +++ b/nsprpub/pr/src/md/unix/scoos.c @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * SCO ODT 5.0 - originally created by mikep + */ +#include "primpl.h" + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ + +PRInt32 _MD_connect(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _connect(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); +} + +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _accept(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); + return(rv); +} +#endif + +/* + * These are also implemented in pratom.c using NSPR locks. Any reason + * this might be better or worse? If you like this better, define + * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h + */ +#ifdef _PR_HAVE_ATOMIC_OPS +/* Atomic operations */ +#include +static FILE *_uw_semf; + +void +_MD_INIT_ATOMIC(void) +{ + /* Sigh. Sure wish SYSV semaphores weren't such a pain to use */ + if ((_uw_semf = tmpfile()) == NULL) + PR_ASSERT(0); + + return; +} + +void +_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)++; + unflockfile(_uw_semf); +} + +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); + (*val)--; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + flockfile(_uw_semf); + *val = newval; + unflockfile(_uw_semf); +} +#endif + +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 SCO */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for SCO."); +} + +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 SCO."); +} diff --git a/nsprpub/pr/src/md/unix/solaris.c b/nsprpub/pr/src/md/unix/solaris.c new file mode 100644 index 00000000000..2ec3bd1ebd2 --- /dev/null +++ b/nsprpub/pr/src/md/unix/solaris.c @@ -0,0 +1,889 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + + +extern PRBool suspendAllOn; +extern PRThread *suspendAllThread; + +extern void _MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri); + +PRIntervalTime _MD_Solaris_TicksPerSecond(void) +{ + /* + * Ticks have a 10-microsecond resolution. So there are + * 100000 ticks per second. + */ + return 100000UL; +} + +/* Interval timers, implemented using gethrtime() */ + +PRIntervalTime _MD_Solaris_GetInterval(void) +{ + union { + hrtime_t hrt; /* hrtime_t is a 64-bit (long long) integer */ + PRInt64 pr64; + } time; + PRInt64 resolution; + PRIntervalTime ticks; + + time.hrt = gethrtime(); /* in nanoseconds */ + /* + * Convert from nanoseconds to ticks. A tick's resolution is + * 10 microseconds, or 10000 nanoseconds. + */ + LL_I2L(resolution, 10000); + LL_DIV(time.pr64, time.pr64, resolution); + LL_L2UI(ticks, time.pr64); + return ticks; +} + +#ifdef _PR_PTHREADS +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np) +{ + *np = 0; + return NULL; +} +#endif /* _PR_PTHREADS */ + +#if !defined(i386) && !defined(IS_64) +#if defined(_PR_HAVE_ATOMIC_OPS) +/* NOTE: + * SPARC v9 (Ultras) do have an atomic test-and-set operation. But + * SPARC v8 doesn't. We should detect in the init if we are running on + * v8 or v9, and then use assembly where we can. + * + * This code uses the Solaris threads API. It can be used in both the + * pthreads and Solaris threads versions of nspr20 because "POSIX threads + * and Solaris threads are fully compatible even within the same process", + * to quote from pthread_create(3T). + */ + +#include +#include + +static mutex_t _solaris_atomic = DEFAULTMUTEX; + +PRInt32 +_MD_AtomicIncrement(PRInt32 *val) +{ + PRInt32 rv; + if (mutex_lock(&_solaris_atomic) != 0) + PR_ASSERT(0); + + rv = ++(*val); + + if (mutex_unlock(&_solaris_atomic) != 0)\ + PR_ASSERT(0); + + return rv; +} + +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; + if (mutex_lock(&_solaris_atomic) != 0) + PR_ASSERT(0); + + rv = --(*val); + + if (mutex_unlock(&_solaris_atomic) != 0)\ + PR_ASSERT(0); + + return rv; +} + +PRInt32 +_MD_AtomicSet(PRInt32 *val, PRInt32 newval) +{ + PRInt32 rv; + if (mutex_lock(&_solaris_atomic) != 0) + PR_ASSERT(0); + + rv = *val; + *val = newval; + + if (mutex_unlock(&_solaris_atomic) != 0)\ + PR_ASSERT(0); + + return rv; +} +#endif /* _PR_HAVE_ATOMIC_OPS */ +#endif /* !defined(i386) */ + +#if defined(_PR_GLOBAL_THREADS_ONLY) +#include +#include +#include +#include + +#include +#include +#include +extern int syscall(); /* not declared in sys/syscall.h */ + +static sigset_t old_mask; /* store away original gc thread sigmask */ +static PRIntn gcprio; /* store away original gc thread priority */ + +THREAD_KEY_T threadid_key; +THREAD_KEY_T cpuid_key; +THREAD_KEY_T last_thread_key; +static sigset_t set, oldset; + +static void +threadid_key_destructor(void *value) +{ + PRThread *me = (PRThread *)value; + PR_ASSERT(me != NULL); + /* the thread could be PRIMORDIAL (thus not ATTACHED) */ + if (me->flags & _PR_ATTACHED) { + /* + * The Solaris thread library sets the thread specific + * data (the current thread) to NULL before invoking + * the destructor. We need to restore it to prevent the + * _PR_MD_CURRENT_THREAD() call in _PRI_DetachThread() + * from attaching the thread again. + */ + _PR_MD_SET_CURRENT_THREAD(me); + _PRI_DetachThread(); + } +} + +void _MD_EarlyInit(void) +{ + THR_KEYCREATE(&threadid_key, threadid_key_destructor); + THR_KEYCREATE(&cpuid_key, NULL); + THR_KEYCREATE(&last_thread_key, NULL); + sigemptyset(&set); + sigaddset(&set, SIGALRM); +} + +PRStatus _MD_CreateThread(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PRInt32 flags; + + /* mask out SIGALRM for native thread creation */ + thr_sigsetmask(SIG_BLOCK, &set, &oldset); + + /* + * 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 (_PR_IS_GCABLE_THREAD(thread) || (thread->flags & _PR_BOUND_THREAD) || + (scope == PR_GLOBAL_BOUND_THREAD)) + flags |= THR_BOUND; + + if (thr_create(NULL, thread->stack->stackSize, + (void *(*)(void *)) start, (void *) thread, + flags, + &thread->md.handle)) { + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); + return PR_FAILURE; + } + + /* When the thread starts running, then the lwpid is set to the right + * value. Until then we want to mark this as 'uninit' so that + * its register state is initialized properly for GC */ + + thread->md.lwpid = -1; + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); + _MD_NEW_SEM(&thread->md.waiter_sem, 0); + + if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) { + thread->flags |= _PR_GLOBAL_SCOPE; + } + + _MD_SET_PRIORITY(&(thread->md), priority); + + /* Activate the thread */ + if (thr_continue( thread->md.handle ) ) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void _MD_cleanup_thread(PRThread *thread) +{ + thread_t hdl; + + hdl = thread->md.handle; + + /* + ** First, suspend the thread (unless it's the active one) + ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to + ** prevent both of us modifying the thread structure at the same time. + */ + if ( thread != _PR_MD_CURRENT_THREAD() ) { + thr_suspend(hdl); + } + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("(0X%x)[DestroyThread]\n", thread)); + + _MD_DESTROY_SEM(&thread->md.waiter_sem); +} + +void _MD_exit_thread(PRThread *thread) +{ + _MD_CLEAN_THREAD(thread); + _MD_SET_CURRENT_THREAD(NULL); +} + +void _MD_SET_PRIORITY(_MDThread *md_thread, + PRThreadPriority newPri) +{ + PRIntn nativePri; + + if (newPri < PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } else if (newPri > PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } + /* Solaris priorities are from 0 to 127 */ + nativePri = newPri * 127 / PR_PRIORITY_LAST; + if(thr_setprio((thread_t)md_thread->handle, nativePri)) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("_PR_SetThreadPriority: can't set thread priority\n")); + } +} + +void _MD_WAIT_CV( + struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout) +{ + struct timespec tt; + PRUint32 msec; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT((!suspendAllOn) || (suspendAllThread != me)); + + if (PR_INTERVAL_NO_TIMEOUT == timeout) { + COND_WAIT(&md_cv->cv, &md_lock->lock); + } else { + msec = PR_IntervalToMilliseconds(timeout); + + GETTIME(&tt); + tt.tv_sec += msec / PR_MSEC_PER_SEC; + tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC; + /* Check for nsec overflow - otherwise we'll get an EINVAL */ + if (tt.tv_nsec >= PR_NSEC_PER_SEC) { + tt.tv_sec++; + tt.tv_nsec -= PR_NSEC_PER_SEC; + } + COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt); + } +} + +void _MD_lock(struct _MDLock *md_lock) +{ +#ifdef DEBUG + /* This code was used for GC testing to make sure that we didn't attempt + * to grab any locks while threads are suspended. + */ + PRLock *lock; + + if ((suspendAllOn) && (suspendAllThread == _PR_MD_CURRENT_THREAD())) { + lock = ((PRLock *) ((char*) (md_lock) - offsetof(PRLock,ilock))); + PR_ASSERT(lock->owner == NULL); + return; + } +#endif /* DEBUG */ + + mutex_lock(&md_lock->lock); +} + +PRThread *_pr_attached_thread_tls() +{ + PRThread *ret; + + thr_getspecific(threadid_key, (void **)&ret); + return ret; +} + +PRThread *_pr_current_thread_tls() +{ + 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; +} + +PRStatus +_MD_wait(PRThread *thread, PRIntervalTime ticks) +{ + _MD_WAIT_SEM(&thread->md.waiter_sem); + return PR_SUCCESS; +} + +PRStatus +_MD_WakeupWaiter(PRThread *thread) +{ + if (thread == NULL) { + return PR_SUCCESS; + } + _MD_POST_SEM(&thread->md.waiter_sem); + return PR_SUCCESS; +} + +_PRCPU *_pr_current_cpu_tls() +{ + _PRCPU *ret; + + thr_getspecific(cpuid_key, (void **)&ret); + return ret; +} + +PRThread *_pr_last_thread_tls() +{ + PRThread *ret; + + thr_getspecific(last_thread_key, (void **)&ret); + return ret; +} + +_MDLock _pr_ioq_lock; + +void +_MD_InitIO(void) +{ + _MD_NEW_LOCK(&_pr_ioq_lock); +} + +PRStatus _MD_InitializeThread(PRThread *thread) +{ + if (!_PR_IS_NATIVE_THREAD(thread)) + return PR_SUCCESS; + /* sol_curthread is an asm routine which grabs GR7; GR7 stores an internal + * thread structure ptr used by solaris. We'll use this ptr later + * with suspend/resume to find which threads are running on LWPs. + */ + thread->md.threadID = sol_curthread(); + /* prime the sp; substract 4 so we don't hit the assert that + * curr sp > base_stack + */ + thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long); + thread->md.lwpid = _lwp_self(); + thread->md.handle = THR_SELF(); + + /* all threads on Solaris are global threads from NSPR's perspective + * since all of them are mapped to Solaris threads. + */ + thread->flags |= _PR_GLOBAL_SCOPE; + + /* For primordial/attached thread, we don't create an underlying native thread. + * So, _MD_CREATE_THREAD() does not get called. We need to do initialization + * like allocating thread's synchronization variables and set the underlying + * native thread's priority. + */ + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + _MD_NEW_SEM(&thread->md.waiter_sem, 0); + _MD_SET_PRIORITY(&(thread->md), thread->priority); + } + return PR_SUCCESS; +} + +/* Sleep for n milliseconds, n < 1000 */ +void solaris_msec_sleep(int n) +{ + struct timespec ts; + + ts.tv_sec = 0; + ts.tv_nsec = 1000000*n; + if (syscall(SYS_nanosleep, &ts, 0, 0) < 0) { + PR_ASSERT(0); + } +} + +#define VALID_SP(sp, bottom, top) \ + (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top))) + +void solaris_record_regs(PRThread *t, prstatus_t *lwpstatus) +{ +#ifdef sparc + long *regs = (long *)&t->md.context.uc_mcontext.gregs[0]; + + PR_ASSERT(_PR_IS_GCABLE_THREAD(t)); + PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[REG_G7]); + + t->md.sp = lwpstatus->pr_reg[REG_SP]; + PR_ASSERT(VALID_SP(t->md.sp, t->stack->stackBottom, t->stack->stackTop)); + + regs[0] = lwpstatus->pr_reg[R_G1]; + regs[1] = lwpstatus->pr_reg[R_G2]; + regs[2] = lwpstatus->pr_reg[R_G3]; + regs[3] = lwpstatus->pr_reg[R_G4]; + regs[4] = lwpstatus->pr_reg[R_O0]; + regs[5] = lwpstatus->pr_reg[R_O1]; + regs[6] = lwpstatus->pr_reg[R_O2]; + regs[7] = lwpstatus->pr_reg[R_O3]; + regs[8] = lwpstatus->pr_reg[R_O4]; + regs[9] = lwpstatus->pr_reg[R_O5]; + regs[10] = lwpstatus->pr_reg[R_O6]; + regs[11] = lwpstatus->pr_reg[R_O7]; +#elif defined(i386) + /* + * To be implemented and tested + */ + PR_ASSERT(0); + PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[GS]); + t->md.sp = lwpstatus->pr_reg[UESP]; +#endif +} + +void solaris_preempt_off() +{ + sigset_t set; + + (void)sigfillset(&set); + syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask); +} + +void solaris_preempt_on() +{ + syscall(SYS_sigprocmask, SIG_SETMASK, &old_mask, NULL); +} + +int solaris_open_main_proc_fd() +{ + char buf[30]; + int fd; + + /* Not locked, so must be created while threads coming up */ + PR_snprintf(buf, sizeof(buf), "/proc/%ld", getpid()); + if ( (fd = syscall(SYS_open, buf, O_RDONLY)) < 0) { + return -1; + } + return fd; +} + +/* Return a file descriptor for the /proc entry corresponding to the + * given lwp. + */ +int solaris_open_lwp(lwpid_t id, int lwp_main_proc_fd) +{ + int result; + + if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCOPENLWP, &id)) <0) + return -1; /* exited??? */ + + return result; +} +void _MD_Begin_SuspendAll() +{ + solaris_preempt_off(); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n")); + /* run at highest prio so I cannot be preempted */ + thr_getprio(thr_self(), &gcprio); + thr_setprio(thr_self(), 0x7fffffff); + suspendAllOn = PR_TRUE; + suspendAllThread = _PR_MD_CURRENT_THREAD(); +} + +void _MD_End_SuspendAll() +{ +} + +void _MD_End_ResumeAll() +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n")); + thr_setprio(thr_self(), gcprio); + solaris_preempt_on(); + suspendAllThread = NULL; + suspendAllOn = PR_FALSE; +} + +void _MD_Suspend(PRThread *thr) +{ + int lwp_fd, result; + prstatus_t lwpstatus; + int lwp_main_proc_fd = 0; + + if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){ + /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend + * during that time we can't call any thread lib or libc calls. Hence + * make sure that no suspension is requested for Non gcable thread + * during suspendAllOn */ + PR_ASSERT(!suspendAllOn); + thr_suspend(thr->md.handle); + return; + } + + /* XXX Primordial thread can't be bound to an lwp, hence there is no + * way we can assume that we can get the lwp status for primordial + * thread reliably. Hence we skip this for primordial thread, hoping + * that the SP is saved during lock and cond. wait. + * XXX - Again this is concern only for java interpreter, not for the + * server, 'cause primordial thread in the server does not do java work + */ + if (thr->flags & _PR_PRIMORDIAL) + return; + + /* XXX Important Note: If the start function of a thread is not called, + * lwpid is -1. Then, skip this thread. This thread will get caught + * in PR_NativeRunThread before calling the start function, because + * we hold the pr_activeLock during suspend/resume */ + + /* if the thread is not started yet then don't do anything */ + if (!suspendAllOn || thr->md.lwpid == -1) + return; + + if (_lwp_suspend(thr->md.lwpid) < 0) { + PR_ASSERT(0); + return; + } + + if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) { + PR_ASSERT(0); + return; /* XXXMB ARGH, we're hosed! */ + } + + if ( (lwp_fd = solaris_open_lwp(thr->md.lwpid, lwp_main_proc_fd)) < 0) { + PR_ASSERT(0); + close(lwp_main_proc_fd); + return; + } + if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) { + /* Hopefully the thread just died... */ + close(lwp_fd); + close(lwp_main_proc_fd); + return; + } + while ( !(lwpstatus.pr_flags & PR_STOPPED) ) { + if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) { + PR_ASSERT(0); /* ARGH SOMETHING WRONG! */ + break; + } + solaris_msec_sleep(1); + } + solaris_record_regs(thr, &lwpstatus); + close(lwp_fd); + close(lwp_main_proc_fd); +} + +#ifdef OLD_CODE + +void _MD_SuspendAll() +{ + /* On solaris there are threads, and there are LWPs. + * Calling _PR_DoSingleThread would freeze all of the threads bound to LWPs + * but not necessarily stop all LWPs (for example if someone did + * an attachthread of a thread which was not bound to an LWP). + * So now go through all the LWPs for this process and freeze them. + * + * Note that if any thread which is capable of having the GC run on it must + * had better be a LWP with a single bound thread on it. Otherwise, this + * might not stop that thread from being run. + */ + PRThread *current = _PR_MD_CURRENT_THREAD(); + prstatus_t status, lwpstatus; + int result, index, lwp_fd; + lwpid_t me = _lwp_self(); + int err; + int lwp_main_proc_fd; + + solaris_preempt_off(); + + /* run at highest prio so I cannot be preempted */ + thr_getprio(thr_self(), &gcprio); + thr_setprio(thr_self(), 0x7fffffff); + + current->md.sp = (uint_t)&me; /* set my own stack pointer */ + + if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) { + PR_ASSERT(0); + solaris_preempt_on(); + return; /* XXXMB ARGH, we're hosed! */ + } + + if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCSTATUS, &status)) < 0) { + err = errno; + PR_ASSERT(0); + goto failure; /* XXXMB ARGH, we're hosed! */ + } + + num_lwps = status.pr_nlwp; + + if ( (all_lwps = (lwpid_t *)PR_MALLOC((num_lwps+1) * sizeof(lwpid_t)))==NULL) { + PR_ASSERT(0); + goto failure; /* XXXMB ARGH, we're hosed! */ + } + + if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCLWPIDS, all_lwps)) < 0) { + PR_ASSERT(0); + PR_DELETE(all_lwps); + goto failure; /* XXXMB ARGH, we're hosed! */ + } + + for (index=0; index< num_lwps; index++) { + if (all_lwps[index] != me) { + if (_lwp_suspend(all_lwps[index]) < 0) { + /* could happen if lwp exited */ + all_lwps[index] = me; /* dummy it up */ + } + } + } + + /* Turns out that lwp_suspend is not a blocking call. + * Go through the list and make sure they are all stopped. + */ + for (index=0; index< num_lwps; index++) { + if (all_lwps[index] != me) { + if ( (lwp_fd = solaris_open_lwp(all_lwps[index], lwp_main_proc_fd)) < 0) { + PR_ASSERT(0); + PR_DELETE(all_lwps); + all_lwps = NULL; + goto failure; /* XXXMB ARGH, we're hosed! */ + } + + if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) { + /* Hopefully the thread just died... */ + close(lwp_fd); + continue; + } + while ( !(lwpstatus.pr_flags & PR_STOPPED) ) { + if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) { + PR_ASSERT(0); /* ARGH SOMETHING WRONG! */ + break; + } + solaris_msec_sleep(1); + } + solaris_record_regs(&lwpstatus); + close(lwp_fd); + } + } + + close(lwp_main_proc_fd); + + return; +failure: + solaris_preempt_on(); + thr_setprio(thr_self(), gcprio); + close(lwp_main_proc_fd); + return; +} + +void _MD_ResumeAll() +{ + int i; + lwpid_t me = _lwp_self(); + + for (i=0; i < num_lwps; i++) { + if (all_lwps[i] == me) + continue; + if ( _lwp_continue(all_lwps[i]) < 0) { + PR_ASSERT(0); /* ARGH, we are hosed! */ + } + } + + /* restore priority and sigmask */ + thr_setprio(thr_self(), gcprio); + solaris_preempt_on(); + PR_DELETE(all_lwps); + all_lwps = NULL; +} +#endif /* OLD_CODE */ + +#ifdef USE_SETJMP +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} +#else +PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np) +{ + if (isCurrent) { + (void) getcontext(CONTEXT(t)); + } + *np = NGREG; + return (PRWord*) &t->md.context.uc_mcontext.gregs[0]; +} +#endif /* USE_SETJMP */ + +#else /* _PR_GLOBAL_THREADS_ONLY */ + +#if defined(_PR_LOCAL_THREADS_ONLY) + +void _MD_EarlyInit(void) +{ +} + +void _MD_SolarisInit() +{ + _PR_UnixInit(); +} + +void +_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority 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) +{ + PR_ASSERT((thread == NULL) || (!(thread->flags & _PR_GLOBAL_SCOPE))); + return PR_SUCCESS; +} + +/* These functions should not be called for Solaris */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Solaris"); +} + +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 Solaris"); + return(PR_FAILURE); +} + +#ifdef USE_SETJMP +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} +#else +PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np) +{ + if (isCurrent) { + (void) getcontext(CONTEXT(t)); + } + *np = NGREG; + return (PRWord*) &t->md.context.uc_mcontext.gregs[0]; +} +#endif /* USE_SETJMP */ + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +#endif /* _PR_GLOBAL_THREADS_ONLY */ + +#ifndef _PR_PTHREADS +#if defined(i386) && defined(SOLARIS2_4) +/* + * Because clock_gettime() on Solaris/x86 2.4 always generates a + * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(), + * which is implemented using gettimeofday(). + */ + +int +_pr_solx86_clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + struct timeval tv; + + if (clock_id != CLOCK_REALTIME) { + errno = EINVAL; + return -1; + } + + gettimeofday(&tv, NULL); + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000; + return 0; +} +#endif /* i386 && SOLARIS2_4 */ +#endif /* _PR_PTHREADS */ diff --git a/nsprpub/pr/src/md/unix/sony.c b/nsprpub/pr/src/md/unix/sony.c new file mode 100644 index 00000000000..dacb4fd570a --- /dev/null +++ b/nsprpub/pr/src/md/unix/sony.c @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(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 Sony */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for SONY."); +} + +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 SONY."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/nsprpub/pr/src/md/unix/sunos4.c b/nsprpub/pr/src/md/unix/sunos4.c new file mode 100644 index 00000000000..d3b40c15cc4 --- /dev/null +++ b/nsprpub/pr/src/md/unix/sunos4.c @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include "primpl.h" + +void _MD_EarlyInit(void) +{ +} + +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 SunOS 4.1.3."); + return PR_FAILURE; +} + +void _MD_SET_PRIORITY(_MDThread *md_thread, PRUintn newPri) +{ + PR_NOT_REACHED("_MD_SET_PRIORITY should not be called for user-level threads."); +} + +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; +} + +PRStatus _MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for SunOS 4.1.3."); +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} diff --git a/nsprpub/pr/src/md/unix/unix.c b/nsprpub/pr/src/md/unix/unix.c new file mode 100644 index 00000000000..198262eee7c --- /dev/null +++ b/nsprpub/pr/src/md/unix/unix.c @@ -0,0 +1,3734 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _PR_POLL_AVAILABLE +#include +#endif + +/* To get FIONREAD */ +#if defined(NCR) || defined(UNIXWARE) || defined(NEC) || defined(SNI) \ + || defined(SONY) +#include +#endif + +#if defined(NTO) +#include +#endif + +/* + * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or + * PRInt32* pointer to a _PRSockLen_t* pointer. + */ +#if defined(HAVE_SOCKLEN_T) \ + || (defined(__GLIBC__) && __GLIBC__ >= 2) +#define _PRSockLen_t socklen_t +#elif defined(IRIX) || defined(HPUX) || defined(OSF1) || defined(SOLARIS) \ + || defined(AIX4_1) || defined(LINUX) || defined(SONY) \ + || defined(BSDI) || defined(SCO) || defined(NEC) || defined(SNI) \ + || defined(SUNOS4) || defined(NCR) || defined(DARWIN) \ + || defined(NEXTSTEP) || defined(QNX) +#define _PRSockLen_t int +#elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) \ + || defined(NETBSD) || defined(OPENBSD) || defined(UNIXWARE) \ + || defined(DGUX) || defined(VMS) || defined(NTO) || defined(RISCOS) +#define _PRSockLen_t size_t +#else +#error "Cannot determine architecture" +#endif + +/* +** Global lock variable used to bracket calls into rusty libraries that +** aren't thread safe (like libc, libX, etc). +*/ +static PRLock *_pr_rename_lock = NULL; +static PRMonitor *_pr_Xfe_mon = NULL; + +static PRInt64 minus_one; + +sigset_t timer_set; + +#if !defined(_PR_PTHREADS) + +static sigset_t empty_set; + +#ifdef SOLARIS +#include +#include +#endif + +#ifndef PIPE_BUF +#define PIPE_BUF 512 +#endif + +/* + * _nspr_noclock - if set clock interrupts are disabled + */ +int _nspr_noclock = 1; + +#ifdef IRIX +extern PRInt32 _nspr_terminate_on_error; +#endif + +/* + * There is an assertion in this code that NSPR's definition of PRIOVec + * is bit compatible with UNIX' definition of a struct iovec. This is + * applicable to the 'writev()' operations where the types are casually + * cast to avoid warnings. + */ + +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 } +}; + +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; +} + +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; +} + +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; +} + +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. + */ + _MD_ERRNO() = 0; + 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; +#endif + +#ifdef UNIXWARE + sigfillset(&set); + sigprocmask(SIG_SETMASK, &set, &oset); +#endif + rv = unlink(name); +#ifdef UNIXWARE + sigprocmask(SIG_SETMASK, &oset, NULL); +#endif + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_UNLINK_ERROR(err); + } + return(rv); +} + +PRInt32 _MD_rename(const char *from, const char *to) +{ + PRInt32 rv = -1, err; + + /* + ** This is trying to enforce the semantics of WINDOZE' rename + ** operation. That means one is not allowed to rename over top + ** of an existing file. Holding a lock across these two function + ** and the open function is known to be a bad idea, but .... + */ + if (NULL != _pr_rename_lock) + PR_Lock(_pr_rename_lock); + if (0 == access(to, F_OK)) + PR_SetError(PR_FILE_EXISTS_ERROR, 0); + else + { + 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; +} + +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); + + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_ACCESS_ERROR(err); + } + +done: + return(rv); +} + +PRInt32 _MD_mkdir(const char *name, PRIntn mode) +{ +int rv, err; + + /* + ** This lock is used to enforce rename semantics as described + ** in PR_Rename. Look there for more fun details. + */ + 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); + } + if (NULL !=_pr_rename_lock) + PR_Unlock(_pr_rename_lock); + 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; +} + +PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount) +{ +PRThread *me = _PR_MD_CURRENT_THREAD(); +PRInt32 rv, err; +#ifndef _PR_USE_POLL +fd_set rd; +#else +struct pollfd pfd; +#endif /* _PR_USE_POLL */ +PRInt32 osfd = fd->secret->md.osfd; + +#ifndef _PR_USE_POLL + FD_ZERO(&rd); + FD_SET(osfd, &rd); +#else + 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)) { + 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 */ + } +#else /* _PR_USE_POLL */ + 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); + } + } +done: + return(rv); +} + +PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ +PRThread *me = _PR_MD_CURRENT_THREAD(); +PRInt32 rv, err; +#ifndef _PR_USE_POLL +fd_set wd; +#else +struct pollfd pfd; +#endif /* _PR_USE_POLL */ +PRInt32 osfd = fd->secret->md.osfd; + +#ifndef _PR_USE_POLL + FD_ZERO(&wd); + FD_SET(osfd, &wd); +#else + 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)) { + 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 */ + } +#else /* _PR_USE_POLL */ + 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); + } + } +done: + return(rv); +} + +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); +} + +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); +} + +PRInt32 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) +{ + PRInt32 osfd, err; + + osfd = socket(domain, type, proto); + + if (osfd == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKET_ERROR(err); + return(osfd); + } + + return(osfd); +} + +PRInt32 _MD_socketavailable(PRFileDesc *fd) +{ + PRInt32 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) +{ + PRInt64 result; + LL_I2L(result, _MD_socketavailable(fd)); + return result; +} /* _MD_socketavailable64 */ + +#define READ_FD 1 +#define WRITE_FD 2 + +/* + * socket_io_wait -- + * + * wait for socket i/o, periodically checking for interrupt + * + * The first implementation uses select(), for platforms without + * poll(). The second (preferred) implementation uses poll(). + */ + +#ifndef _PR_USE_POLL + +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 epoch, now, elapsed, remaining; + PRBool wait_for_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. + */ + wait_for_remaining = PR_TRUE; + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + wait_for_remaining = PR_FALSE; + 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) { + if (wait_for_remaining) { + now += remaining; + } else { + 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 */ + +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; + PRBool wait_for_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 POLLERR is set, don't process it; retry the operation + */ + if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { + rv = -1; + _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. + */ + wait_for_remaining = PR_TRUE; + msecs = PR_IntervalToMilliseconds(remaining); + if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { + wait_for_remaining = PR_FALSE; + 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; + } + /* + * If POLLERR is set, don't process it; retry the operation + */ + 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) { + if (wait_for_remaining) { + now += remaining; + } else { + 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 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 + * from socketpairs. As long as we don't use flags on socketpairs, this + * is a decent fix. - mikep + */ +#if defined(UNIXWARE) || defined(SOLARIS) || defined(NCR) + while ((rv = read(osfd,buf,amount)) == -1) { +#else + 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 ((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_RECV_ERROR(err); + } +done: + 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 ((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) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRInt32 flags, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#if defined(SOLARIS) + PRInt32 tmp_amount = amount; +#endif + + /* + * 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,tmp_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 { +#if defined(SOLARIS) + /* + * The write system call has been reported to return the ERANGE + * error on occasion. Try to write in smaller chunks to workaround + * this bug. + */ + if (err == ERANGE) { + if (tmp_amount > 1) { + tmp_amount = tmp_amount/2; /* half the bytes */ + continue; + } + } +#endif + 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 (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) { + rv = -1; + goto done; + } + } + } + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } +done: + 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(); +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; + + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) &addrCopy, addrlen)) == -1) { +#else + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -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; + } + } + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } +done: + return(rv); +} + +PRInt32 _MD_writev( + PRFileDesc *fd, const 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; indexsecret->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 (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) { + rv = -1; + goto done; + } + } + } + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } +done: + return(rv); +} + +PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, + 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) || (err == ECONNABORTED)) { + 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_ACCEPT_ERROR(err); + } +done: +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv != -1) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +extern int _connect (int s, const struct sockaddr *name, int namelen); +PRInt32 _MD_connect( + PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 rv, err; + 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); +#endif +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; +#endif + + /* + * We initiate the connection setup by making a nonblocking connect() + * call. If the connect() call fails, there are two cases we handle + * specially: + * 1. The connect() call was interrupted by a signal. In this case + * we simply retry connect(). + * 2. The NSPR socket is nonblocking and connect() fails with + * EINPROGRESS. We first wait until the socket becomes writable. + * Then we try to find out whether the connection setup succeeded + * or failed. + */ + +retry: +#ifdef IRIX + if ((rv = _MD_irix_connect(osfd, addr, addrlen, timeout)) == -1) { +#else +#ifdef _PR_HAVE_SOCKADDR_LEN + if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) { +#else + if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { +#endif +#endif + err = _MD_ERRNO(); + + if (err == EINTR) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + goto retry; + } + + if (!fd->secret->nonblocking && (err == EINPROGRESS)) { + if (!_PR_IS_NATIVE_THREAD(me)) { + + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) + return -1; + } else { + /* + * socket_io_wait() may return -1 or 1. + */ + + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv == -1) { + return -1; + } + } + + PR_ASSERT(rv == 1); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + err = _MD_unix_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; + } + return 0; + } + + _PR_MD_MAP_CONNECT_ERROR(err); + } + + return rv; +} /* _MD_connect */ + +PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv, err; +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; + rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen); +#else + rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); +#endif + 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); +} + +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); +} + +PRInt32 _MD_socketpair(int af, int type, int flags, + 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; +} + +PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getsockname(fd->secret->md.osfd, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv == 0) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETSOCKNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getpeername(fd->secret->md.osfd, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv == 0) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETPEERNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, + 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; +} + +PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, + 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; +} + +PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable) +{ + int rv; + + rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC); + if (-1 == rv) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported) +{ + if (imported) { + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + /* By default, a Unix fd is not closed on exec. */ +#ifdef DEBUG + { + int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + PR_ASSERT(0 == flags); + } +#endif + fd->secret->inheritable = _PR_TRI_TRUE; + } +} + +/************************************************************************/ +#if !defined(_PR_USE_POLL) + +/* +** 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_UNIX_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); + 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)); + } + } + + _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); + + if (pq->thr->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; + * a Resume operation on the thread + * will move it to the runQ + */ + pq->thr->state = _PR_SUSPENDED; + _PR_MISCQ_LOCK(pq->thr->cpu); + _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); + _PR_MISCQ_UNLOCK(pq->thr->cpu); + } else { + 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) */ + +/************************************************************************/ + +/* +** Called by the scheduler when there is nothing to do. This means that +** all threads are blocked on some monitor somewhere. +** +** Note: this code doesn't release the scheduler lock. +*/ +/* +** Pause the current CPU. longjmp to the cpu's pause stack +** +** This must be called with the scheduler locked +*/ +void _MD_PauseCPU(PRIntervalTime ticks) +{ + 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() */ +#else + 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; +#ifdef IRIX +extern sigset_t ints_off; +#endif + + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + + _PR_MD_IOQ_LOCK(); + +#ifdef _PR_USE_POLL + /* 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); + + /* + * 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++; +#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(_PR_IOQ_POLLFDS(me->cpu)); + 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; + } 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 = 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; + + 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); + + rp = &r; + wp = &w; + ep = &e; + + 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; + + 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; + } + +#ifdef _PR_USE_POLL + 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; + } +#endif /* _PR_USE_POLL */ + + _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)) +#else + if (!_nspr_noclock) +#endif /* IRIX */ +#ifdef IRIX + sigprocmask(SIG_BLOCK, &ints_off, &oldset); +#else + 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); +#else + nfd = _MD_POLL(pollfds, npollfds, timeout); +#endif /* !_PR_USE_POLL */ + +#ifndef _PR_NO_CLOCK_TIMER +#ifdef IRIX + if ((!_nspr_noclock) || (_nspr_terminate_on_error)) +#else + if (!_nspr_noclock) +#endif /* IRIX */ + sigprocmask(SIG_SETMASK, &oldset, 0); +#endif /* !_PR_NO_CLOCK_TIMER */ + + _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()) { + /* + * 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 + /* + * 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); + } + } + pollfdPtr++; + } +#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; + + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; + + 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); + + if (pq->thr->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; + * a Resume operation on the thread + * will move it to the runQ + */ + pq->thr->state = _PR_SUSPENDED; + _PR_MISCQ_LOCK(pq->thr->cpu); + _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); + _PR_MISCQ_UNLOCK(pq->thr->cpu); + } else { + 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_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; + + /* + * 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; + _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); + + if (pq->thr->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; + * a Resume operation on the thread + * will move it to the runQ + */ + pq->thr->state = _PR_SUSPENDED; + _PR_MISCQ_LOCK(pq->thr->cpu); + _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); + _PR_MISCQ_UNLOCK(pq->thr->cpu); + } else { + 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); + } + } + 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]; + } +#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(); +} + +void _MD_Wakeup_CPUs() +{ + PRInt32 rv, data; + + 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); + } +} + + +void _MD_InitCPUS() +{ + 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]; +#ifndef _PR_USE_POLL + 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); +} + +/* +** Unix SIGALRM (clock) signal handler +*/ +static void ClockInterruptHandler() +{ + 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; + } +#endif + + 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; + + /* + ** 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))) { +#ifdef _PR_NO_PREEMPT + 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")); +#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); +} + +/* + * On HP-UX 9, we have to use the sigvector() interface to restart + * interrupted system calls, because sigaction() does not have the + * SA_RESTART flag. + */ + +#ifdef HPUX9 +static void HPUX9_ClockInterruptHandler( + int sig, + int code, + struct sigcontext *scp) +{ + ClockInterruptHandler(); + scp->sc_syscall_action = SIG_RESTART; +} +#endif /* HPUX9 */ + +/* # of milliseconds per clock tick that we will use */ +#define MSEC_PER_TICK 50 + + +void _MD_StartInterrupts() +{ + char *eval; + + 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) { + _MD_EnableClockInterrupts(); + } +#endif +} + +void _MD_StopInterrupts() +{ + sigprocmask(SIG_BLOCK, &timer_set, 0); +} + +void _MD_EnableClockInterrupts() +{ + struct itimerval itval; + extern PRUintn _pr_numCPU; +#ifdef HPUX9 + struct sigvec vec; + + vec.sv_handler = (void (*)()) HPUX9_ClockInterruptHandler; + vec.sv_mask = 0; + vec.sv_flags = 0; + sigvector(SIGALRM, &vec, 0); +#else + struct sigaction vtact; + + vtact.sa_handler = (void (*)()) ClockInterruptHandler; + sigemptyset(&vtact.sa_mask); + vtact.sa_flags = SA_RESTART; + sigaction(SIGALRM, &vtact, 0); +#endif /* HPUX9 */ + + 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; + + 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); +} + +void _MD_UnblockClockInterrupts() +{ + sigprocmask(SIG_UNBLOCK, &timer_set, 0); +} + +void _MD_MakeNonblock(PRFileDesc *fd) +{ + 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); + + /* + * 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); +#else + fcntl(osfd, F_SETFL, flags | O_NONBLOCK); +#endif + } + +PRInt32 _MD_open(const char *name, PRIntn flags, PRIntn mode) +{ + 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_EXCL) + osflags |= O_EXCL; + 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; +#elif defined(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) + { + osflags |= O_CREAT; + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + } + + rv = _md_iovector._open64(name, osflags, mode); + + 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; +} + +PRIntervalTime intr_timeout_ticks; + +#if defined(SOLARIS) || defined(IRIX) +static void sigsegvhandler() { + fprintf(stderr,"Received SIGSEGV\n"); + fflush(stderr); + pause(); +} + +static void sigaborthandler() { + fprintf(stderr,"Received SIGABRT\n"); + fflush(stderr); + pause(); +} + +static void sigbushandler() { + fprintf(stderr,"Received SIGBUS\n"); + fflush(stderr); + pause(); +} +#endif /* SOLARIS, IRIX */ + +#endif /* !defined(_PR_PTHREADS) */ + +void _MD_query_fd_inheritable(PRFileDesc *fd) +{ + int flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + PR_ASSERT(-1 != flags); + fd->secret->inheritable = (flags & FD_CLOEXEC) ? + _PR_TRI_FALSE : _PR_TRI_TRUE; +} + +PROffset32 _MD_lseek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) +{ + PROffset32 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); +} + +PROffset64 _MD_lseek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) +{ + PRInt32 where; + PROffset64 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) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtim.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtim.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctim.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctim.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_mtim.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtim.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctim.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctim.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} +#elif defined(_PR_STAT_HAS_ST_ATIM_UNION) +/* +** The st_atim, st_mtim, and st_ctim fields in struct stat are +** unions with a st__tim union member of type timestruc_t. +*/ +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_mtim.st__tim.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctim.st__tim.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_mtim.st__tim.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} +#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) +{ + 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 */ + +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 = { open }; + +/* +** 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 PROffset64 _MD_Unix_lseek64(PRIntn osfd, PROffset64 offset, PRIntn whence) +{ + PRUint64 maxoff; + PROffset64 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(OSF1) && defined(__GNUC__) + +/* + * On OSF1 V5.0A, defines stat and fstat as + * macros when compiled under gcc, so it is rather tricky to + * take the addresses of the real functions the macros expend + * to. A simple solution is to define forwarder functions + * and take the addresses of the forwarder functions instead. + */ + +static int stat_forwarder(const char *path, struct stat *buffer) +{ + return stat(path, buffer); +} + +static int fstat_forwarder(int filedes, struct stat *buffer) +{ + return fstat(filedes, buffer); +} + +#endif + +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._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._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._lseek64 = _MD_Unix_lseek64; +#elif defined(_PR_HAVE_OFF64_T) +#if defined(IRIX5_3) + _md_iovector._open64 = open; +#else + _md_iovector._open64 = open64; +#endif + _md_iovector._mmap64 = mmap64; + _md_iovector._fstat64 = fstat64; + _md_iovector._stat64 = stat64; + _md_iovector._lseek64 = lseek64; +#elif defined(_PR_HAVE_LARGE_OFF_T) + _md_iovector._open64 = open; + _md_iovector._mmap64 = mmap; +#if defined(OSF1) && defined(__GNUC__) + _md_iovector._fstat64 = fstat_forwarder; + _md_iovector._stat64 = stat_forwarder; +#else + _md_iovector._fstat64 = fstat; + _md_iovector._stat64 = stat; +#endif + _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); + +#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); + } + + if (getenv("NSPR_SIGABRT_HANDLE")) { + 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); + } + +#endif +#endif /* !defined(_PR_PTHREADS) */ + + /* + * Under HP-UX DCE threads, sigaction() installs a per-thread + * handler, so we use sigvector() to install a process-wide + * handler. + */ +#if defined(HPUX) && defined(_PR_DCETHREADS) + { + struct sigvec vec; + + vec.sv_handler = SIG_IGN; + vec.sv_mask = 0; + vec.sv_flags = 0; + rv = sigvector(SIGPIPE, &vec, NULL); + 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); +#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_InitIOV(); /* one last hack */ +} + +#if !defined(_PR_PTHREADS) + +/* + * Variables used by the GC code, initialized in _MD_InitSegs(). + */ +static PRInt32 _pr_zero_fd = -1; +static PRLock *_pr_md_lock = NULL; + +/* + * _MD_InitSegs -- + * + * This is Unix's version of _PR_MD_INIT_SEGS(), which is + * called by _PR_InitSegs(), which in turn is called by + * PR_Init(). + */ +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; + } +#endif + _pr_zero_fd = open("/dev/zero",O_RDWR , 0); + /* Prevent the fd from being inherited by child processes */ + fcntl(_pr_zero_fd, F_SETFD, FD_CLOEXEC); + _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; + + PR_ASSERT(seg != 0); + PR_ASSERT(size != 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; + } + 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. + */ +#if defined(LINUX) && defined(__alpha) + 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->flags = _PR_SEG_VM; + +exit: + 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); +} + +#endif /* _PR_PTHREADS */ + +/* + *----------------------------------------------------------------------- + * + * PR_Now -- + * + * Returns the current time in microseconds since the epoch. + * The epoch is midnight January 1, 1970 GMT. + * The implementation is machine dependent. This is the Unix + * implementation. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRTime) +PR_Now(void) +{ + 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; +} + +PRIntervalTime _PR_UNIX_GetInterval() +{ + 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; +} /* _PR_SUNOS_GetInterval */ + +PRIntervalTime _PR_UNIX_TicksPerSecond() +{ + return 1000; /* this needs some work :) */ +} + +#if !defined(_PR_PTHREADS) +/* + * Wait for I/O on multiple descriptors. + * + * 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) +{ + PRPollQueue pq; + PRIntn is; + PRInt32 rv; + _PRCPU *io_cpu; + _PRUnixPollDesc *unixpd, *eunixpd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + pq.pds = unixpds; + pq.npds = pdcnt; + + _PR_INTSOFF(is); + _PR_MD_IOQ_LOCK(); + _PR_THREAD_LOCK(me); + + pq.thr = me; + io_cpu = me->cpu; + pq.on_ioq = PR_TRUE; + pq.timeout = timeout; + _PR_ADD_TO_IOQ(pq, me->cpu); + +#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_TIMEOUT(me->cpu) > timeout) { + _PR_IOQ_TIMEOUT(me->cpu) = timeout; + } + + _PR_IOQ_OSFD_CNT(me->cpu) += pdcnt; + + _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); + + /* + ** 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_REMOVE_LINK(&pq.links); +#ifndef _PR_USE_POLL + 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(); + } + /* 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 + * + * NOTE: The thread lock should held when this function is called. + * On return, the thread lock is released. + */ +void _PR_Unblock_IO_Wait(PRThread *thr) +{ + int pri = thr->priority; + _PRCPU *cpu = thr->cpu; + + /* + * GLOBAL threads wakeup periodically to check for interrupt + */ + if (_PR_IS_NATIVE_THREAD(thr)) { + _PR_THREAD_UNLOCK(thr); + return; + } + + PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)); + _PR_SLEEPQ_LOCK(cpu); + _PR_DEL_SLEEPQ(thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(cpu); + + PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD)); + thr->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(thr); + _PR_MD_WAKEUP_WAITER(thr); +} +#endif /* !defined(_PR_PTHREADS) */ + +/* + * When a nonblocking connect has completed, determine whether it + * succeeded or failed, and if it failed, what the error code is. + * + * The function returns the error code. An error code of 0 means + * that the nonblocking connect succeeded. + */ + +int _MD_unix_get_nonblocking_connect_error(int osfd) +{ +#if defined(NTO) + /* Neutrino does not support the SO_ERROR socket option */ + PRInt32 rv; + PRNetAddr addr; + _PRSockLen_t addrlen = sizeof(addr); + + /* Test to see if we are using the Tiny TCP/IP Stack or the Full one. */ + struct statvfs superblock; + rv = fstatvfs(osfd, &superblock); + if (rv == 0) { + if (strcmp(superblock.f_basetype, "ttcpip") == 0) { + /* Using the Tiny Stack! */ + rv = getpeername(osfd, (struct sockaddr *) &addr, + (_PRSockLen_t *) &addrlen); + if (rv == -1) { + int errno_copy = errno; /* make a copy so I don't + * accidentally reset */ + + if (errno_copy == ENOTCONN) { + struct stat StatInfo; + rv = fstat(osfd, &StatInfo); + if (rv == 0) { + time_t current_time = time(NULL); + + /* + * this is a real hack, can't explain why it + * works it just does + */ + if (abs(current_time - StatInfo.st_atime) < 5) { + return ECONNREFUSED; + } else { + return ETIMEDOUT; + } + } else { + return ECONNREFUSED; + } + } else { + return errno_copy; + } + } else { + /* No Error */ + return 0; + } + } else { + /* Have the FULL Stack which supports SO_ERROR */ + /* Hasn't been written yet, never been tested! */ + /* Jerry.Kirk@Nexwarecorp.com */ + + int err; + _PRSockLen_t optlen = sizeof(err); + + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, + (char *) &err, &optlen) == -1) { + return errno; + } else { + return err; + } + } + } else { + return ECONNREFUSED; + } +#elif defined(NCR) || defined(UNIXWARE) || defined(SNI) || defined(NEC) + /* + * getsockopt() fails with EPIPE, so use getmsg() instead. + */ + + int rv; + int flags = 0; + rv = getmsg(osfd, NULL, NULL, &flags); + PR_ASSERT(-1 == rv || 0 == rv); + if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) { + return errno; + } + return 0; /* no error */ +#else + int err; + _PRSockLen_t optlen = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) { + return errno; + } else { + return err; + } +#endif +} + +/************************************************************************/ + +/* +** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread +** safe. Unfortunately, neither is mozilla. To make these programs work +** in a pre-emptive threaded environment, we need to use a lock. +*/ + +void PR_XLock(void) +{ + PR_EnterMonitor(_pr_Xfe_mon); +} + +void PR_XUnlock(void) +{ + PR_ExitMonitor(_pr_Xfe_mon); +} + +PRBool PR_XIsLocked(void) +{ + return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE; +} + +void PR_XWait(int ms) +{ + PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms)); +} + +void PR_XNotify(void) +{ + PR_Notify(_pr_Xfe_mon); +} + +void PR_XNotifyAll(void) +{ + PR_NotifyAll(_pr_Xfe_mon); +} + +#if defined(HAVE_FCNTL_FILE_LOCKING) + +PRStatus +_MD_LockFile(PRInt32 f) +{ + PRInt32 rv; + struct flock arg; + + arg.l_type = F_WRLCK; + arg.l_whence = SEEK_SET; + arg.l_start = 0; + arg.l_len = 0; /* until EOF */ + rv = fcntl(f, F_SETLKW, &arg); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PRStatus +_MD_TLockFile(PRInt32 f) +{ + PRInt32 rv; + struct flock arg; + + arg.l_type = F_WRLCK; + arg.l_whence = SEEK_SET; + arg.l_start = 0; + arg.l_len = 0; /* until EOF */ + rv = fcntl(f, F_SETLK, &arg); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PRStatus +_MD_UnlockFile(PRInt32 f) +{ + PRInt32 rv; + struct flock arg; + + arg.l_type = F_UNLCK; + arg.l_whence = SEEK_SET; + arg.l_start = 0; + arg.l_len = 0; /* until EOF */ + rv = fcntl(f, F_SETLK, &arg); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +#elif defined(HAVE_BSD_FLOCK) + +#include + +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; +} + +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; +} + +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; +} +#else + +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; +} + +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; +} + +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; +} +#endif + +PRStatus _MD_gethostname(char *name, PRUint32 namelen) +{ + PRIntn rv; + + rv = gethostname(name, namelen); + if (0 == rv) { + return PR_SUCCESS; + } + _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PRStatus _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen) +{ + struct utsname info; + + PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE)); + + if (uname(&info) == -1) { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + if (PR_SI_SYSNAME == cmd) + (void)PR_snprintf(name, namelen, info.sysname); + else if (PR_SI_RELEASE == cmd) + (void)PR_snprintf(name, namelen, info.release); + else + return PR_FAILURE; + return PR_SUCCESS; +} + +/* + ******************************************************************* + * + * Memory-mapped files + * + ******************************************************************* + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ + PRFileInfo info; + PRUint32 sz; + + LL_L2UI(sz, size); + if (sz) { + if (PR_GetOpenFileInfo(fmap->fd, &info) == 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; + } + if (PR_Seek(fmap->fd, sz - 1, PR_SEEK_SET) == -1) { + return PR_FAILURE; + } + if (PR_Write(fmap->fd, "", 1) != 1) { + return PR_FAILURE; + } + } + } + if (fmap->prot == PR_PROT_READONLY) { + fmap->md.prot = PROT_READ; +#ifdef OSF1V4_MAP_PRIVATE_BUG + /* + * Use MAP_SHARED to work around a bug in OSF1 V4.0D + * (QAR 70220 in the OSF_QAR database) that results in + * corrupted data in the memory-mapped region. This + * bug is fixed in V5.0. + */ + fmap->md.flags = MAP_SHARED; +#else + fmap->md.flags = MAP_PRIVATE; +#endif + } else if (fmap->prot == PR_PROT_READWRITE) { + 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; + } + return PR_SUCCESS; +} + +void * _MD_MemMap( + PRFileMap *fmap, + PRInt64 offset, + PRUint32 len) +{ + PRInt32 off; + void *addr; + + 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()); + addr = NULL; + } + return addr; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ + if (munmap(addr, len) == 0) { + return PR_SUCCESS; + } else { + if (errno == EINVAL) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, errno); + } else { + PR_SetError(PR_UNKNOWN_ERROR, errno); + } + return PR_FAILURE; + } +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ + if ( PR_TRUE == fmap->md.isAnonFM ) { + PRStatus rc = PR_Close( fmap->fd ); + if ( PR_FAILURE == rc ) { + PR_LOG( _pr_io_lm, PR_LOG_DEBUG, + ("_MD_CloseFileMap(): error closing anonymnous file map osfd")); + return PR_FAILURE; + } + } + PR_DELETE(fmap); + return PR_SUCCESS; +} + +#if defined(_PR_NEED_FAKE_POLL) + +/* + * Some platforms don't have poll(). For easier porting of code + * that calls poll(), we emulate poll() using select(). + */ + +int poll(struct pollfd *filedes, unsigned long nfds, int timeout) +{ + int i; + int rv; + int maxfd; + fd_set rd, wr, ex; + struct timeval tv, *tvp; + + if (timeout < 0 && timeout != -1) { + errno = EINVAL; + return -1; + } + + if (timeout == -1) { + tvp = NULL; + } else { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + tvp = &tv; + } + + maxfd = -1; + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + + for (i = 0; i < nfds; i++) { + int osfd = filedes[i].fd; + int events = filedes[i].events; + PRBool fdHasEvent = PR_FALSE; + + if (osfd < 0) { + continue; /* Skip this 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; + for (i = 0; i < nfds; i++) { + PRBool fdHasEvent = PR_FALSE; + + 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++; + } + } + PR_ASSERT(rv > 0); + } else if (rv == -1 && errno == EBADF) { + rv = 0; + for (i = 0; i < nfds; i++) { + filedes[i].revents = 0; + if (filedes[i].fd < 0) { + continue; + } + if (fcntl(filedes[i].fd, F_GETFL, 0) == -1) { + filedes[i].revents = POLLNVAL; + rv++; + } + } + PR_ASSERT(rv > 0); + } + PR_ASSERT(-1 != timeout || rv != 0); + + return rv; +} +#endif /* _PR_NEED_FAKE_POLL */ diff --git a/nsprpub/pr/src/md/unix/unix_errors.c b/nsprpub/pr/src/md/unix/unix_errors.c new file mode 100644 index 00000000000..90ebe7de45e --- /dev/null +++ b/nsprpub/pr/src/md/unix/unix_errors.c @@ -0,0 +1,877 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#if defined(_PR_POLL_AVAILABLE) +#include +#endif +#include + +void _MD_unix_map_default_error(int err) +{ + PRErrorCode prError; + + switch (err ) { + case EACCES: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case EADDRINUSE: + prError = PR_ADDRESS_IN_USE_ERROR; + break; + case EADDRNOTAVAIL: + prError = PR_ADDRESS_NOT_AVAILABLE_ERROR; + break; + case EAFNOSUPPORT: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case EAGAIN: + prError = PR_WOULD_BLOCK_ERROR; + break; + /* + * On QNX and Neutrino, EALREADY is defined as EBUSY. + */ +#if EALREADY != EBUSY + case EALREADY: + prError = PR_ALREADY_INITIATED_ERROR; + break; +#endif + case EBADF: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; +#ifdef EBADMSG + case EBADMSG: + prError = PR_IO_ERROR; + break; +#endif + case EBUSY: + prError = PR_FILESYSTEM_MOUNTED_ERROR; + break; + case ECONNABORTED: + prError = PR_CONNECT_ABORTED_ERROR; + break; + case ECONNREFUSED: + prError = PR_CONNECT_REFUSED_ERROR; + break; + case ECONNRESET: + prError = PR_CONNECT_RESET_ERROR; + break; + case EDEADLK: + prError = PR_DEADLOCK_ERROR; + break; +#ifdef EDIRCORRUPTED + case EDIRCORRUPTED: + prError = PR_DIRECTORY_CORRUPTED_ERROR; + break; +#endif +#ifdef EDQUOT + case EDQUOT: + prError = PR_NO_DEVICE_SPACE_ERROR; + break; +#endif + case EEXIST: + prError = PR_FILE_EXISTS_ERROR; + break; + case EFAULT: + prError = PR_ACCESS_FAULT_ERROR; + break; + case EFBIG: + prError = PR_FILE_TOO_BIG_ERROR; + break; + case EHOSTUNREACH: + prError = PR_HOST_UNREACHABLE_ERROR; + break; + case EINPROGRESS: + prError = PR_IN_PROGRESS_ERROR; + break; + case EINTR: + prError = PR_PENDING_INTERRUPT_ERROR; + break; + case EINVAL: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case EIO: + prError = PR_IO_ERROR; + break; + case EISCONN: + prError = PR_IS_CONNECTED_ERROR; + break; + case EISDIR: + prError = PR_IS_DIRECTORY_ERROR; + break; + case ELOOP: + prError = PR_LOOP_ERROR; + break; + case EMFILE: + prError = PR_PROC_DESC_TABLE_FULL_ERROR; + break; + case EMLINK: + prError = PR_MAX_DIRECTORY_ENTRIES_ERROR; + break; + case EMSGSIZE: + prError = PR_INVALID_ARGUMENT_ERROR; + break; +#ifdef EMULTIHOP + case EMULTIHOP: + prError = PR_REMOTE_FILE_ERROR; + break; +#endif + case ENAMETOOLONG: + prError = PR_NAME_TOO_LONG_ERROR; + break; + case ENETUNREACH: + prError = PR_NETWORK_UNREACHABLE_ERROR; + break; + case ENFILE: + prError = PR_SYS_DESC_TABLE_FULL_ERROR; + break; + /* + * On SCO OpenServer 5, ENOBUFS is defined as ENOSR. + */ +#if defined(ENOBUFS) && (ENOBUFS != ENOSR) + case ENOBUFS: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; +#endif + case ENODEV: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ENOENT: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ENOLCK: + prError = PR_FILE_IS_LOCKED_ERROR; + break; +#ifdef ENOLINK + case ENOLINK: + prError = PR_REMOTE_FILE_ERROR; + break; +#endif + case ENOMEM: + prError = PR_OUT_OF_MEMORY_ERROR; + break; + case ENOPROTOOPT: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case ENOSPC: + prError = PR_NO_DEVICE_SPACE_ERROR; + break; +#ifdef ENOSR + case ENOSR: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; +#endif + case ENOTCONN: + prError = PR_NOT_CONNECTED_ERROR; + break; + case ENOTDIR: + prError = PR_NOT_DIRECTORY_ERROR; + break; + case ENOTSOCK: + prError = PR_NOT_SOCKET_ERROR; + break; + case ENXIO: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case EOPNOTSUPP: + prError = PR_NOT_TCP_SOCKET_ERROR; + break; +#ifdef EOVERFLOW + case EOVERFLOW: + prError = PR_BUFFER_OVERFLOW_ERROR; + break; +#endif + case EPERM: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case EPIPE: + prError = PR_CONNECT_RESET_ERROR; + break; +#ifdef EPROTO + case EPROTO: + prError = PR_IO_ERROR; + break; +#endif + case EPROTONOSUPPORT: + prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR; + break; + case EPROTOTYPE: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case ERANGE: + prError = PR_INVALID_METHOD_ERROR; + break; + case EROFS: + prError = PR_READ_ONLY_FILESYSTEM_ERROR; + break; + case ESPIPE: + prError = PR_INVALID_METHOD_ERROR; + break; + case ETIMEDOUT: + prError = PR_IO_TIMEOUT_ERROR; + break; +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: + prError = PR_WOULD_BLOCK_ERROR; + break; +#endif + case EXDEV: + prError = PR_NOT_SAME_DEVICE_ERROR; + break; + default: + prError = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_opendir_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_closedir_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_readdir_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case 0: + case ENOENT: + prError = PR_NO_MORE_FILES_ERROR; + break; +#ifdef EOVERFLOW + case EOVERFLOW: + prError = PR_IO_ERROR; + break; +#endif + case EINVAL: + prError = PR_IO_ERROR; + break; + case ENXIO: + prError = PR_IO_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_unlink_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EPERM: + prError = PR_IS_DIRECTORY_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_stat_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_fstat_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_rename_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EEXIST: + prError = PR_DIRECTORY_NOT_EMPTY_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_access_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_mkdir_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_rmdir_error(int err) +{ + PRErrorCode prError; + + switch (err) { + /* + * On AIX 4.3, ENOTEMPTY is defined as EEXIST. + */ +#if ENOTEMPTY != EEXIST + case ENOTEMPTY: + prError = PR_DIRECTORY_NOT_EMPTY_ERROR; + break; +#endif + case EEXIST: + prError = PR_DIRECTORY_NOT_EMPTY_ERROR; + break; + case EINVAL: + prError = PR_DIRECTORY_NOT_EMPTY_ERROR; + break; + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_read_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_INVALID_METHOD_ERROR; + break; + case ENXIO: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_write_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_INVALID_METHOD_ERROR; + break; + case ENXIO: + prError = PR_INVALID_METHOD_ERROR; + break; + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_lseek_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_fsync_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + case EINVAL: + prError = PR_INVALID_METHOD_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_close_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_socket_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_socketavailable_error(int err) +{ + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); +} + +void _MD_unix_map_recv_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_recvfrom_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_send_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_sendto_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_writev_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_accept_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENODEV: + prError = PR_NOT_TCP_SOCKET_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_connect_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EACCES: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; +#if defined(UNIXWARE) || defined(SNI) || defined(NEC) + /* + * On some platforms, if we connect to a port on the local host + * (the loopback address) that no process is listening on, we get + * EIO instead of ECONNREFUSED. + */ + case EIO: + prError = PR_CONNECT_REFUSED_ERROR; + break; +#endif + case ELOOP: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case ENOENT: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case ENXIO: + prError = PR_IO_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_bind_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; + break; + /* + * UNIX domain sockets are not supported in NSPR + */ + case EIO: + case EISDIR: + case ELOOP: + case ENOENT: + case ENOTDIR: + case EROFS: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_listen_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_shutdown_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_socketpair_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_getsockname_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_getpeername_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_getsockopt_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_BUFFER_OVERFLOW_ERROR; + break; + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_setsockopt_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_BUFFER_OVERFLOW_ERROR; + break; + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_open_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EAGAIN: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EBUSY: + prError = PR_IO_ERROR; + break; + case ENODEV: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; +#ifdef EOVERFLOW + case EOVERFLOW: + prError = PR_FILE_TOO_BIG_ERROR; + break; +#endif + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_mmap_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EAGAIN: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EMFILE: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case ENODEV: + prError = PR_OPERATION_NOT_SUPPORTED_ERROR; + break; + case ENXIO: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_gethostname_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_select_error(int err) +{ + _MD_unix_map_default_error(err); +} + +#if defined(_PR_POLL_AVAILABLE) || defined(_PR_NEED_FAKE_POLL) +void _MD_unix_map_poll_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EAGAIN: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + 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 || _PR_NEED_FAKE_POLL */ + + +void _MD_unix_map_flock_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + case EWOULDBLOCK: + prError = PR_FILE_IS_LOCKED_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_lockf_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EACCES: + prError = PR_FILE_IS_LOCKED_ERROR; + break; + case EDEADLK: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +#ifdef AIX +void _MD_aix_map_sendfile_error(int err) +{ + _MD_unix_map_default_error(err); +} +#endif /* AIX */ + +#ifdef HPUX11 +void _MD_hpux_map_sendfile_error(int err) +{ + _MD_unix_map_default_error(err); +} +#endif /* HPUX11 */ + +#ifdef SOLARIS +void _MD_solaris_map_sendfile_error(int err) +{ + PRErrorCode prError; + + switch (err) { + /* + * Solaris defines a 0 return value for sendfile to mean end-of-file. + */ + case 0: + prError = PR_END_OF_FILE_ERROR; + break; + + default: + _MD_unix_map_default_error(err) ; + return; + } + PR_SetError(prError, err); +} +#endif /* SOLARIS */ + +#ifdef LINUX +void _MD_linux_map_sendfile_error(int err) +{ + _MD_unix_map_default_error(err) ; +} +#endif /* LINUX */ diff --git a/nsprpub/pr/src/md/unix/unixware.c b/nsprpub/pr/src/md/unix/unixware.c new file mode 100644 index 00000000000..cbcbb3eb456 --- /dev/null +++ b/nsprpub/pr/src/md/unix/unixware.c @@ -0,0 +1,583 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#if !defined (USE_SVR4_THREADS) + +/* + * using only NSPR threads here + */ + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ + +PRInt32 _MD_connect(PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _connect(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); +} + +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _accept(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); + return(rv); +} +#endif + +/* + * These are also implemented in pratom.c using NSPR locks. Any reason + * this might be better or worse? If you like this better, define + * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h + */ +#ifdef _PR_HAVE_ATOMIC_OPS +/* Atomic operations */ +#include +static FILE *_uw_semf; + +void +_MD_INIT_ATOMIC(void) +{ + /* Sigh. Sure wish SYSV semaphores weren't such a pain to use */ + if ((_uw_semf = tmpfile()) == NULL) + PR_ASSERT(0); + + return; +} + +void +_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)++; + unflockfile(_uw_semf); +} + +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); + (*val)--; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + flockfile(_uw_semf); + *val = newval; + unflockfile(_uw_semf); +} +#endif + +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 Unixware */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Unixware."); +} + +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 Unixware."); +} + +#else /* USE_SVR4_THREADS */ + +/* NOTE: + * SPARC v9 (Ultras) do have an atomic test-and-set operation. But + * SPARC v8 doesn't. We should detect in the init if we are running on + * v8 or v9, and then use assembly where we can. + */ + +#include +#include + +static mutex_t _unixware_atomic = DEFAULTMUTEX; + +#define TEST_THEN_ADD(where, inc) \ + if (mutex_lock(&_unixware_atomic) != 0)\ + PR_ASSERT(0);\ + *where += inc;\ + if (mutex_unlock(&_unixware_atomic) != 0)\ + PR_ASSERT(0); + +#define TEST_THEN_SET(where, val) \ + if (mutex_lock(&_unixware_atomic) != 0)\ + PR_ASSERT(0);\ + *where = val;\ + if (mutex_unlock(&_unixware_atomic) != 0)\ + PR_ASSERT(0); + +void +_MD_INIT_ATOMIC(void) +{ +} + +void +_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + TEST_THEN_ADD(val, 1); +} + +void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + TEST_THEN_ADD(ptr, val); +} + +void +_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + TEST_THEN_ADD(val, 0xffffffff); +} + +void +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + TEST_THEN_SET(val, newval); +} + +#include +#include +#include + +#include +#include +#include + + +THREAD_KEY_T threadid_key; +THREAD_KEY_T cpuid_key; +THREAD_KEY_T last_thread_key; +static sigset_t set, oldset; + +void _MD_EarlyInit(void) +{ + THR_KEYCREATE(&threadid_key, NULL); + THR_KEYCREATE(&cpuid_key, NULL); + THR_KEYCREATE(&last_thread_key, NULL); + sigemptyset(&set); + sigaddset(&set, SIGALRM); +} + +PRStatus _MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + long flags; + + /* mask out SIGALRM for native thread creation */ + thr_sigsetmask(SIG_BLOCK, &set, &oldset); + + flags = (state == PR_JOINABLE_THREAD ? THR_SUSPENDED/*|THR_NEW_LWP*/ + : THR_SUSPENDED|THR_DETACHED/*|THR_NEW_LWP*/); + if (_PR_IS_GCABLE_THREAD(thread) || + (scope == PR_GLOBAL_BOUND_THREAD)) + flags |= THR_BOUND; + + if (thr_create(NULL, thread->stack->stackSize, + (void *(*)(void *)) start, (void *) thread, + flags, + &thread->md.handle)) { + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); + return PR_FAILURE; + } + + + /* When the thread starts running, then the lwpid is set to the right + * value. Until then we want to mark this as 'uninit' so that + * its register state is initialized properly for GC */ + + thread->md.lwpid = -1; + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); + _MD_NEW_SEM(&thread->md.waiter_sem, 0); + + if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) { + thread->flags |= _PR_GLOBAL_SCOPE; + } + + /* + ** Set the thread priority. This will also place the thread on + ** the runQ. + ** + ** Force PR_SetThreadPriority to set the priority by + ** setting thread->priority to 100. + */ + { + int pri; + pri = thread->priority; + thread->priority = 100; + PR_SetThreadPriority( thread, pri ); + + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("(0X%x)[Start]: on to runq at priority %d", + thread, thread->priority)); + } + + /* Activate the thread */ + if (thr_continue( thread->md.handle ) ) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void _MD_cleanup_thread(PRThread *thread) +{ + thread_t hdl; + PRMonitor *mon; + + hdl = thread->md.handle; + + /* + ** First, suspend the thread (unless it's the active one) + ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to + ** prevent both of us modifying the thread structure at the same time. + */ + if ( thread != _PR_MD_CURRENT_THREAD() ) { + thr_suspend(hdl); + } + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("(0X%x)[DestroyThread]\n", thread)); + + _MD_DESTROY_SEM(&thread->md.waiter_sem); +} + +void _MD_SET_PRIORITY(_MDThread *md_thread, PRUintn newPri) +{ + if(thr_setprio((thread_t)md_thread->handle, newPri)) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("_PR_SetThreadPriority: can't set thread priority\n")); + } +} + +void _MD_WAIT_CV( + struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout) +{ + struct timespec tt; + PRUint32 msec; + int rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + msec = PR_IntervalToMilliseconds(timeout); + + GETTIME (&tt); + + tt.tv_sec += msec / PR_MSEC_PER_SEC; + tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC; + /* Check for nsec overflow - otherwise we'll get an EINVAL */ + if (tt.tv_nsec >= PR_NSEC_PER_SEC) { + tt.tv_sec++; + tt.tv_nsec -= PR_NSEC_PER_SEC; + } + me->md.sp = unixware_getsp(); + + + /* XXX Solaris 2.5.x gives back EINTR occasionally for no reason + * hence ignore EINTR for now */ + + COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt); +} + +void _MD_lock(struct _MDLock *md_lock) +{ + mutex_lock(&md_lock->lock); +} + +void _MD_unlock(struct _MDLock *md_lock) +{ + mutex_unlock(&((md_lock)->lock)); +} + + +PRThread *_pr_current_thread_tls() +{ + PRThread *ret; + + thr_getspecific(threadid_key, (void **)&ret); + return ret; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + _MD_WAIT_SEM(&thread->md.waiter_sem); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread == NULL) { + return PR_SUCCESS; + } + _MD_POST_SEM(&thread->md.waiter_sem); + return PR_SUCCESS; +} + +_PRCPU *_pr_current_cpu_tls() +{ + _PRCPU *ret; + + thr_getspecific(cpuid_key, (void **)&ret); + return ret; +} + +PRThread *_pr_last_thread_tls() +{ + PRThread *ret; + + thr_getspecific(last_thread_key, (void **)&ret); + return ret; +} + +_MDLock _pr_ioq_lock; + +void _MD_INIT_IO (void) +{ + _MD_NEW_LOCK(&_pr_ioq_lock); +} + +PRStatus _MD_InitializeThread(PRThread *thread) +{ + if (!_PR_IS_NATIVE_THREAD(thread)) + return; + /* prime the sp; substract 4 so we don't hit the assert that + * curr sp > base_stack + */ + thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long); + thread->md.lwpid = _lwp_self(); + thread->md.handle = THR_SELF(); + + /* all threads on Solaris are global threads from NSPR's perspective + * since all of them are mapped to Solaris threads. + */ + thread->flags |= _PR_GLOBAL_SCOPE; + + /* For primordial/attached thread, we don't create an underlying native thread. + * So, _MD_CREATE_THREAD() does not get called. We need to do initialization + * like allocating thread's synchronization variables and set the underlying + * native thread's priority. + */ + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + _MD_NEW_SEM(&thread->md.waiter_sem, 0); + _MD_SET_PRIORITY(&(thread->md), thread->priority); + } + return PR_SUCCESS; +} + +static sigset_t old_mask; /* store away original gc thread sigmask */ +static int gcprio; /* store away original gc thread priority */ +static lwpid_t *all_lwps=NULL; /* list of lwps that we suspended */ +static int num_lwps ; +static int suspendAllOn = 0; + +#define VALID_SP(sp, bottom, top) \ + (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top))) + +void unixware_preempt_off() +{ + sigset_t set; + (void)sigfillset(&set); + sigprocmask (SIG_SETMASK, &set, &old_mask); +} + +void unixware_preempt_on() +{ + sigprocmask (SIG_SETMASK, &old_mask, NULL); +} + +void _MD_Begin_SuspendAll() +{ + unixware_preempt_off(); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n")); + /* run at highest prio so I cannot be preempted */ + thr_getprio(thr_self(), &gcprio); + thr_setprio(thr_self(), 0x7fffffff); + suspendAllOn = 1; +} + +void _MD_End_SuspendAll() +{ +} + +void _MD_End_ResumeAll() +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n")); + thr_setprio(thr_self(), gcprio); + unixware_preempt_on(); + suspendAllOn = 0; +} + +void _MD_Suspend(PRThread *thr) +{ + int lwp_fd, result; + int lwp_main_proc_fd = 0; + + thr_suspend(thr->md.handle); + if (!_PR_IS_GCABLE_THREAD(thr)) + return; + /* XXX Primordial thread can't be bound to an lwp, hence there is no + * way we can assume that we can get the lwp status for primordial + * thread reliably. Hence we skip this for primordial thread, hoping + * that the SP is saved during lock and cond. wait. + * XXX - Again this is concern only for java interpreter, not for the + * server, 'cause primordial thread in the server does not do java work + */ + if (thr->flags & _PR_PRIMORDIAL) + return; + + /* if the thread is not started yet then don't do anything */ + if (!suspendAllOn || thr->md.lwpid == -1) + return; + +} +void _MD_Resume(PRThread *thr) +{ + if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){ + /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend + * during that time we can't call any thread lib or libc calls. Hence + * make sure that no resume is requested for Non gcable thread + * during suspendAllOn */ + PR_ASSERT(!suspendAllOn); + thr_continue(thr->md.handle); + return; + } + if (thr->md.lwpid == -1) + return; + + if ( _lwp_continue(thr->md.lwpid) < 0) { + PR_ASSERT(0); /* ARGH, we are hosed! */ + } +} + + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) getcontext(CONTEXT(t)); /* XXX tune me: set md_IRIX.c */ + } + *np = NGREG; + if (t->md.lwpid == -1) + memset(&t->md.context.uc_mcontext.gregs[0], 0, NGREG * sizeof(PRWord)); + return (PRWord*) &t->md.context.uc_mcontext.gregs[0]; +} + +int +_pr_unixware_clock_gettime (struct timespec *tp) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000; + return 0; +} + + +#endif /* USE_SVR4_THREADS */ diff --git a/nsprpub/pr/src/md/unix/uxpoll.c b/nsprpub/pr/src/md/unix/uxpoll.c new file mode 100644 index 00000000000..aa026568e7f --- /dev/null +++ b/nsprpub/pr/src/md/unix/uxpoll.c @@ -0,0 +1,708 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if defined(_PR_PTHREADS) + +#error "This file should not be compiled" + +#else /* defined(_PR_PTHREADS) */ + +#include "primpl.h" + +#include + +#include +#ifdef _PR_USE_POLL +#include +#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; + syspoll[index].events = 0; + pds[index].out_flags = 0; + } + } + + 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 */ + } + } + } + else + { + pd->out_flags = 0; + } + } + + 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 = PR_IntervalToMicroseconds( remaining % 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) */ + +/* uxpoll.c */ + diff --git a/nsprpub/pr/src/md/unix/uxproces.c b/nsprpub/pr/src/md/unix/uxproces.c new file mode 100644 index 00000000000..66dcc92e81d --- /dev/null +++ b/nsprpub/pr/src/md/unix/uxproces.c @@ -0,0 +1,1000 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include +#include +#include +#include +#include +#if defined(AIX) +#include /* For dlopen, dlsym, dlclose */ +#endif + +#if defined(DARWIN) +#include +#else +PR_IMPORT_DATA(char **) environ; +#endif + +/* + * HP-UX 9 doesn't have the SA_RESTART flag. + */ +#ifndef SA_RESTART +#define SA_RESTART 0 +#endif + +#if defined(VMS) +static PRLock *_pr_vms_fork_lock = NULL; +#endif + +/* + ********************************************************************** + * + * The Unix process routines + * + ********************************************************************** + */ + +#define _PR_SIGNALED_EXITSTATUS 256 + +typedef enum pr_PidState { + _PR_PID_DETACHED, + _PR_PID_REAPED, + _PR_PID_WAITING +} pr_PidState; + +typedef struct pr_PidRecord { + pid_t pid; + int exitStatus; + pr_PidState state; + PRCondVar *reapedCV; + struct pr_PidRecord *next; +} pr_PidRecord; + +/* + * Irix sprocs and LinuxThreads are actually a kind of processes + * that can share the virtual address space and file descriptors. + */ +#if (defined(IRIX) && !defined(_PR_PTHREADS)) \ + || ((defined(LINUX) || defined(__GNU__) || defined(__GLIBC__)) \ + && defined(_PR_PTHREADS)) +#define _PR_SHARE_CLONES +#endif + +/* + * The macro _PR_NATIVE_THREADS indicates that we are + * using native threads only, so waitpid() blocks just the + * calling thread, not the process. In this case, the waitpid + * daemon thread can safely block in waitpid(). So we don't + * need to catch SIGCHLD, and the pipe to unblock PR_Poll() is + * also not necessary. + */ + +#if defined(_PR_GLOBAL_THREADS_ONLY) \ + || (defined(_PR_PTHREADS) \ + && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__)) +#define _PR_NATIVE_THREADS +#endif + +/* + * All the static variables used by the Unix process routines are + * collected in this structure. + */ + +static struct { + PRCallOnceType once; + PRThread *thread; + PRLock *ml; +#if defined(_PR_NATIVE_THREADS) + PRInt32 numProcs; + PRCondVar *cv; +#else + int pipefd[2]; +#endif + pr_PidRecord **pidTable; + +#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 +static int pr_waitpid_daemon_exit; + +void +_MD_unix_terminate_waitpid_daemon(void) +{ + if (pr_wp.thread) { + pr_waitpid_daemon_exit = 1; + write(pr_wp.pipefd[1], "", 1); + PR_JoinThread(pr_wp.thread); + } +} +#endif + +static PRStatus _MD_InitProcesses(void); +#if !defined(_PR_NATIVE_THREADS) +static void pr_InstallSigchldHandler(void); +#endif + +static PRProcess * +ForkAndExec( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + PRProcess *process; + int nEnv, idx; + char *const *childEnvp; + char **newEnvp = NULL; + int flags; +#ifdef VMS + char VMScurdir[FILENAME_MAX+1] = { '\0' } ; +#endif + + process = PR_NEW(PRProcess); + if (!process) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + childEnvp = envp; + if (attr && attr->fdInheritBuffer) { + PRBool found = PR_FALSE; + + if (NULL == childEnvp) { +#ifdef DARWIN + childEnvp = *(_NSGetEnviron()); +#else + childEnvp = environ; +#endif + } + for (nEnv = 0; childEnvp[nEnv]; nEnv++) { + } + newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *)); + if (NULL == newEnvp) { + PR_DELETE(process); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + for (idx = 0; idx < nEnv; idx++) { + newEnvp[idx] = childEnvp[idx]; + if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) { + newEnvp[idx] = attr->fdInheritBuffer; + found = PR_TRUE; + } + } + if (!found) { + newEnvp[idx++] = attr->fdInheritBuffer; + } + newEnvp[idx] = NULL; + childEnvp = newEnvp; + } + +#ifdef VMS +/* +** Since vfork/exec is implemented VERY differently on OpenVMS, we have to +** handle the setting up of the standard streams very differently. And since +** none of this code can ever execute in the context of the child, we have +** to perform the chdir in the parent so the child is born into the correct +** directory (and then switch the parent back again). +*/ +{ + int decc$set_child_standard_streams(int,int,int); + int n, fd_stdin=0, fd_stdout=1, fd_stderr=2; + + /* Set up any standard streams we are given, assuming defaults */ + if (attr) { + if (attr->stdinFd) + fd_stdin = attr->stdinFd->secret->md.osfd; + if (attr->stdoutFd) + fd_stdout = attr->stdoutFd->secret->md.osfd; + if (attr->stderrFd) + fd_stderr = attr->stderrFd->secret->md.osfd; + } + + /* + ** Put a lock around anything that isn't going to be thread-safe. + */ + PR_Lock(_pr_vms_fork_lock); + + /* + ** Prepare the child's streams. We always do this in case a previous fork + ** has left the stream assignments in some non-standard way. + */ + n = decc$set_child_standard_streams(fd_stdin,fd_stdout,fd_stderr); + if (n == -1) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + PR_Unlock(_pr_vms_fork_lock); + return NULL; + } + + /* Switch directory if we have to */ + if (attr) { + if (attr->currentDirectory) { + if ( (getcwd(VMScurdir,sizeof(VMScurdir)) == NULL) || + (chdir(attr->currentDirectory) < 0) ) { + PR_SetError(PR_DIRECTORY_OPEN_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + PR_Unlock(_pr_vms_fork_lock); + return NULL; + } + } + } +} +#endif /* VMS */ + +#ifdef AIX + process->md.pid = (*pr_wp.forkptr)(); +#elif defined(NTO) + /* + * fork() & exec() does not work in a multithreaded process. + * Use spawn() instead. + */ + { + int fd_map[3] = { 0, 1, 2 }; + + if (attr) { + if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) { + fd_map[0] = dup(attr->stdinFd->secret->md.osfd); + flags = fcntl(fd_map[0], F_GETFL, 0); + if (flags & O_NONBLOCK) + fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK); + } + if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) { + fd_map[1] = dup(attr->stdoutFd->secret->md.osfd); + flags = fcntl(fd_map[1], F_GETFL, 0); + if (flags & O_NONBLOCK) + fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK); + } + if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) { + fd_map[2] = dup(attr->stderrFd->secret->md.osfd); + flags = fcntl(fd_map[2], F_GETFL, 0); + if (flags & O_NONBLOCK) + fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK); + } + + PR_ASSERT(attr->currentDirectory == NULL); /* not implemented */ + } + + process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp); + + if (fd_map[0] != 0) + close(fd_map[0]); + if (fd_map[1] != 1) + close(fd_map[1]); + if (fd_map[2] != 2) + close(fd_map[2]); + } +#else + process->md.pid = fork(); +#endif + if ((pid_t) -1 == process->md.pid) { + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + return NULL; + } else if (0 == process->md.pid) { /* the child process */ + /* + * If the child process needs to exit, it must call _exit(). + * Do not call exit(), because exit() will flush and close + * the standard I/O file descriptors, and hence corrupt + * the parent process's standard I/O data structures. + */ + +#if !defined(NTO) +#ifdef VMS + /* OpenVMS has already handled all this above */ +#else + if (attr) { + /* the osfd's to redirect stdin, stdout, and stderr to */ + int in_osfd = -1, out_osfd = -1, err_osfd = -1; + + if (attr->stdinFd + && attr->stdinFd->secret->md.osfd != 0) { + in_osfd = attr->stdinFd->secret->md.osfd; + if (dup2(in_osfd, 0) != 0) { + _exit(1); /* failed */ + } + flags = fcntl(0, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(0, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (attr->stdoutFd + && attr->stdoutFd->secret->md.osfd != 1) { + out_osfd = attr->stdoutFd->secret->md.osfd; + if (dup2(out_osfd, 1) != 1) { + _exit(1); /* failed */ + } + flags = fcntl(1, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(1, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (attr->stderrFd + && attr->stderrFd->secret->md.osfd != 2) { + err_osfd = attr->stderrFd->secret->md.osfd; + if (dup2(err_osfd, 2) != 2) { + _exit(1); /* failed */ + } + flags = fcntl(2, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(2, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (in_osfd != -1) { + close(in_osfd); + } + if (out_osfd != -1 && out_osfd != in_osfd) { + close(out_osfd); + } + if (err_osfd != -1 && err_osfd != in_osfd + && err_osfd != out_osfd) { + close(err_osfd); + } + if (attr->currentDirectory) { + if (chdir(attr->currentDirectory) < 0) { + _exit(1); /* failed */ + } + } + } +#endif /* !VMS */ + + if (childEnvp) { + (void)execve(path, argv, childEnvp); + } else { + /* Inherit the environment of the parent. */ + (void)execv(path, argv); + } + /* Whoops! It returned. That's a bad sign. */ +#ifdef VMS + /* + ** On OpenVMS we are still in the context of the parent, and so we + ** can (and should!) perform normal error handling. + */ + PR_SetError(PR_UNKNOWN_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (VMScurdir[0] != '\0') + chdir(VMScurdir); + PR_Unlock(_pr_vms_fork_lock); + return NULL; +#else + _exit(1); +#endif /* VMS */ +#endif /* !NTO */ + } + + if (newEnvp) { + PR_DELETE(newEnvp); + } +#ifdef VMS + /* If we switched directories, then remember to switch back */ + if (VMScurdir[0] != '\0') { + chdir(VMScurdir); /* can't do much if it fails */ + } + PR_Unlock(_pr_vms_fork_lock); +#endif /* VMS */ + +#if defined(_PR_NATIVE_THREADS) + PR_Lock(pr_wp.ml); + if (0 == pr_wp.numProcs++) { + PR_NotifyCondVar(pr_wp.cv); + } + PR_Unlock(pr_wp.ml); +#endif + return process; +} + +#ifdef _PR_SHARE_CLONES + +struct pr_CreateProcOp { + const char *path; + char *const *argv; + char *const *envp; + const PRProcessAttr *attr; + PRProcess *process; + PRErrorCode prerror; + PRInt32 oserror; + PRBool done; + PRCondVar *doneCV; + struct pr_CreateProcOp *next; +}; + +PRProcess * +_MD_CreateUnixProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + struct pr_CreateProcOp *op; + PRProcess *proc; + int rv; + + if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) { + return NULL; + } + + op = PR_NEW(struct pr_CreateProcOp); + if (NULL == op) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + op->path = path; + op->argv = argv; + op->envp = envp; + op->attr = attr; + op->done = PR_FALSE; + op->doneCV = PR_NewCondVar(pr_wp.ml); + if (NULL == op->doneCV) { + PR_DELETE(op); + return NULL; + } + PR_Lock(pr_wp.ml); + + /* add to the tail of op queue */ + op->next = NULL; + if (pr_wp.opTail) { + pr_wp.opTail->next = op; + pr_wp.opTail = op; + } else { + PR_ASSERT(NULL == pr_wp.opHead); + pr_wp.opHead = pr_wp.opTail = op; + } + + /* wake up the daemon thread */ + do { + rv = write(pr_wp.pipefd[1], "", 1); + } while (-1 == rv && EINTR == errno); + + while (op->done == PR_FALSE) { + PR_WaitCondVar(op->doneCV, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(pr_wp.ml); + PR_DestroyCondVar(op->doneCV); + proc = op->process; + if (!proc) { + PR_SetError(op->prerror, op->oserror); + } + PR_DELETE(op); + return proc; +} + +#else /* ! _PR_SHARE_CLONES */ + +PRProcess * +_MD_CreateUnixProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) { + return NULL; + } + return ForkAndExec(path, argv, envp, attr); +} /* _MD_CreateUnixProcess */ + +#endif /* _PR_SHARE_CLONES */ + +/* + * The pid table is a hashtable. + * + * The number of buckets in the hashtable (NBUCKETS) must be a power of 2. + */ +#define NBUCKETS_LOG2 6 +#define NBUCKETS (1 << NBUCKETS_LOG2) +#define PID_HASH_MASK ((pid_t) (NBUCKETS - 1)) + +static pr_PidRecord * +FindPidTable(pid_t pid) +{ + pr_PidRecord *pRec; + int keyHash = (int) (pid & PID_HASH_MASK); + + pRec = pr_wp.pidTable[keyHash]; + while (pRec) { + if (pRec->pid == pid) { + break; + } + pRec = pRec->next; + } + return pRec; +} + +static void +InsertPidTable(pr_PidRecord *pRec) +{ + int keyHash = (int) (pRec->pid & PID_HASH_MASK); + + pRec->next = pr_wp.pidTable[keyHash]; + pr_wp.pidTable[keyHash] = pRec; +} + +static void +DeletePidTable(pr_PidRecord *pRec) +{ + int keyHash = (int) (pRec->pid & PID_HASH_MASK); + + if (pr_wp.pidTable[keyHash] == pRec) { + pr_wp.pidTable[keyHash] = pRec->next; + } else { + pr_PidRecord *pred, *cur; /* predecessor and current */ + + pred = pr_wp.pidTable[keyHash]; + cur = pred->next; + while (cur) { + if (cur == pRec) { + pred->next = cur->next; + break; + } + pred = cur; + cur = cur->next; + } + PR_ASSERT(cur != NULL); + } +} + +static int +ExtractExitStatus(int rawExitStatus) +{ + /* + * We did not specify the WCONTINUED and WUNTRACED options + * for waitpid, so these two events should not be reported. + */ + PR_ASSERT(!WIFSTOPPED(rawExitStatus)); +#ifdef WIFCONTINUED + PR_ASSERT(!WIFCONTINUED(rawExitStatus)); +#endif + if (WIFEXITED(rawExitStatus)) { + return WEXITSTATUS(rawExitStatus); + } else { + PR_ASSERT(WIFSIGNALED(rawExitStatus)); + return _PR_SIGNALED_EXITSTATUS; + } +} + +static void +ProcessReapedChildInternal(pid_t pid, int status) +{ + pr_PidRecord *pRec; + + pRec = FindPidTable(pid); + if (NULL == pRec) { + pRec = PR_NEW(pr_PidRecord); + pRec->pid = pid; + pRec->state = _PR_PID_REAPED; + pRec->exitStatus = ExtractExitStatus(status); + pRec->reapedCV = NULL; + InsertPidTable(pRec); + } else { + PR_ASSERT(pRec->state != _PR_PID_REAPED); + if (_PR_PID_DETACHED == pRec->state) { + PR_ASSERT(NULL == pRec->reapedCV); + DeletePidTable(pRec); + PR_DELETE(pRec); + } else { + PR_ASSERT(_PR_PID_WAITING == pRec->state); + PR_ASSERT(NULL != pRec->reapedCV); + pRec->exitStatus = ExtractExitStatus(status); + pRec->state = _PR_PID_REAPED; + PR_NotifyCondVar(pRec->reapedCV); + } + } +} + +#if defined(_PR_NATIVE_THREADS) + +/* + * If all the threads are native threads, the daemon thread is + * simpler. We don't need to catch the SIGCHLD signal. We can + * just have the daemon thread block in waitpid(). + */ + +static void WaitPidDaemonThread(void *unused) +{ + pid_t pid; + int status; + + while (1) { + PR_Lock(pr_wp.ml); + while (0 == pr_wp.numProcs) { + PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(pr_wp.ml); + + while (1) { + do { + pid = waitpid((pid_t) -1, &status, 0); + } while ((pid_t) -1 == pid && EINTR == errno); + + /* + * waitpid() cannot return 0 because we did not invoke it + * with the WNOHANG option. + */ + PR_ASSERT(0 != pid); + + /* + * The only possible error code is ECHILD. But if we do + * our accounting correctly, we should only call waitpid() + * when there is a child process to wait for. + */ + PR_ASSERT((pid_t) -1 != pid); + if ((pid_t) -1 == pid) { + break; + } + + PR_Lock(pr_wp.ml); + ProcessReapedChildInternal(pid, status); + pr_wp.numProcs--; + while (0 == pr_wp.numProcs) { + PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(pr_wp.ml); + } + } +} + +#else /* _PR_NATIVE_THREADS */ + +static void WaitPidDaemonThread(void *unused) +{ + PRPollDesc pd; + PRFileDesc *fd; + int rv; + char buf[128]; + pid_t pid; + int status; +#ifdef _PR_SHARE_CLONES + struct pr_CreateProcOp *op; +#endif + +#ifdef _PR_SHARE_CLONES + pr_InstallSigchldHandler(); +#endif + + fd = PR_ImportFile(pr_wp.pipefd[0]); + PR_ASSERT(NULL != fd); + pd.fd = fd; + pd.in_flags = PR_POLL_READ; + + while (1) { + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(1 == rv); + +#ifdef _PR_SHARE_CLONES + if (pr_waitpid_daemon_exit) { + return; + } + PR_Lock(pr_wp.ml); +#endif + + do { + rv = read(pr_wp.pipefd[0], buf, sizeof(buf)); + } while (sizeof(buf) == rv || (-1 == rv && EINTR == errno)); + +#ifdef _PR_SHARE_CLONES + PR_Unlock(pr_wp.ml); + while ((op = pr_wp.opHead) != NULL) { + op->process = ForkAndExec(op->path, op->argv, + op->envp, op->attr); + if (NULL == op->process) { + op->prerror = PR_GetError(); + op->oserror = PR_GetOSError(); + } + PR_Lock(pr_wp.ml); + pr_wp.opHead = op->next; + if (NULL == pr_wp.opHead) { + pr_wp.opTail = NULL; + } + op->done = PR_TRUE; + PR_NotifyCondVar(op->doneCV); + PR_Unlock(pr_wp.ml); + } +#endif + + while (1) { + do { + pid = waitpid((pid_t) -1, &status, WNOHANG); + } while ((pid_t) -1 == pid && EINTR == errno); + if (0 == pid) break; + if ((pid_t) -1 == pid) { + /* must be because we have no child processes */ + PR_ASSERT(ECHILD == errno); + break; + } + + PR_Lock(pr_wp.ml); + ProcessReapedChildInternal(pid, status); + PR_Unlock(pr_wp.ml); + } + } +} + +static void pr_SigchldHandler(int sig) +{ + int errnoCopy; + int rv; + + errnoCopy = errno; + + do { + rv = write(pr_wp.pipefd[1], "", 1); + } while (-1 == rv && EINTR == errno); + +#ifdef DEBUG + if (-1 == rv && EAGAIN != errno && EWOULDBLOCK != errno) { + char *msg = "cannot write to pipe\n"; + write(2, msg, strlen(msg) + 1); + _exit(1); + } +#endif + + errno = errnoCopy; +} + +static void pr_InstallSigchldHandler() +{ +#if defined(HPUX) && defined(_PR_DCETHREADS) +#error "HP-UX DCE threads have their own SIGCHLD handler" +#endif + + struct sigaction act, oact; + int rv; + + act.sa_handler = pr_SigchldHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_NOCLDSTOP | SA_RESTART; + rv = sigaction(SIGCHLD, &act, &oact); + PR_ASSERT(0 == rv); + /* Make sure we are not overriding someone else's SIGCHLD handler */ +#ifndef _PR_SHARE_CLONES + PR_ASSERT(oact.sa_handler == SIG_DFL); +#endif +} + +#endif /* !defined(_PR_NATIVE_THREADS) */ + +static PRStatus _MD_InitProcesses(void) +{ +#if !defined(_PR_NATIVE_THREADS) + int rv; + int flags; +#endif +#ifdef SUNOS4 +#define _PR_NBIO_FLAG FNDELAY +#else +#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); + +#if defined(VMS) + _pr_vms_fork_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_vms_fork_lock); +#endif + +#if defined(_PR_NATIVE_THREADS) + pr_wp.numProcs = 0; + pr_wp.cv = PR_NewCondVar(pr_wp.ml); + PR_ASSERT(NULL != pr_wp.cv); +#else + rv = pipe(pr_wp.pipefd); + PR_ASSERT(0 == rv); + flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0); + fcntl(pr_wp.pipefd[0], F_SETFL, flags | _PR_NBIO_FLAG); + flags = fcntl(pr_wp.pipefd[1], F_GETFL, 0); + fcntl(pr_wp.pipefd[1], F_SETFL, flags | _PR_NBIO_FLAG); + +#ifndef _PR_SHARE_CLONES + pr_InstallSigchldHandler(); +#endif +#endif /* !_PR_NATIVE_THREADS */ + + pr_wp.thread = PR_CreateThread(PR_SYSTEM_THREAD, + WaitPidDaemonThread, NULL, PR_PRIORITY_NORMAL, +#ifdef _PR_SHARE_CLONES + PR_GLOBAL_THREAD, +#else + PR_LOCAL_THREAD, +#endif + PR_JOINABLE_THREAD, 0); + PR_ASSERT(NULL != pr_wp.thread); + + pr_wp.pidTable = (pr_PidRecord**)PR_CALLOC(NBUCKETS * sizeof(pr_PidRecord *)); + PR_ASSERT(NULL != pr_wp.pidTable); + return PR_SUCCESS; +} + +PRStatus _MD_DetachUnixProcess(PRProcess *process) +{ + PRStatus retVal = PR_SUCCESS; + pr_PidRecord *pRec; + + PR_Lock(pr_wp.ml); + pRec = FindPidTable(process->md.pid); + if (NULL == pRec) { + pRec = PR_NEW(pr_PidRecord); + if (NULL == pRec) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + retVal = PR_FAILURE; + goto done; + } + pRec->pid = process->md.pid; + pRec->state = _PR_PID_DETACHED; + pRec->reapedCV = NULL; + InsertPidTable(pRec); + } else { + PR_ASSERT(_PR_PID_REAPED == pRec->state); + if (_PR_PID_REAPED != pRec->state) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + retVal = PR_FAILURE; + } else { + DeletePidTable(pRec); + PR_ASSERT(NULL == pRec->reapedCV); + PR_DELETE(pRec); + } + } + PR_DELETE(process); + +done: + PR_Unlock(pr_wp.ml); + return retVal; +} + +PRStatus _MD_WaitUnixProcess( + PRProcess *process, + PRInt32 *exitCode) +{ + pr_PidRecord *pRec; + PRStatus retVal = PR_SUCCESS; + PRBool interrupted = PR_FALSE; + + PR_Lock(pr_wp.ml); + pRec = FindPidTable(process->md.pid); + if (NULL == pRec) { + pRec = PR_NEW(pr_PidRecord); + if (NULL == pRec) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + retVal = PR_FAILURE; + goto done; + } + pRec->pid = process->md.pid; + pRec->state = _PR_PID_WAITING; + pRec->reapedCV = PR_NewCondVar(pr_wp.ml); + if (NULL == pRec->reapedCV) { + PR_DELETE(pRec); + retVal = PR_FAILURE; + goto done; + } + InsertPidTable(pRec); + while (!interrupted && _PR_PID_REAPED != pRec->state) { + if (PR_WaitCondVar(pRec->reapedCV, + PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE + && PR_GetError() == PR_PENDING_INTERRUPT_ERROR) { + interrupted = PR_TRUE; + } + } + if (_PR_PID_REAPED == pRec->state) { + if (exitCode) { + *exitCode = pRec->exitStatus; + } + } else { + PR_ASSERT(interrupted); + retVal = PR_FAILURE; + } + DeletePidTable(pRec); + PR_DestroyCondVar(pRec->reapedCV); + PR_DELETE(pRec); + } else { + PR_ASSERT(_PR_PID_REAPED == pRec->state); + PR_ASSERT(NULL == pRec->reapedCV); + DeletePidTable(pRec); + if (exitCode) { + *exitCode = pRec->exitStatus; + } + PR_DELETE(pRec); + } + PR_DELETE(process); + +done: + PR_Unlock(pr_wp.ml); + return retVal; +} /* _MD_WaitUnixProcess */ + +PRStatus _MD_KillUnixProcess(PRProcess *process) +{ + PRErrorCode prerror; + PRInt32 oserror; + + if (kill(process->md.pid, SIGKILL) == 0) { + return PR_SUCCESS; + } + oserror = errno; + switch (oserror) { + case EPERM: + prerror = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case ESRCH: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, oserror); + return PR_FAILURE; +} /* _MD_KillUnixProcess */ diff --git a/nsprpub/pr/src/md/unix/uxrng.c b/nsprpub/pr/src/md/unix/uxrng.c new file mode 100644 index 00000000000..50b18826482 --- /dev/null +++ b/nsprpub/pr/src/md/unix/uxrng.c @@ -0,0 +1,341 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "primpl.h" + +#include +#include +#include +#include + + +#if defined(SOLARIS) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + hrtime_t t; + t = gethrtime(); + if (t) { + return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); + } + return 0; +} + +#elif defined(SUNOS4) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +#elif defined(HPUX) + +#ifdef __ia64 +#include + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + PRUint64 t; + + t = _Asm_mov_from_ar(_AREG44); + return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); +} +#else +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + extern int ret_cr16(); + int cr16val; + + cr16val = ret_cr16(); + return(_pr_CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val))); +} +#endif + +#elif defined(OSF1) + +#include + +/* + * Use the "get the cycle counter" instruction on the alpha. + * The low 32 bits completely turn over in less than a minute. + * The high 32 bits are some non-counter gunk that changes sometimes. + */ +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + unsigned long t; + +#ifdef __GNUC__ + __asm__("rpcc %0" : "=r" (t)); +#else + t = asm("rpcc %v0"); +#endif + return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); +} + +#elif defined(VMS) + +#include + +/* + * Use the "get the cycle counter" instruction on the alpha. + * The low 32 bits completely turn over in less than a minute. + * The high 32 bits are some non-counter gunk that changes sometimes. + */ +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + uint64 t; + + t = __RPCC(); + return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); +} + +#elif defined(AIX) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +#elif (defined(LINUX) || defined(FREEBSD) || defined(__FreeBSD_kernel__) \ + || defined(NETBSD) || defined(__NetBSD_kernel__) || defined(OPENBSD)) +#include +#include +#include + +static int fdDevRandom; +static PRCallOnceType coOpenDevRandom; + +static PRStatus OpenDevRandom( void ) +{ + fdDevRandom = open( "/dev/random", O_RDONLY ); + return((-1 == fdDevRandom)? PR_FAILURE : PR_SUCCESS ); +} /* end OpenDevRandom() */ + +static size_t GetDevRandom( void *buf, size_t size ) +{ + int bytesIn; + int rc; + + rc = PR_CallOnce( &coOpenDevRandom, OpenDevRandom ); + if ( PR_FAILURE == rc ) { + _PR_MD_MAP_OPEN_ERROR( errno ); + return(0); + } + + bytesIn = read( fdDevRandom, buf, size ); + if ( -1 == bytesIn ) { + _PR_MD_MAP_READ_ERROR( errno ); + return(0); + } + + return( bytesIn ); +} /* end GetDevRandom() */ + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return(GetDevRandom( buf, maxbytes )); +} + +#elif defined(NCR) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +#elif defined(IRIX) +#include +#undef PRIVATE +#include +#include +#include +#include +#include + +static size_t GetHighResClock(void *buf, size_t maxbuf) +{ + unsigned phys_addr, raddr, cycleval; + static volatile unsigned *iotimer_addr = NULL; + static int tries = 0; + static int cntr_size; + int mfd; + unsigned s0[2]; + +#ifndef SGI_CYCLECNTR_SIZE +#define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ +#endif + + if (iotimer_addr == NULL) { + if (tries++ > 1) { + /* Don't keep trying if it didn't work */ + return 0; + } + + /* + ** For SGI machines we can use the cycle counter, if it has one, + ** to generate some truly random numbers + */ + phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); + if (phys_addr) { + int pgsz = getpagesize(); + int pgoffmask = pgsz - 1; + + raddr = phys_addr & ~pgoffmask; + mfd = open("/dev/mmem", O_RDONLY); + if (mfd < 0) { + return 0; + } + iotimer_addr = (unsigned *) + mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr); + if (iotimer_addr == (unsigned*)-1) { + close(mfd); + iotimer_addr = NULL; + return 0; + } + iotimer_addr = (unsigned*) + ((__psint_t)iotimer_addr | (phys_addr & pgoffmask)); + /* + * The file 'mfd' is purposefully not closed. + */ + cntr_size = syssgi(SGI_CYCLECNTR_SIZE); + if (cntr_size < 0) { + struct utsname utsinfo; + + /* + * We must be executing on a 6.0 or earlier system, since the + * SGI_CYCLECNTR_SIZE call is not supported. + * + * The only pre-6.1 platforms with 64-bit counters are + * IP19 and IP21 (Challenge, PowerChallenge, Onyx). + */ + uname(&utsinfo); + if (!strncmp(utsinfo.machine, "IP19", 4) || + !strncmp(utsinfo.machine, "IP21", 4)) + cntr_size = 64; + else + cntr_size = 32; + } + cntr_size /= 8; /* Convert from bits to bytes */ + } + } + + s0[0] = *iotimer_addr; + if (cntr_size > 4) + s0[1] = *(iotimer_addr + 1); + memcpy(buf, (char *)&s0[0], cntr_size); + return _pr_CopyLowBits(buf, maxbuf, &s0, cntr_size); +} + +#elif defined(SONY) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +#elif defined(SNI) +#include + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + int ticks; + struct tms buffer; + + ticks=times(&buffer); + return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); +} + +#elif defined(NEC) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} +#elif defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(NTO) \ + || defined(QNX) || defined(DARWIN) || defined(RISCOS) +#include + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + int ticks; + struct tms buffer; + + ticks=times(&buffer); + return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); +} +#else +#error! Platform undefined +#endif /* defined(SOLARIS) */ + +extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) +{ + struct timeval tv; + int n = 0; + int s; + + n += GetHighResClock(buf, size); + size -= n; + + GETTIMEOFDAY(&tv); + + if ( size > 0 ) { + s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec)); + size -= s; + n += s; + } + if ( size > 0 ) { + s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec)); + size -= s; + n += s; + } + + return n; +} /* end _PR_MD_GetRandomNoise() */ diff --git a/nsprpub/pr/src/md/unix/uxshm.c b/nsprpub/pr/src/md/unix/uxshm.c new file mode 100644 index 00000000000..9fc2cd668b8 --- /dev/null +++ b/nsprpub/pr/src/md/unix/uxshm.c @@ -0,0 +1,659 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** uxshm.c -- Unix Implementations NSPR Named Shared Memory +** +** +** lth. Jul-1999. +** +*/ +#include +#include +#include +#include +#include "primpl.h" +#include + +extern PRLogModuleInfo *_pr_shm_lm; + + +#define NSPR_IPC_SHM_KEY 'b' +/* +** Implementation for System V +*/ +#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY +#include +#include +#include +#include + +#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory +#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory +#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory +#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory +#define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory + +extern PRSharedMemory * _MD_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +) +{ + PRStatus rc = PR_SUCCESS; + key_t key; + PRSharedMemory *shm; + char ipcname[PR_IPC_NAME_SIZE]; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name )); + return( NULL ); + } + + shm = PR_NEWZAP( PRSharedMemory ); + if ( NULL == shm ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); + return( NULL ); + } + + shm->ipcname = (char*)PR_MALLOC( strlen( ipcname ) + 1 ); + if ( NULL == shm->ipcname ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); + PR_DELETE( shm ); + return( NULL ); + } + + /* copy args to struct */ + strcpy( shm->ipcname, ipcname ); + shm->size = size; + shm->mode = mode; + shm->flags = flags; + shm->ident = _PR_SHM_IDENT; + + /* create the file first */ + if ( flags & PR_SHM_CREATE ) { + int osfd = open( shm->ipcname, (O_RDWR | O_CREAT), shm->mode ); + if ( -1 == osfd ) { + _PR_MD_MAP_OPEN_ERROR( errno ); + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + return( NULL ); + } + if ( close(osfd) == -1 ) { + _PR_MD_MAP_CLOSE_ERROR( errno ); + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + return( NULL ); + } + } + + /* hash the shm.name to an ID */ + key = ftok( shm->ipcname, NSPR_IPC_SHM_KEY ); + if ( -1 == key ) + { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): ftok() failed on name: %s", shm->ipcname)); + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + return( NULL ); + } + + /* get the shared memory */ + if ( flags & PR_SHM_CREATE ) { + shm->id = shmget( key, shm->size, ( shm->mode | IPC_CREAT|IPC_EXCL)); + if ( shm->id >= 0 ) { + return( shm ); + } + if ((errno == EEXIST) && (flags & PR_SHM_EXCL)) { + PR_SetError( PR_FILE_EXISTS_ERROR, errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): shmget() exclusive failed, errno: %d", errno)); + PR_FREEIF(shm->ipcname); + PR_DELETE(shm); + return(NULL); + } + } + + shm->id = shmget( key, shm->size, shm->mode ); + if ( -1 == shm->id ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): shmget() failed, errno: %d", errno)); + PR_FREEIF(shm->ipcname); + PR_DELETE(shm); + return(NULL); + } + + return( shm ); +} /* end _MD_OpenSharedMemory() */ + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ) +{ + void *addr; + PRUint32 aFlags = shm->mode; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + aFlags |= (flags & PR_SHM_READONLY )? SHM_RDONLY : 0; + + addr = shmat( shm->id, NULL, aFlags ); + if ( (void*)-1 == addr ) + { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_AttachSharedMemory(): shmat() failed on name: %s, OsError: %d", + shm->ipcname, PR_GetOSError() )); + addr = NULL; + } + + return addr; +} + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ) +{ + PRStatus rc = PR_SUCCESS; + PRIntn urc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + urc = shmdt( addr ); + if ( -1 == urc ) + { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DetachSharedMemory(): shmdt() failed on name: %s", shm->ipcname )); + } + + return rc; +} + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ) +{ + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + PR_FREEIF(shm->ipcname); + PR_DELETE(shm); + + return PR_SUCCESS; +} + +extern PRStatus _MD_DeleteSharedMemory( const char *name ) +{ + PRStatus rc = PR_SUCCESS; + key_t key; + int id; + PRIntn urc; + char ipcname[PR_IPC_NAME_SIZE]; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + PR_SetError( PR_UNKNOWN_ERROR , errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name )); + return(PR_FAILURE); + } + + /* create the file first */ + { + int osfd = open( ipcname, (O_RDWR | O_CREAT), 0666 ); + if ( -1 == osfd ) { + _PR_MD_MAP_OPEN_ERROR( errno ); + return( PR_FAILURE ); + } + if ( close(osfd) == -1 ) { + _PR_MD_MAP_CLOSE_ERROR( errno ); + return( PR_FAILURE ); + } + } + + /* hash the shm.name to an ID */ + key = ftok( ipcname, NSPR_IPC_SHM_KEY ); + if ( -1 == key ) + { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): ftok() failed on name: %s", ipcname)); + } + + id = shmget( key, 0, 0 ); + if ( -1 == id ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): shmget() failed, errno: %d", errno)); + return(PR_FAILURE); + } + + urc = shmctl( id, IPC_RMID, NULL ); + if ( -1 == urc ) + { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): shmctl() failed on name: %s", ipcname )); + return(PR_FAILURE); + } + + urc = unlink( ipcname ); + if ( -1 == urc ) { + _PR_MD_MAP_UNLINK_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): unlink() failed: %s", ipcname )); + return(PR_FAILURE); + } + + return rc; +} /* end _MD_DeleteSharedMemory() */ + +/* +** Implementation for Posix +*/ +#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#include + +#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory +#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory +#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory +#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory +#define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory + +struct _MDSharedMemory { + int handle; +}; + +extern PRSharedMemory * _MD_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +) +{ + PRStatus rc = PR_SUCCESS; + PRInt32 end; + PRSharedMemory *shm; + char ipcname[PR_IPC_NAME_SIZE]; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + PR_SetError( PR_UNKNOWN_ERROR , errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name )); + return( NULL ); + } + + shm = PR_NEWZAP( PRSharedMemory ); + if ( NULL == shm ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); + return( NULL ); + } + + shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 ); + if ( NULL == shm->ipcname ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); + return( NULL ); + } + + /* copy args to struct */ + strcpy( shm->ipcname, ipcname ); + shm->size = size; + shm->mode = mode; + shm->flags = flags; + shm->ident = _PR_SHM_IDENT; + + /* + ** Create the shared memory + */ + if ( flags & PR_SHM_CREATE ) { + int oflag = (O_CREAT | O_RDWR); + + if ( flags & PR_SHM_EXCL ) + oflag |= O_EXCL; + shm->id = shm_open( shm->ipcname, oflag, shm->mode ); + } else { + shm->id = shm_open( shm->ipcname, O_RDWR, shm->mode ); + } + + if ( -1 == shm->id ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): shm_open failed: %s, OSError: %d", + shm->ipcname, PR_GetOSError())); + PR_DELETE( shm->ipcname ); + PR_DELETE( shm ); + return(NULL); + } + + end = ftruncate( shm->id, shm->size ); + if ( -1 == end ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): ftruncate failed, OSError: %d", + PR_GetOSError())); + PR_DELETE( shm->ipcname ); + PR_DELETE( shm ); + return(NULL); + } + + return(shm); +} /* end _MD_OpenSharedMemory() */ + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ) +{ + void *addr; + PRIntn prot = (PROT_READ | PROT_WRITE); + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + if ( PR_SHM_READONLY == flags) + prot ^= PROT_WRITE; + + addr = mmap( (void*)0, shm->size, prot, MAP_SHARED, shm->id, 0 ); + if ((void*)-1 == addr ) + { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_AttachSharedMemory(): mmap failed: %s, errno: %d", + shm->ipcname, PR_GetOSError())); + addr = NULL; + } else { + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_AttachSharedMemory(): name: %s, attached at: %p", shm->ipcname, addr)); + } + + return addr; +} + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ) +{ + PRStatus rc = PR_SUCCESS; + PRIntn urc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + urc = munmap( addr, shm->size ); + if ( -1 == urc ) + { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DetachSharedMemory(): munmap failed: %s, errno: %d", + shm->ipcname, PR_GetOSError())); + } + return rc; +} + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ) +{ + int urc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + urc = close( shm->id ); + if ( -1 == urc ) { + _PR_MD_MAP_CLOSE_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_CloseSharedMemory(): close() failed, error: %d", PR_GetOSError())); + return(PR_FAILURE); + } + PR_DELETE( shm->ipcname ); + PR_DELETE( shm ); + return PR_SUCCESS; +} + +extern PRStatus _MD_DeleteSharedMemory( const char *name ) +{ + PRStatus rc = PR_SUCCESS; + PRUintn urc; + char ipcname[PR_IPC_NAME_SIZE]; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + PR_SetError( PR_UNKNOWN_ERROR , errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name )); + return rc; + } + + urc = shm_unlink( ipcname ); + if ( -1 == urc ) { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): shm_unlink failed: %s, errno: %d", + ipcname, PR_GetOSError())); + } else { + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): %s, success", ipcname)); + } + + return rc; +} /* end _MD_DeleteSharedMemory() */ +#endif + + + +/* +** Unix implementation for anonymous memory (file) mapping +*/ +extern PRLogModuleInfo *_pr_shma_lm; + +#include + +extern PRFileMap* _md_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +) +{ + PRFileMap *fm = NULL; + PRFileDesc *fd; + int osfd; + PRIntn urc; + PRIntn mode = 0600; + char *genName; + pid_t pid = getpid(); /* for generating filename */ + PRThread *tid = PR_GetCurrentThread(); /* for generating filename */ + int incr; /* for generating filename */ + const int maxTries = 20; /* maximum # attempts at a unique filename */ + PRInt64 size64; /* 64-bit version of 'size' */ + + /* + ** generate a filename from input and runtime environment + ** open the file, unlink the file. + ** make maxTries number of attempts at uniqueness in the filename + */ + for ( incr = 0; incr < maxTries ; incr++ ) { + genName = PR_smprintf( "%s/.NSPR-AFM-%d-%p.%d", + dirName, (int) pid, tid, incr ); + if ( NULL == genName ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): PR_snprintf(): failed, generating filename")); + goto Finished; + } + + /* create the file */ + osfd = open( genName, (O_CREAT | O_EXCL | O_RDWR), mode ); + if ( -1 == osfd ) { + if ( EEXIST == errno ) { + PR_smprintf_free( genName ); + continue; /* name exists, try again */ + } else { + _PR_MD_MAP_OPEN_ERROR( errno ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): open(): failed, filename: %s, errno: %d", + genName, PR_GetOSError())); + PR_smprintf_free( genName ); + goto Finished; + } + } + break; /* name generation and open successful, break; */ + } /* end for() */ + + if ( incr == maxTries ) { + PR_ASSERT( -1 == osfd ); + PR_ASSERT( EEXIST == errno ); + _PR_MD_MAP_OPEN_ERROR( errno ); + goto Finished; + } + + urc = unlink( genName ); + if ( -1 == urc ) { + _PR_MD_MAP_UNLINK_ERROR( errno ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): failed on unlink(), errno: %d", errno)); + PR_smprintf_free( genName ); + close( osfd ); + goto Finished; + } + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): unlink(): %s", genName )); + + PR_smprintf_free( genName ); + + fd = PR_ImportFile( osfd ); + if ( NULL == fd ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): PR_ImportFile(): failed")); + goto Finished; + } + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): fd: %p", fd )); + + urc = ftruncate( fd->secret->md.osfd, size ); + if ( -1 == urc ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): failed on ftruncate(), errno: %d", errno)); + PR_Close( fd ); + goto Finished; + } + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): ftruncate(): size: %d", size )); + + LL_UI2L(size64, size); /* PRSize (size_t) is unsigned */ + fm = PR_CreateFileMap( fd, size64, prot ); + if ( NULL == fm ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("PR_OpenAnonFileMap(): failed")); + PR_Close( fd ); + goto Finished; + } + fm->md.isAnonFM = PR_TRUE; /* set fd close */ + + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): PR_CreateFileMap(): fm: %p", fm )); + +Finished: + return(fm); +} /* end md_OpenAnonFileMap() */ + +/* +** _md_ExportFileMapAsString() +** +** +*/ +extern PRStatus _md_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufSize, + char *buf +) +{ + PRIntn written; + PRIntn prot = (PRIntn)fm->prot; + + written = PR_snprintf( buf, bufSize, "%ld:%d", + fm->fd->secret->md.osfd, prot ); + + return((written == -1)? PR_FAILURE : PR_SUCCESS); +} /* end _md_ExportFileMapAsString() */ + + +extern PRFileMap * _md_ImportFileMapFromString( + const char *fmstring +) +{ + PRStatus rc; + PRInt32 osfd; + PRIntn prot; /* really: a PRFileMapProtect */ + PRFileDesc *fd; + PRFileMap *fm = NULL; /* default return value */ + PRFileInfo64 info; + + PR_sscanf( fmstring, "%ld:%d", &osfd, &prot ); + + /* import the os file descriptor */ + fd = PR_ImportFile( osfd ); + if ( NULL == fd ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): PR_ImportFile() failed")); + goto Finished; + } + + rc = PR_GetOpenFileInfo64( fd, &info ); + if ( PR_FAILURE == rc ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): PR_GetOpenFileInfo64() failed")); + goto Finished; + } + + fm = PR_CreateFileMap( fd, info.size, (PRFileMapProtect)prot ); + if ( NULL == fm ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): PR_CreateFileMap() failed")); + } + +Finished: + return(fm); +} /* end _md_ImportFileMapFromString() */ diff --git a/nsprpub/pr/src/md/unix/uxwrap.c b/nsprpub/pr/src/md/unix/uxwrap.c new file mode 100644 index 00000000000..ef226a6be19 --- /dev/null +++ b/nsprpub/pr/src/md/unix/uxwrap.c @@ -0,0 +1,548 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + *------------------------------------------------------------------------ + * File: uxwrap.c + * + * Our wrapped versions of the Unix select() and poll() system calls. + * + *------------------------------------------------------------------------ + */ + +#include "primpl.h" + +#if defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(QNX) +/* Do not wrap select() and poll(). */ +#else /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */ +/* The include files for select() */ +#ifdef IRIX +#include +#include +#endif + +#include +#include +#include + +#define ZAP_SET(_to, _width) \ + PR_BEGIN_MACRO \ + memset(_to, 0, \ + ((_width + 8*sizeof(int)-1) / (8*sizeof(int))) \ + * sizeof(int) \ + ); \ + PR_END_MACRO + +/* 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]; + + 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; +} + + +/* + *----------------------------------------------------------------------- + * select() -- + * + * Wrap up the select system call so that we can deschedule + * a thread that tries to wait for i/o. + * + *----------------------------------------------------------------------- + */ + +#if defined(HPUX9) +int select(size_t width, int *rl, int *wl, int *el, const struct timeval *tv) +#elif defined(NEXTSTEP) +int wrap_select(int width, fd_set *rd, fd_set *wr, fd_set *ex, + const struct timeval *tv) +#elif defined(AIX_RENAME_SELECT) +int wrap_select(unsigned long width, void *rl, void *wl, void *el, + struct timeval *tv) +#elif defined(_PR_SELECT_CONST_TIMEVAL) +int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, + const struct timeval *tv) +#else +int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) +#endif +{ + int osfd; + _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; + PRInt32 pdcnt; + PRIntervalTime timeout; + int retVal; +#if defined(HPUX9) || defined(AIX_RENAME_SELECT) + fd_set *rd = (fd_set*) rl; + fd_set *wr = (fd_set*) wl; + fd_set *ex = (fd_set*) el; +#endif + +#if 0 + /* + * Easy special case: zero timeout. Simply call the native + * select() with no fear of blocking. + */ + if (tv != NULL && tv->tv_sec == 0 && tv->tv_usec == 0) { +#if defined(HPUX9) || defined(AIX_RENAME_SELECT) + return _MD_SELECT(width, rl, wl, el, tv); +#else + return _MD_SELECT(width, rd, wr, ex, tv); +#endif + } +#endif + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + +#ifndef _PR_LOCAL_THREADS_ONLY + if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { + return _MD_SELECT(width, rd, wr, ex, tv); + } +#endif + + if (width < 0 || width > FD_SETSIZE) { + 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); + } else { + /* 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; + } + + /* + * Set up for PR_Poll(). The PRPollDesc array is allocated + * dynamically. If this turns out to have high performance + * penalty, one can change to use a large PRPollDesc array + * on the stack, and allocate dynamically only when it turns + * out to be not large enough. + * + * I allocate an array of size 'width', which is the maximum + * number of fds we may need to poll. + */ + unixpds = (_PRUnixPollDesc *) PR_CALLOC(width * sizeof(_PRUnixPollDesc)); + if (!unixpds) { + errno = ENOMEM; + return -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 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, rd) && PR_XIsLocked() + && (!_pr_xt_hack_okayToReleaseXLock + || _pr_xt_hack_okayToReleaseXLock())) { + PR_XUnlock(); + needToLockXAgain = 1; + } + + /* This is the potentially blocking step */ + retVal = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); + + if (needToLockXAgain) { + PR_XLock(); + } + } + + if (retVal > 0) { + /* Compute select results */ + if (rd) ZAP_SET(rd, width); + if (wr) ZAP_SET(wr, width); + if (ex) ZAP_SET(ex, width); + + /* + * The return value can be either the number of ready file + * descriptors or the number of set bits in the three fd_set's. + */ + retVal = 0; /* we're going to recompute */ + 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(unixpds); + + return retVal; +} + +/* + * Redefine poll, when supported on platforms, for local threads + */ + +/* + * I am commenting out the poll() wrapper for Linux for now + * because it is difficult to define _MD_POLL that works on all + * Linux varieties. People reported that glibc 2.0.7 on Debian + * 2.0 Linux machines doesn't have the __syscall_poll symbol + * defined. (WTC 30 Nov. 1998) + */ +#if defined(_PR_POLL_AVAILABLE) && !defined(LINUX) + +/* + *----------------------------------------------------------------------- + * poll() -- + * + * RETURN VALUES: + * -1: fails, errno indicates the error. + * 0: timed out, the revents bitmasks are not set. + * positive value: the number of file descriptors for which poll() + * has set the revents bitmask. + * + *----------------------------------------------------------------------- + */ + +#include + +#if defined(AIX_RENAME_SELECT) +int wrap_poll(void *listptr, unsigned long nfds, long timeout) +#elif (defined(AIX) && !defined(AIX_RENAME_SELECT)) +int poll(void *listptr, unsigned long nfds, long timeout) +#elif defined(OSF1) || (defined(HPUX) && !defined(HPUX9)) +int poll(struct pollfd filedes[], unsigned int nfds, int timeout) +#elif defined(HPUX9) +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[], nfds_t nfds, int timeout) +#elif defined(FREEBSD) +int poll(struct pollfd *filedes, unsigned nfds, int timeout) +#else +int poll(struct pollfd *filedes, unsigned long nfds, int timeout) +#endif +{ +#ifdef AIX + struct pollfd *filedes = (struct pollfd *) listptr; +#endif + struct pollfd *pfd, *epfd; + _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; + PRIntervalTime ticks; + PRInt32 pdcnt; + int ready; + + /* + * Easy special case: zero timeout. Simply call the native + * poll() with no fear of blocking. + */ + if (timeout == 0) { +#if defined(AIX) + return _MD_POLL(listptr, nfds, timeout); +#else + return _MD_POLL(filedes, nfds, timeout); +#endif + } + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + +#ifndef _PR_LOCAL_THREADS_ONLY + if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { + return _MD_POLL(filedes, nfds, timeout); + } +#endif + + /* We do not support the pollmsg structures on AIX */ +#ifdef AIX + PR_ASSERT((nfds & 0xff00) == 0); +#endif + + if (timeout < 0 && timeout != -1) { + errno = EINVAL; + return -1; + } + + /* Convert timeout from miliseconds to ticks */ + if (timeout == -1) { + 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; + } + + unixpds = (_PRUnixPollDesc *) + PR_MALLOC(nfds * sizeof(_PRUnixPollDesc)); + if (NULL == unixpds) { + errno = EAGAIN; + return -1; + } + + 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 + unixpd->in_flags = pfd->events; +#else + /* + * 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 +#endif + )) { + unixpd->in_flags |= _PR_UNIX_POLL_READ; + } + if (pfd->events & (POLLOUT +#ifdef POLLWRNORM + | POLLWRNORM +#endif + )) { + unixpd->in_flags |= _PR_UNIX_POLL_WRITE; + } + if (pfd->events & (POLLPRI +#ifdef POLLRDBAND + | POLLRDBAND +#endif + )) { + unixpd->in_flags |= PR_POLL_EXCEPT; + } +#endif /* _PR_USE_POLL */ + unixpd->out_flags = 0; + unixpd++; + pdcnt++; + } + } + + 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; + } + + /* + * 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 + pfd->revents = unixpd->out_flags; +#else + if (0 != unixpd->out_flags) { + if (unixpd->out_flags & _PR_UNIX_POLL_READ) { + if (pfd->events & POLLIN) { + pfd->revents |= POLLIN; + } +#ifdef POLLRDNORM + if (pfd->events & POLLRDNORM) { + pfd->revents |= POLLRDNORM; + } +#endif + } + if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) { + if (pfd->events & POLLOUT) { + pfd->revents |= POLLOUT; + } +#ifdef POLLWRNORM + if (pfd->events & POLLWRNORM) { + pfd->revents |= POLLWRNORM; + } +#endif + } + if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) { + if (pfd->events & POLLPRI) { + pfd->revents |= POLLPRI; + } +#ifdef POLLRDBAND + if (pfd->events & POLLRDBAND) { + pfd->revents |= POLLRDBAND; + } +#endif + } + 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++; + } + } + +done: + PR_DELETE(unixpds); + return ready; +} + +#endif /* !defined(LINUX) */ + +#endif /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */ + +/* uxwrap.c */ + diff --git a/nsprpub/pr/src/md/windows/.cvsignore b/nsprpub/pr/src/md/windows/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/md/windows/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/md/windows/Makefile.in b/nsprpub/pr/src/md/windows/Makefile.in new file mode 100644 index 00000000000..c97c982121c --- /dev/null +++ b/nsprpub/pr/src/md/windows/Makefile.in @@ -0,0 +1,121 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +CSRCS = \ + w16null.c \ + w16thred.c \ + w16proc.c \ + w16fmem.c \ + w16sock.c \ + w16mem.c \ + w16io.c \ + w16gc.c \ + w16error.c \ + w16stdio.c \ + w16callb.c \ + ntinrval.c \ + $(NULL) +else +ifeq ($(OS_TARGET), WIN95) +CSRCS = \ + ntmisc.c \ + ntsec.c \ + ntsem.c \ + ntinrval.c \ + ntgc.c \ + w95thred.c \ + w95io.c \ + w95cv.c \ + w32rng.c \ + w95sock.c \ + win32_errors.c \ + w32ipcsem.c \ + w32poll.c \ + w32shm.c \ + w95dllmain.c \ + $(NULL) +else +CSRCS = \ + ntdllmn.c \ + ntmisc.c \ + ntsec.c \ + ntsem.c \ + ntinrval.c \ + ntgc.c \ + ntthread.c \ + ntio.c \ + win32_errors.c \ + w32ipcsem.c \ + w32poll.c \ + w32rng.c \ + w32shm.c \ + $(NULL) +endif +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + +# Bug 122433 workaround: disable global optimization (-Og-) on ntio.c. +ifdef BUILD_OPT +ifeq ($(OS_TARGET), WINNT) +ifndef NS_USE_GCC +$(OBJDIR)/ntio.$(OBJ_SUFFIX): ntio.c + @$(MAKE_OBJDIR) + $(CC) -Fo$@ -c $(CFLAGS) -Og- $< +endif +endif +endif diff --git a/nsprpub/pr/src/md/windows/ntdllmn.c b/nsprpub/pr/src/md/windows/ntdllmn.c new file mode 100644 index 00000000000..fa8d25f6f62 --- /dev/null +++ b/nsprpub/pr/src/md/windows/ntdllmn.c @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * 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 +#include + +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: + if (_pr_initialized) { + 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/nsprpub/pr/src/md/windows/ntgc.c b/nsprpub/pr/src/md/windows/ntgc.c new file mode 100644 index 00000000000..e12b30d6c90 --- /dev/null +++ b/nsprpub/pr/src/md/windows/ntgc.c @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * GC related routines + * + */ +#include +#include "primpl.h" + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#if defined(_X86_) + CONTEXT context; + context.ContextFlags = CONTEXT_INTEGER; + + if (_PR_IS_NATIVE_THREAD(t)) { + context.ContextFlags |= CONTEXT_CONTROL; + if (GetThreadContext(t->md.handle, &context)) { + t->md.gcContext[0] = context.Eax; + t->md.gcContext[1] = context.Ebx; + t->md.gcContext[2] = context.Ecx; + t->md.gcContext[3] = context.Edx; + t->md.gcContext[4] = context.Esi; + t->md.gcContext[5] = context.Edi; + t->md.gcContext[6] = context.Esp; + t->md.gcContext[7] = context.Ebp; + *np = PR_NUM_GCREGS; + } else { + PR_ASSERT(0);/* XXX */ + } + } else { + /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * This code is extremely machine dependant and completely + * undocumented by MS. Its only known to work experimentally. + * Ready for a walk on the wild * side? + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ + +#if !defined WIN95 // Win95 does not have fibers + int *fiberData = t->md.fiber_id; + + /* I found these offsets by disassembling SwitchToFiber(). + * Are your palms sweating yet? + */ + + /* + ** EAX is on the stack (ESP+0) + ** EDX is on the stack (ESP+4) + ** ECX is on the stack (ESP+8) + */ + t->md.gcContext[0] = 0; /* context.Eax */ + t->md.gcContext[1] = fiberData[0x2e]; /* context.Ebx */ + t->md.gcContext[2] = 0; /* context.Ecx */ + t->md.gcContext[2] = 0; /* context.Edx */ + t->md.gcContext[4] = fiberData[0x2d]; /* context.Esi */ + t->md.gcContext[5] = fiberData[0x2c]; /* context.Edi */ + t->md.gcContext[6] = fiberData[0x36]; /* context.Esp */ + t->md.gcContext[7] = fiberData[0x32]; /* context.Ebp */ + *np = PR_NUM_GCREGS; +#endif + } + return (PRWord *)&t->md.gcContext; +#else + PR_NOT_REACHED("not implemented"); + return NULL; +#endif /* defined(_X86_) */ +} + +/* This function is not used right now, but is left as a reference. + * If you ever need to get the fiberID from the currently running fiber, + * this is it. + */ +void * +GetMyFiberID() +{ +#if defined(_X86_) && !defined(__MINGW32__) + void *fiberData; + + /* A pointer to our tib entry is found at FS:[18] + * At offset 10h is the fiberData pointer. The context of the + * fiber is stored in there. + */ + __asm { + mov EDX, FS:[18h] + mov EAX, DWORD PTR [EDX+10h] + mov [fiberData], EAX + } + + return fiberData; +#else + PR_NOT_REACHED("not implemented"); + return NULL; +#endif /* defined(_X86_) */ +} diff --git a/nsprpub/pr/src/md/windows/ntinrval.c b/nsprpub/pr/src/md/windows/ntinrval.c new file mode 100644 index 00000000000..b8d858315ea --- /dev/null +++ b/nsprpub/pr/src/md/windows/ntinrval.c @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * NT interval timers + * + */ + +#include "primpl.h" + +void +_PR_MD_INTERVAL_INIT() +{ +} + +PRIntervalTime +_PR_MD_GET_INTERVAL() +{ + return timeGetTime(); /* milliseconds since system start */ +} + +PRIntervalTime +_PR_MD_INTERVAL_PER_SEC() +{ + return 1000; +} diff --git a/nsprpub/pr/src/md/windows/ntio.c b/nsprpub/pr/src/md/windows/ntio.c new file mode 100644 index 00000000000..afa867b358b --- /dev/null +++ b/nsprpub/pr/src/md/windows/ntio.c @@ -0,0 +1,4650 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Masayuki Nakano + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Windows NT IO module + * + * This module handles IO for LOCAL_SCOPE and GLOBAL_SCOPE threads. + * For LOCAL_SCOPE threads, we're using NT fibers. For GLOBAL_SCOPE threads + * we're using NT-native threads. + * + * When doing IO, we want to use completion ports for optimal performance + * with fibers. But if we use completion ports for all IO, it is difficult + * to project a blocking model with GLOBAL_SCOPE threads. To handle this + * we create an extra thread for completing IO for GLOBAL_SCOPE threads. + * We don't really want to complete IO on a separate thread for LOCAL_SCOPE + * threads because it means extra context switches, which are really slow + * on NT... Since we're using a single completion port, some IO will + * be incorrectly completed on the GLOBAL_SCOPE IO thread; this will mean + * extra context switching; but I don't think there is anything I can do + * about it. + */ + +#include "primpl.h" +#include "pprmwait.h" +#include +#include + +static HANDLE _pr_completion_port; +static PRThread *_pr_io_completion_thread; + +#define RECYCLE_SIZE 512 +static struct _MDLock _pr_recycle_lock; +static PRInt32 _pr_recycle_INET_array[RECYCLE_SIZE]; +static PRInt32 _pr_recycle_INET_tail = 0; +static PRInt32 _pr_recycle_INET6_array[RECYCLE_SIZE]; +static PRInt32 _pr_recycle_INET6_tail = 0; + +__declspec(thread) PRThread *_pr_io_restarted_io = NULL; +DWORD _pr_io_restartedIOIndex; /* The thread local storage slot for each + * thread is initialized to NULL. */ + +PRBool _nt_version_gets_lockfile_completion; + +struct _MDLock _pr_ioq_lock; +extern _MDLock _nt_idleLock; +extern PRCList _nt_idleList; +extern PRUint32 _nt_idleCount; + +#define CLOSE_TIMEOUT PR_SecondsToInterval(5) + +/* + * NSPR-to-NT access right mapping table for files. + */ +static DWORD fileAccessTable[] = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE +}; + +/* + * NSPR-to-NT access right mapping table for directories. + */ +static DWORD dirAccessTable[] = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE|FILE_DELETE_CHILD, + FILE_GENERIC_EXECUTE +}; + +/* + * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME. + * We store the value in a PRTime variable for convenience. + * This constant is used by _PR_FileTimeToPRTime(). + */ +#ifdef __GNUC__ +static const PRTime _pr_filetime_offset = 116444736000000000LL; +#else +static const PRTime _pr_filetime_offset = 116444736000000000i64; +#endif + +static PRBool IsPrevCharSlash(const char *str, const char *current); + +#define _NEED_351_FILE_LOCKING_HACK +#ifdef _NEED_351_FILE_LOCKING_HACK +#define _PR_LOCAL_FILE 1 +#define _PR_REMOTE_FILE 2 +PRBool IsFileLocalInit(); +PRInt32 IsFileLocal(HANDLE hFile); +#endif /* _NEED_351_FILE_LOCKING_HACK */ + +static PRInt32 _md_MakeNonblock(HANDLE); + +static PROsfd _nt_nonblock_accept(PRFileDesc *fd, struct sockaddr *addr, int *addrlen, PRIntervalTime); +static PRInt32 _nt_nonblock_connect(PRFileDesc *fd, struct sockaddr *addr, int addrlen, PRIntervalTime); +static PRInt32 _nt_nonblock_recv(PRFileDesc *fd, char *buf, int len, int flags, PRIntervalTime); +static PRInt32 _nt_nonblock_send(PRFileDesc *fd, char *buf, int len, PRIntervalTime); +static PRInt32 _nt_nonblock_writev(PRFileDesc *fd, const PRIOVec *iov, int size, PRIntervalTime); +static PRInt32 _nt_nonblock_sendto(PRFileDesc *, const char *, int, const struct sockaddr *, int, PRIntervalTime); +static PRInt32 _nt_nonblock_recvfrom(PRFileDesc *, char *, int, struct sockaddr *, int *, PRIntervalTime); + +/* + * We cannot associate a fd (a socket) with an I/O completion port + * if the fd is nonblocking or inheritable. + * + * Nonblocking socket I/O won't work if the socket is associated with + * an I/O completion port. + * + * An inheritable fd cannot be associated with an I/O completion port + * because the completion notification of async I/O initiated by the + * child process is still posted to the I/O completion port in the + * parent process. + */ +#define _NT_USE_NB_IO(fd) \ + ((fd)->secret->nonblocking || (fd)->secret->inheritable == _PR_TRI_TRUE) + +/* + * UDP support + * + * UDP is supported on NT by the continuation thread mechanism. + * The code is borrowed from ptio.c in pthreads nspr, hence the + * PT and pt prefixes. This mechanism is in fact general and + * not limited to UDP. For now, only UDP's recvfrom and sendto + * go through the continuation thread if they get WSAEWOULDBLOCK + * on first try. Recv and send on a connected UDP socket still + * goes through asychronous io. + */ + +#define PT_DEFAULT_SELECT_MSEC 100 + +typedef struct pt_Continuation pt_Continuation; +typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revent); + +typedef enum pr_ContuationStatus +{ + pt_continuation_sumbitted, + pt_continuation_inprogress, + pt_continuation_abort, + pt_continuation_done +} pr_ContuationStatus; + +struct pt_Continuation +{ + /* These objects are linked in ascending timeout order */ + pt_Continuation *next, *prev; /* self linked list of these things */ + + /* The building of the continuation operation */ + ContinuationFn function; /* what function to continue */ + union { SOCKET osfd; } arg1; /* #1 - the op's fd */ + union { void* buffer; } arg2; /* #2 - primary transfer buffer */ + union { PRIntn amount; } arg3; /* #3 - size of 'buffer' */ + union { PRIntn flags; } arg4; /* #4 - read/write flags */ + union { PRNetAddr *addr; } arg5; /* #5 - send/recv address */ + + PRIntervalTime timeout; /* representation of the timeout */ + + PRIntn event; /* flags for select()'s events */ + + /* + ** The representation and notification of the results of the operation. + ** These function can either return an int return code or a pointer to + ** some object. + */ + union { PRIntn code; void *object; } result; + + PRIntn syserrno; /* in case it failed, why (errno) */ + pr_ContuationStatus status; /* the status of the operation */ + PRCondVar *complete; /* to notify the initiating thread */ +}; + +static struct pt_TimedQueue +{ + PRLock *ml; /* a little protection */ + PRThread *thread; /* internal thread's identification */ + PRCondVar *new_op; /* new operation supplied */ + PRCondVar *finish_op; /* an existing operation finished */ + PRUintn op_count; /* number of operations in the list */ + pt_Continuation *head, *tail; /* head/tail of list of operations */ + + pt_Continuation *op; /* timed operation furthest in future */ + PRIntervalTime epoch; /* the epoch of 'timed' */ +} pt_tq; + +#if defined(DEBUG) +static struct pt_debug_s +{ + PRIntn predictionsFoiled; + PRIntn pollingListMax; + PRIntn continuationsServed; +} pt_debug; +#endif /* DEBUG */ + +static void ContinuationThread(void *arg); +static PRInt32 pt_SendTo( + SOCKET osfd, const void *buf, + PRInt32 amount, PRInt32 flags, const PRNetAddr *addr, + PRIntn addrlen, PRIntervalTime timeout); +static PRInt32 pt_RecvFrom(SOCKET osfd, void *buf, PRInt32 amount, + PRInt32 flags, PRNetAddr *addr, PRIntn *addr_len, PRIntervalTime timeout); + + +/* The key returned from GetQueuedCompletionStatus() is used to determine what + * type of completion we have. We differentiate between IO completions and + * CVAR completions. + */ +#define KEY_IO 0xaaaaaaaa +#define KEY_CVAR 0xbbbbbbbb + +PRInt32 +_PR_MD_PAUSE_CPU(PRIntervalTime ticks) +{ + int awoken = 0; + unsigned long bytes, key; + int rv; + LPOVERLAPPED olp; + _MDOverlapped *mdOlp; + PRUint32 timeout; + + if (_nt_idleCount > 0) { + PRThread *deadThread; + + _MD_LOCK(&_nt_idleLock); + while( !PR_CLIST_IS_EMPTY(&_nt_idleList) ) { + deadThread = _PR_THREAD_PTR(PR_LIST_HEAD(&_nt_idleList)); + PR_REMOVE_LINK(&deadThread->links); + + PR_ASSERT(deadThread->state == _PR_DEAD_STATE); + + /* XXXMB - cleanup to do here? */ + if ( !_PR_IS_NATIVE_THREAD(deadThread) ){ + /* Spinlock while user thread is still running. + * There is no way to use a condition variable here. The thread + * is dead, and we have to wait until we switch off the dead + * thread before we can kill the fiber completely. + */ + while ( deadThread->no_sched) + ; + + DeleteFiber(deadThread->md.fiber_id); + } + memset(deadThread, 0xa, sizeof(PRThread)); /* debugging */ + if (!deadThread->threadAllocatedOnStack) + PR_DELETE(deadThread); + _nt_idleCount--; + } + _MD_UNLOCK(&_nt_idleLock); + } + + if (ticks == PR_INTERVAL_NO_TIMEOUT) +#if 0 + timeout = INFINITE; +#else + /* + * temporary hack to poll the runq every 5 seconds because of bug in + * native threads creating user threads and not poking the right cpu. + * + * A local thread that was interrupted is bound to its current + * cpu but there is no easy way for the interrupter to poke the + * right cpu. This is a hack to poll the runq every 5 seconds. + */ + timeout = 5000; +#endif + else + timeout = PR_IntervalToMilliseconds(ticks); + + /* + * The idea of looping here is to complete as many IOs as possible before + * returning. This should minimize trips to the idle thread. + */ + while(1) { + rv = GetQueuedCompletionStatus( + _pr_completion_port, + &bytes, + &key, + &olp, + timeout); + if (rv == 0 && olp == NULL) { + /* Error in GetQueuedCompetionStatus */ + if (GetLastError() != WAIT_TIMEOUT) { + /* ARGH - what can we do here? Log an error? XXXMB */ + return -1; + } else { + /* If awoken == 0, then we just had a timeout */ + return awoken; + } + } + + if (olp == NULL) + return 0; + + 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(thred, lockedCPU, pri); + _PR_RUNQ_UNLOCK(lockedCPU); + } else { + /* + * The thread was just interrupted and moved + * from the pause queue to the run queue. + */ + _PR_THREAD_UNLOCK(thred); + } + } else { + _PR_THREAD_LOCK(thred); + thred->state = _PR_RUNNABLE; + _PR_THREAD_UNLOCK(thred); + ReleaseSemaphore(thred->md.blocked_sema, 1, NULL); + } + } + } else { + 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); + PR_ASSERT(completed_io->io_suspended == PR_FALSE); + PR_ASSERT(completed_io->md.thr_bound_cpu == NULL); + + /* 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); + + /* + * If an I/O operation is suspended, the thread + * must be running on the same cpu on which the + * I/O operation was issued. + */ + PR_ASSERT(!completed_io->md.thr_bound_cpu || + (completed_io->cpu == completed_io->md.thr_bound_cpu)); + + if (!completed_io->md.thr_bound_cpu) + completed_io->cpu = lockedCPU; + completed_io->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(completed_io->cpu); + _PR_ADD_RUNQ(completed_io, completed_io->cpu, pri); + _PR_RUNQ_UNLOCK(completed_io->cpu); + } else { + _PR_THREAD_UNLOCK(completed_io); + } + } else { + _PR_THREAD_UNLOCK(completed_io); + } + } + } else { + /* 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; + _PR_THREAD_UNLOCK(completed_io); + rv = ReleaseSemaphore(completed_io->md.blocked_sema, + 1, NULL); + PR_ASSERT(0 != rv); + } else { + _PR_THREAD_UNLOCK(completed_io); + } + } + } + + awoken++; + timeout = 0; /* Don't block on subsequent trips through the loop */ + } + + /* never reached */ + return 0; +} + +static PRStatus +_native_thread_md_wait(PRThread *thread, PRIntervalTime ticks) +{ + DWORD rv; + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(ticks); + + /* + * thread waiting for a cvar or a joining thread + */ + rv = WaitForSingleObject(thread->md.blocked_sema, msecs); + switch(rv) { + case WAIT_OBJECT_0: + return PR_SUCCESS; + break; + case WAIT_TIMEOUT: + _PR_THREAD_LOCK(thread); + PR_ASSERT (thread->state != _PR_IO_WAIT); + if (thread->wait.cvar != NULL) { + PR_ASSERT(thread->state == _PR_COND_WAIT); + thread->wait.cvar = NULL; + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + } else { + /* The CVAR was notified just as the timeout + * occurred. This left the semaphore in the + * signaled state. Call WaitForSingleObject() + * to clear the semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + return PR_SUCCESS; + break; + default: + return PR_FAILURE; + break; + } + + return PR_SUCCESS; +} + +PRStatus +_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + DWORD rv; + + if (_native_threads_only) { + return(_native_thread_md_wait(thread, ticks)); + } + if ( thread->flags & _PR_GLOBAL_SCOPE ) { + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(ticks); + rv = WaitForSingleObject(thread->md.blocked_sema, msecs); + switch(rv) { + case WAIT_OBJECT_0: + return PR_SUCCESS; + break; + case WAIT_TIMEOUT: + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + if (thread->io_pending == PR_TRUE) { + thread->state = _PR_RUNNING; + thread->io_suspended = PR_TRUE; + _PR_THREAD_UNLOCK(thread); + } else { + /* The IO completed just at the same time the timeout + * occurred. This left the semaphore in the signaled + * state. Call WaitForSingleObject() to clear the + * semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + } else { + if (thread->wait.cvar != NULL) { + PR_ASSERT(thread->state == _PR_COND_WAIT); + thread->wait.cvar = NULL; + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + } else { + /* The CVAR was notified just as the timeout + * occurred. This left the semaphore in the + * signaled state. Call WaitForSingleObject() + * to clear the semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + } + return PR_SUCCESS; + break; + default: + return PR_FAILURE; + break; + } + } else { + PRInt32 is; + + _PR_INTSOFF(is); + _PR_MD_SWITCH_CONTEXT(thread); + } + + return PR_SUCCESS; +} + +static void +_native_thread_io_nowait( + PRThread *thread, + int rv, + int bytes) +{ + int rc; + + PR_ASSERT(rv != 0); + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + PR_ASSERT(thread->io_suspended == PR_FALSE); + PR_ASSERT(thread->io_pending == PR_TRUE); + thread->state = _PR_RUNNING; + thread->io_pending = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + } else { + /* The IO completed just at the same time the + * thread was interrupted. This left the semaphore + * in the signaled state. Call WaitForSingleObject() + * to clear the semaphore. + */ + PR_ASSERT(thread->io_suspended == PR_TRUE); + PR_ASSERT(thread->io_pending == PR_TRUE); + thread->io_pending = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + rc = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rc == WAIT_OBJECT_0); + } + + thread->md.blocked_io_status = rv; + thread->md.blocked_io_bytes = bytes; + rc = ResetEvent(thread->md.thr_event); + PR_ASSERT(rc != 0); + return; +} + +static PRStatus +_native_thread_io_wait(PRThread *thread, PRIntervalTime ticks) +{ + DWORD rv, bytes; +#define _NATIVE_IO_WAIT_HANDLES 2 +#define _NATIVE_WAKEUP_EVENT_INDEX 0 +#define _NATIVE_IO_EVENT_INDEX 1 + + HANDLE wait_handles[_NATIVE_IO_WAIT_HANDLES]; + + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(ticks); + + PR_ASSERT(thread->flags & _PR_GLOBAL_SCOPE); + + wait_handles[0] = thread->md.blocked_sema; + wait_handles[1] = thread->md.thr_event; + rv = WaitForMultipleObjects(_NATIVE_IO_WAIT_HANDLES, wait_handles, + FALSE, msecs); + + switch(rv) { + case WAIT_OBJECT_0 + _NATIVE_IO_EVENT_INDEX: + /* + * I/O op completed + */ + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + + PR_ASSERT(thread->io_suspended == PR_FALSE); + PR_ASSERT(thread->io_pending == PR_TRUE); + thread->state = _PR_RUNNING; + thread->io_pending = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + } else { + /* The IO completed just at the same time the + * thread was interrupted. This led to us being + * notified twice. Call WaitForSingleObject() + * to clear the semaphore. + */ + PR_ASSERT(thread->io_suspended == PR_TRUE); + PR_ASSERT(thread->io_pending == PR_TRUE); + thread->io_pending = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, + INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + + rv = GetOverlappedResult((HANDLE) thread->io_fd, + &thread->md.overlapped.overlapped, &bytes, FALSE); + + thread->md.blocked_io_status = rv; + if (rv != 0) { + thread->md.blocked_io_bytes = bytes; + } else { + thread->md.blocked_io_error = GetLastError(); + PR_ASSERT(ERROR_IO_PENDING != thread->md.blocked_io_error); + } + rv = ResetEvent(thread->md.thr_event); + PR_ASSERT(rv != 0); + break; + case WAIT_OBJECT_0 + _NATIVE_WAKEUP_EVENT_INDEX: + /* + * I/O interrupted; + */ +#ifdef DEBUG + _PR_THREAD_LOCK(thread); + PR_ASSERT(thread->io_suspended == PR_TRUE); + _PR_THREAD_UNLOCK(thread); +#endif + break; + case WAIT_TIMEOUT: + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + thread->state = _PR_RUNNING; + thread->io_suspended = PR_TRUE; + _PR_THREAD_UNLOCK(thread); + } else { + /* + * The thread was interrupted just as the timeout + * occurred. This left the semaphore in the signaled + * state. Call WaitForSingleObject() to clear the + * semaphore. + */ + PR_ASSERT(thread->io_suspended == PR_TRUE); + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + break; + default: + return PR_FAILURE; + break; + } + + return PR_SUCCESS; +} + + +static PRStatus +_NT_IO_WAIT(PRThread *thread, PRIntervalTime timeout) +{ + PRBool fWait = PR_TRUE; + + if (_native_threads_only) { + return(_native_thread_io_wait(thread, timeout)); + } + if (!_PR_IS_NATIVE_THREAD(thread)) { + + _PR_THREAD_LOCK(thread); + + /* The IO may have already completed; if so, don't add to sleepQ, + * since we are already on the runQ! + */ + if (thread->io_pending == PR_TRUE) { + _PR_SLEEPQ_LOCK(thread->cpu); + _PR_ADD_SLEEPQ(thread, timeout); + _PR_SLEEPQ_UNLOCK(thread->cpu); + } else + fWait = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + } + if (fWait) + return _PR_MD_WAIT(thread, timeout); + else + return PR_SUCCESS; +} + +/* + * Unblock threads waiting for I/O + * used when interrupting threads + * + * NOTE: The thread lock should held when this function is called. + * On return, the thread lock is released. + */ +void _PR_Unblock_IO_Wait(PRThread *thr) +{ + PRStatus rv; + _PRCPU *cpu = thr->cpu; + + PR_ASSERT(thr->state == _PR_IO_WAIT); + /* + * A thread for which an I/O timed out or was interrupted cannot be + * in an IO_WAIT state except as a result of calling PR_Close or + * PR_NT_CancelIo for the FD. For these two cases, _PR_IO_WAIT state + * is not interruptible + */ + if (thr->md.interrupt_disabled == PR_TRUE) { + _PR_THREAD_UNLOCK(thr); + return; + } + thr->io_suspended = PR_TRUE; + thr->state = _PR_RUNNABLE; + + if (!_PR_IS_NATIVE_THREAD(thr)) { + PRThread *me = _PR_MD_CURRENT_THREAD(); + PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)); + _PR_SLEEPQ_LOCK(cpu); + _PR_DEL_SLEEPQ(thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(cpu); + /* + * this thread will continue to run on the same cpu until the + * I/O is aborted by closing the FD or calling CancelIO + */ + thr->md.thr_bound_cpu = cpu; + + PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD)); + _PR_AddThreadToRunQ(me, thr); + } + _PR_THREAD_UNLOCK(thr); + rv = _PR_MD_WAKEUP_WAITER(thr); + PR_ASSERT(PR_SUCCESS == rv); +} + +/* Resume an outstanding IO; requires that after the switch, we disable */ +static PRStatus +_NT_ResumeIO(PRThread *thread, PRIntervalTime ticks) +{ + PRBool fWait = PR_TRUE; + + if (!_PR_IS_NATIVE_THREAD(thread)) { + 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) + fWait = PR_FALSE; + thread->io_suspended = PR_FALSE; + + _PR_THREAD_UNLOCK(thread); + } + /* We don't put ourselves back on the sleepQ yet; until we + * set the suspended bit to false, we can't do that. Just save + * the sleep time here, and then continue. The restarted_io handler + * will add us to the sleepQ if needed. + */ + thread->sleep = ticks; + + if (fWait) { + if (!_PR_IS_NATIVE_THREAD(thread)) + return _PR_MD_WAIT(thread, ticks); + else + return _NT_IO_WAIT(thread, ticks); + } + return PR_SUCCESS; +} + +PRStatus +_PR_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread == NULL) { + /* If thread is NULL, we aren't waking a thread, we're just poking + * idle thread + */ + if ( PostQueuedCompletionStatus(_pr_completion_port, 0, + KEY_CVAR, NULL) == FALSE) + return PR_FAILURE; + return PR_SUCCESS; + } + + if ( _PR_IS_NATIVE_THREAD(thread) ) { + if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE) + return PR_FAILURE; + else + return PR_SUCCESS; + } else { + PRThread *me = _PR_MD_CURRENT_THREAD(); + + /* When a Native thread has to awaken a user thread, it has to poke + * the completion port because all user threads might be idle, and + * thus the CPUs are just waiting for a completion. + * + * XXXMB - can we know when we are truely idle (and not checking + * the runq)? + */ + if ((_PR_IS_NATIVE_THREAD(me) || (thread->cpu != me->cpu)) && + (!thread->md.thr_bound_cpu)) { + /* The thread should not be in any queue */ + PR_ASSERT(thread->queueCount == 0); + if ( PostQueuedCompletionStatus(_pr_completion_port, 0, + KEY_CVAR, &(thread->md.overlapped.overlapped)) == FALSE) + return PR_FAILURE; + } + return PR_SUCCESS; + } +} + +void +_PR_MD_INIT_IO() +{ + WORD WSAVersion = 0x0101; + WSADATA WSAData; + int err; + OSVERSIONINFO OSversion; + + err = WSAStartup( WSAVersion, &WSAData ); + PR_ASSERT(0 == err); + + _pr_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, + NULL, + 0, + 0); + + _MD_NEW_LOCK(&_pr_recycle_lock); + _MD_NEW_LOCK(&_pr_ioq_lock); + + OSversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx(&OSversion)) { + _nt_version_gets_lockfile_completion = PR_FALSE; + if (OSversion.dwMajorVersion >= 4) { + _nt_version_gets_lockfile_completion = PR_TRUE; + } + } else + PR_ASSERT(0); + +#ifdef _NEED_351_FILE_LOCKING_HACK + IsFileLocalInit(); +#endif /* _NEED_351_FILE_LOCKING_HACK */ + + /* + * UDP support: start up the continuation thread + */ + + pt_tq.op_count = 0; + pt_tq.head = pt_tq.tail = NULL; + pt_tq.ml = PR_NewLock(); + PR_ASSERT(NULL != pt_tq.ml); + pt_tq.new_op = PR_NewCondVar(pt_tq.ml); + PR_ASSERT(NULL != pt_tq.new_op); +#if defined(DEBUG) + memset(&pt_debug, 0, sizeof(struct pt_debug_s)); +#endif + + pt_tq.thread = PR_CreateThread( + PR_SYSTEM_THREAD, ContinuationThread, NULL, + PR_PRIORITY_URGENT, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + + PR_ASSERT(NULL != pt_tq.thread); + +#ifdef DEBUG + /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */ + { + SYSTEMTIME systime; + union { + PRTime prt; + FILETIME ft; + } filetime; + BOOL rv; + + systime.wYear = 1970; + systime.wMonth = 1; + /* wDayOfWeek is ignored */ + systime.wDay = 1; + systime.wHour = 0; + systime.wMinute = 0; + systime.wSecond = 0; + systime.wMilliseconds = 0; + + rv = SystemTimeToFileTime(&systime, &filetime.ft); + PR_ASSERT(0 != rv); + PR_ASSERT(filetime.prt == _pr_filetime_offset); + } +#endif /* DEBUG */ + + _PR_NT_InitSids(); +} + +/* --- SOCKET IO --------------------------------------------------------- */ + +/* _md_get_recycled_socket() + * Get a socket from the recycle bin; if no sockets are in the bin, + * create one. The socket will be passed to AcceptEx() as the + * second argument. + */ +static SOCKET +_md_get_recycled_socket(int af) +{ + SOCKET rv; + + _MD_LOCK(&_pr_recycle_lock); + if (af == AF_INET && _pr_recycle_INET_tail) { + _pr_recycle_INET_tail--; + rv = _pr_recycle_INET_array[_pr_recycle_INET_tail]; + _MD_UNLOCK(&_pr_recycle_lock); + return rv; + } + if (af == AF_INET6 && _pr_recycle_INET6_tail) { + _pr_recycle_INET6_tail--; + rv = _pr_recycle_INET6_array[_pr_recycle_INET6_tail]; + _MD_UNLOCK(&_pr_recycle_lock); + return rv; + } + _MD_UNLOCK(&_pr_recycle_lock); + + rv = _PR_MD_SOCKET(af, SOCK_STREAM, 0); + if (rv != INVALID_SOCKET && _md_Associate((HANDLE)rv) == 0) { + closesocket(rv); + return INVALID_SOCKET; + } + return rv; +} + +/* _md_put_recycled_socket() + * Add a socket to the recycle bin. + */ +static void +_md_put_recycled_socket(SOCKET newsock, int af) +{ + PR_ASSERT(_pr_recycle_INET_tail >= 0); + PR_ASSERT(_pr_recycle_INET6_tail >= 0); + + _MD_LOCK(&_pr_recycle_lock); + if (af == AF_INET && _pr_recycle_INET_tail < RECYCLE_SIZE) { + _pr_recycle_INET_array[_pr_recycle_INET_tail] = newsock; + _pr_recycle_INET_tail++; + _MD_UNLOCK(&_pr_recycle_lock); + } else if (af == AF_INET6 && _pr_recycle_INET6_tail < RECYCLE_SIZE) { + _pr_recycle_INET6_array[_pr_recycle_INET6_tail] = newsock; + _pr_recycle_INET6_tail++; + _MD_UNLOCK(&_pr_recycle_lock); + } else { + _MD_UNLOCK(&_pr_recycle_lock); + closesocket(newsock); + } + + return; +} + +/* _md_Associate() + * Associates a file with the completion port. + * Returns 0 on failure, 1 on success. + */ +PRInt32 +_md_Associate(HANDLE file) +{ + HANDLE port; + + if (!_native_threads_only) { + port = CreateIoCompletionPort((HANDLE)file, + _pr_completion_port, + KEY_IO, + 0); + + /* XXX should map error codes on failures */ + return (port == _pr_completion_port); + } else { + return 1; + } +} + +/* + * _md_MakeNonblock() + * Make a socket nonblocking. + * Returns 0 on failure, 1 on success. + */ +static PRInt32 +_md_MakeNonblock(HANDLE file) +{ + int rv; + u_long one = 1; + + rv = ioctlsocket((SOCKET)file, FIONBIO, &one); + /* XXX should map error codes on failures */ + return (rv == 0); +} + +static int missing_completions = 0; +static int max_wait_loops = 0; + +static PRInt32 +_NT_IO_ABORT(PROsfd sock) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRBool fWait; + PRInt32 rv; + int loop_count; + + /* This is a clumsy way to abort the IO, but it is all we can do. + * It looks a bit racy, but we handle all the cases. + * case 1: IO completes before calling closesocket + * case 1a: fWait is set to PR_FALSE + * This should e the most likely case. We'll properly + * not wait call _NT_IO_WAIT, since the closesocket() + * won't be forcing a completion. + * case 1b: fWait is set to PR_TRUE + * This hopefully won't happen much. When it does, this + * thread will timeout in _NT_IO_WAIT for CLOSE_INTERVAL + * before cleaning up. + * case 2: IO does not complete before calling closesocket + * case 2a: IO never completes + * This is the likely case. We'll close it and wait + * for the completion forced by the close. Return should + * be immediate. + * case 2b: IO completes just after calling closesocket + * Since the closesocket is issued, we'll either get a + * completion back for the real IO or for the close. We + * don't really care. It may not even be possible to get + * a real completion here. In any event, we'll awaken + * from NT_IO_WAIT immediately. + */ + + _PR_THREAD_LOCK(me); + fWait = me->io_pending; + if (fWait) { + /* + * If there's still I/O pending, it should have already timed + * out once before this function is called. + */ + PR_ASSERT(me->io_suspended == PR_TRUE); + + /* Set up to wait for I/O completion again */ + me->state = _PR_IO_WAIT; + me->io_suspended = PR_FALSE; + me->md.interrupt_disabled = PR_TRUE; + } + _PR_THREAD_UNLOCK(me); + + /* Close the socket if there is one */ + if (sock != INVALID_SOCKET) { + rv = closesocket((SOCKET)sock); + } + + /* If there was I/O pending before the close, wait for it to complete */ + if (fWait) { + + /* Wait and wait for the I/O to complete */ + for (loop_count = 0; fWait; ++loop_count) { + + _NT_IO_WAIT(me, CLOSE_TIMEOUT); + + _PR_THREAD_LOCK(me); + fWait = me->io_pending; + if (fWait) { + PR_ASSERT(me->io_suspended == PR_TRUE); + me->state = _PR_IO_WAIT; + me->io_suspended = PR_FALSE; + } + _PR_THREAD_UNLOCK(me); + + if (loop_count > max_wait_loops) { + max_wait_loops = loop_count; + } + } + + if (loop_count > 1) { + ++missing_completions; + } + + me->md.interrupt_disabled = PR_FALSE; + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + } + + PR_ASSERT(me->io_pending == PR_FALSE); + me->md.thr_bound_cpu = NULL; + me->io_suspended = PR_FALSE; + + return rv; +} + + +PROsfd +_PR_MD_SOCKET(int af, int type, int flags) +{ + SOCKET sock; + + sock = socket(af, type, flags); + + if (sock == INVALID_SOCKET) { + _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError()); + } + + return (PROsfd)sock; +} + +struct connect_data_s { + PRInt32 status; + PRInt32 error; + PROsfd osfd; + struct sockaddr *addr; + PRUint32 addrlen; + PRIntervalTime timeout; +}; + +void +_PR_MD_connect_thread(void *cdata) +{ + struct connect_data_s *cd = (struct connect_data_s *)cdata; + + cd->status = connect(cd->osfd, cd->addr, cd->addrlen); + + if (cd->status == SOCKET_ERROR) + cd->error = WSAGetLastError(); + + return; +} + + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + u_long nbio; + PRInt32 rc; + + if (fd->secret->nonblocking) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + + if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) { + err = WSAGetLastError(); + _PR_MD_MAP_CONNECT_ERROR(err); + } + return rv; + } + + /* + * Temporarily make the socket non-blocking so that we can + * initiate a non-blocking connect and wait for its completion + * (with a timeout) in select. + */ + PR_ASSERT(!fd->secret->md.io_model_committed); + nbio = 1; + rv = ioctlsocket((SOCKET)osfd, FIONBIO, &nbio); + PR_ASSERT(0 == rv); + + rc = _nt_nonblock_connect(fd, (struct sockaddr *) addr, addrlen, timeout); + + /* Set the socket back to blocking. */ + nbio = 0; + rv = ioctlsocket((SOCKET)osfd, FIONBIO, &nbio); + PR_ASSERT(0 == rv); + + return rc; +} + +PRInt32 +_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv; +#if 0 + int one = 1; +#endif + + rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen); + + if (rv == SOCKET_ERROR) { + _PR_MD_MAP_BIND_ERROR(WSAGetLastError()); + return -1; + } + +#if 0 + /* Disable nagle- so far unknown if this is good or not... + */ + rv = setsockopt(fd->secret->md.osfd, + SOL_SOCKET, + TCP_NODELAY, + (const char *)&one, + sizeof(one)); + PR_ASSERT(rv == 0); +#endif + + return 0; +} + +void _PR_MD_UPDATE_ACCEPT_CONTEXT(PROsfd accept_sock, PROsfd listen_sock) +{ + /* Sockets accept()'d with AcceptEx need to call this setsockopt before + * calling anything other than ReadFile(), WriteFile(), send(), recv(), + * Transmitfile(), and closesocket(). In order to call any other + * winsock functions, we have to make this setsockopt call. + * + * XXXMB - For the server, we *NEVER* need this in + * the "normal" code path. But now we have to call it. This is a waste + * of a system call. We'd like to only call it before calling the + * obscure socket calls, but since we don't know at that point what the + * original socket was (or even if it is still alive) we can't do it + * at that point... + */ + setsockopt((SOCKET)accept_sock, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (char *)&listen_sock, + sizeof(listen_sock)); + +} + +#define INET_ADDR_PADDED (sizeof(PRNetAddr) + 16) +PROsfd +_PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, + PRIntervalTime timeout, PRBool fast, + _PR_AcceptTimeoutCallback callback, void *callbackArg) +{ + PROsfd osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + SOCKET accept_sock; + int bytes; + PRNetAddr *Laddr; + PRNetAddr *Raddr; + PRUint32 llen, err; + int rv; + + if (_NT_USE_NB_IO(fd)) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + /* + * The accepted socket inherits the nonblocking and + * inheritable (HANDLE_FLAG_INHERIT) attributes of + * the listening socket. + */ + accept_sock = _nt_nonblock_accept(fd, (struct sockaddr *)raddr, rlen, timeout); + if (!fd->secret->nonblocking) { + u_long zero = 0; + + rv = ioctlsocket(accept_sock, FIONBIO, &zero); + PR_ASSERT(0 == rv); + } + return accept_sock; + } + + 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; + } + + if (!me->md.acceptex_buf) { + me->md.acceptex_buf = PR_MALLOC(2*INET_ADDR_PADDED); + if (!me->md.acceptex_buf) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + } + + accept_sock = _md_get_recycled_socket(fd->secret->af); + if (accept_sock == INVALID_SOCKET) + return -1; + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + closesocket(accept_sock); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = osfd; + + rv = AcceptEx((SOCKET)osfd, + accept_sock, + me->md.acceptex_buf, + 0, + INET_ADDR_PADDED, + INET_ADDR_PADDED, + &bytes, + &(me->md.overlapped.overlapped)); + + if ( (rv == 0) && ((err = WSAGetLastError()) != ERROR_IO_PENDING)) { + /* Argh! The IO failed */ + closesocket(accept_sock); + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_ACCEPTEX_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + closesocket(accept_sock); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + closesocket(accept_sock); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + closesocket(accept_sock); + _PR_MD_MAP_ACCEPTEX_ERROR(me->md.blocked_io_error); + return -1; + } + + if (!fast) + _PR_MD_UPDATE_ACCEPT_CONTEXT((SOCKET)accept_sock, (SOCKET)osfd); + + /* IO is done */ + GetAcceptExSockaddrs( + me->md.acceptex_buf, + 0, + INET_ADDR_PADDED, + INET_ADDR_PADDED, + (LPSOCKADDR *)&(Laddr), + &llen, + (LPSOCKADDR *)&(Raddr), + (unsigned int *)rlen); + + if (raddr != NULL) + memcpy((char *)raddr, (char *)&Raddr->inet, *rlen); + + PR_ASSERT(me->io_pending == PR_FALSE); + + return accept_sock; +} + +PRInt32 +_PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PROsfd *newSock, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout, + PRBool fast, _PR_AcceptTimeoutCallback callback, + void *callbackArg) +{ + PROsfd sock = sd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + int bytes; + PRNetAddr *Laddr; + PRUint32 llen, rlen, err; + int rv; + PRBool isConnected; + PRBool madeCallback = PR_FALSE; + + 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); + sd->secret->md.io_model_committed = PR_TRUE; + } + + *newSock = _md_get_recycled_socket(sd->secret->af); + if (*newSock == INVALID_SOCKET) + return -1; + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + closesocket(*newSock); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = sock; + + rv = AcceptEx((SOCKET)sock, + *newSock, + buf, + amount, + INET_ADDR_PADDED, + INET_ADDR_PADDED, + &bytes, + &(me->md.overlapped.overlapped)); + + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) { + closesocket(*newSock); + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_ACCEPTEX_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + closesocket(*newSock); + return -1; + } + +retry: + if (me->io_suspended) { + PRInt32 err; + INT seconds; + INT bytes = sizeof(seconds); + + PR_ASSERT(timeout != PR_INTERVAL_NO_TIMEOUT); + + err = getsockopt(*newSock, + SOL_SOCKET, + SO_CONNECT_TIME, + (char *)&seconds, + (PINT)&bytes); + if ( err == NO_ERROR ) { + PRIntervalTime elapsed = PR_SecondsToInterval(seconds); + + if (seconds == 0xffffffff) + isConnected = PR_FALSE; + else + isConnected = PR_TRUE; + + if (!isConnected) { + if (madeCallback == PR_FALSE && callback) + callback(callbackArg); + madeCallback = PR_TRUE; + me->state = _PR_IO_WAIT; + if (_NT_ResumeIO(me, timeout) == PR_FAILURE) { + closesocket(*newSock); + return -1; + } + goto retry; + } + + if (elapsed < timeout) { + /* Socket is connected but time not elapsed, RESUME IO */ + timeout -= elapsed; + me->state = _PR_IO_WAIT; + if (_NT_ResumeIO(me, timeout) == PR_FAILURE) { + closesocket(*newSock); + return -1; + } + goto retry; + } + } else { + /* What to do here? Assume socket not open?*/ + PR_ASSERT(0); + isConnected = PR_FALSE; + } + + rv = _NT_IO_ABORT(*newSock); + + PR_ASSERT(me->io_pending == PR_FALSE); + PR_ASSERT(me->io_suspended == PR_FALSE); + PR_ASSERT(me->md.thr_bound_cpu == NULL); + /* If the IO is still suspended, it means we didn't get any + * completion from NT_IO_WAIT. This is not disasterous, I hope, + * but it may mean we still have an IO outstanding... Try to + * recover by just allowing ourselves to continue. + */ + me->io_suspended = PR_FALSE; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + me->state = _PR_RUNNING; + closesocket(*newSock); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE); + PR_ASSERT(me->io_suspended == PR_FALSE); + PR_ASSERT(me->md.thr_bound_cpu == NULL); + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_ACCEPTEX_ERROR(me->md.blocked_io_error); + closesocket(*newSock); + return -1; + } + + if (!fast) + _PR_MD_UPDATE_ACCEPT_CONTEXT((SOCKET)*newSock, (SOCKET)sock); + + /* IO is done */ + GetAcceptExSockaddrs( + buf, + amount, + INET_ADDR_PADDED, + INET_ADDR_PADDED, + (LPSOCKADDR *)&(Laddr), + &llen, + (LPSOCKADDR *)(raddr), + (unsigned int *)&rlen); + + return me->md.blocked_io_bytes; +} + +PRInt32 +_PR_MD_SENDFILE(PRFileDesc *sock, PRSendFileData *sfd, + PRInt32 flags, PRIntervalTime timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 tflags; + int rv, err; + + 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); + sock->secret->md.io_model_committed = PR_TRUE; + } + if (!me->md.xmit_bufs) { + me->md.xmit_bufs = PR_NEW(TRANSMIT_FILE_BUFFERS); + if (!me->md.xmit_bufs) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + } + me->md.xmit_bufs->Head = (void *)sfd->header; + me->md.xmit_bufs->HeadLength = sfd->hlen; + me->md.xmit_bufs->Tail = (void *)sfd->trailer; + me->md.xmit_bufs->TailLength = sfd->tlen; + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + me->md.overlapped.overlapped.Offset = sfd->file_offset; + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + tflags = 0; + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) + tflags = TF_DISCONNECT | TF_REUSE_SOCKET; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = sock->secret->md.osfd; + + rv = TransmitFile((SOCKET)sock->secret->md.osfd, + (HANDLE)sfd->fd->secret->md.osfd, + (DWORD)sfd->file_nbytes, + (DWORD)0, + (LPOVERLAPPED)&(me->md.overlapped.overlapped), + (TRANSMIT_FILE_BUFFERS *)me->md.xmit_bufs, + (DWORD)tflags); + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_TRANSMITFILE_ERROR(err); + return -1; + } + + if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_TRANSMITFILE_ERROR(me->md.blocked_io_error); + return -1; + } + + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + _md_put_recycled_socket(sock->secret->md.osfd, sock->secret->af); + } + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; +} + +PRInt32 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + int bytes; + int rv, err; + + if (_NT_USE_NB_IO(fd)) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + return _nt_nonblock_recv(fd, buf, amount, flags, 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.overlapped), 0, sizeof(OVERLAPPED)); + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = osfd; + + rv = ReadFile((HANDLE)osfd, + buf, + amount, + &bytes, + &(me->md.overlapped.overlapped)); + if ( (rv == 0) && (GetLastError() != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + if ((err = GetLastError()) == ERROR_HANDLE_EOF) + return 0; + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + if (me->md.blocked_io_error == ERROR_HANDLE_EOF) + return 0; + _PR_MD_MAP_READ_ERROR(me->md.blocked_io_error); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + int bytes; + int rv, err; + + if (_NT_USE_NB_IO(fd)) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + 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.overlapped), 0, sizeof(OVERLAPPED)); + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = osfd; + + rv = WriteFile((HANDLE)osfd, + buf, + amount, + &bytes, + &(me->md.overlapped.overlapped)); + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_WRITE_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_WRITE_ERROR(me->md.blocked_io_error); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; +} + +PRInt32 +_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv; + + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + if (_NT_USE_NB_IO(fd)) + return _nt_nonblock_sendto(fd, buf, amount, (struct sockaddr *)addr, addrlen, timeout); + else + return pt_SendTo(osfd, buf, amount, flags, addr, addrlen, timeout); +} + +PRInt32 +_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv; + + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + if (_NT_USE_NB_IO(fd)) + return _nt_nonblock_recvfrom(fd, buf, amount, (struct sockaddr *)addr, addrlen, timeout); + else + return pt_RecvFrom(osfd, buf, amount, flags, addr, addrlen, timeout); +} + +/* XXXMB - for now this is a sockets call only */ +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + int index; + int sent = 0; + int rv; + + if (_NT_USE_NB_IO(fd)) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + return _nt_nonblock_writev(fd, iov, iov_size, timeout); + } + + for (index=0; index 0) + sent += rv; + if ( rv != iov[index].iov_len ) { + if (sent <= 0) + return -1; + return -1; + } + } + + return sent; +} + +PRInt32 +_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv; + + rv = listen(fd->secret->md.osfd, backlog); + if (rv < 0) + _PR_MD_MAP_LISTEN_ERROR(WSAGetLastError()); + return(rv); +} + +PRInt32 +_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); +} + +PRStatus +_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; + } +} + +PRStatus +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + /* + * NT has a bug that, when invoked on a socket accepted by + * AcceptEx(), getpeername() returns an all-zero peer address. + * To work around this bug, we store the peer's address (returned + * by AcceptEx()) with the socket fd and use the cached peer + * address if the socket is an accepted socket. + */ + + if (fd->secret->md.accepted_socket) { + INT seconds; + INT bytes = sizeof(seconds); + + /* + * Determine if the socket is connected. + */ + + rv = getsockopt(fd->secret->md.osfd, + SOL_SOCKET, + SO_CONNECT_TIME, + (char *) &seconds, + (PINT) &bytes); + if (rv == NO_ERROR) { + if (seconds == 0xffffffff) { + PR_SetError(PR_NOT_CONNECTED_ERROR, 0); + return PR_FAILURE; + } + *len = PR_NETADDR_SIZE(&fd->secret->md.peer_addr); + memcpy(addr, &fd->secret->md.peer_addr, *len); + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } + } else { + 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; + } + } +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +{ + 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; + } +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +{ + 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; + } +} + +/* --- FILE IO ----------------------------------------------------------- */ + +PROsfd +_PR_MD_OPEN(const char *name, PRIntn osflags, PRIntn mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) + flags = (0 != (osflags & PR_TRUNCATE)) ? CREATE_ALWAYS : OPEN_ALWAYS; + else if (osflags & PR_TRUNCATE) flags = TRUNCATE_EXISTING; + else flags = OPEN_EXISTING; + + + flag6 |= FILE_FLAG_OVERLAPPED; + + file = CreateFile(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + flags, + flag6, + NULL); + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + if (osflags & PR_APPEND) { + if ( SetFilePointer(file, 0, 0, FILE_END) == 0xFFFFFFFF ) { + _PR_MD_MAP_LSEEK_ERROR(GetLastError()); + CloseHandle(file); + return -1; + } + } + + return (PROsfd)file; +} + +PROsfd +_PR_MD_OPEN_FILE(const char *name, PRIntn osflags, PRIntn mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) + flags = (0 != (osflags & PR_TRUNCATE)) ? CREATE_ALWAYS : OPEN_ALWAYS; + else if (osflags & PR_TRUNCATE) flags = TRUNCATE_EXISTING; + else flags = OPEN_EXISTING; + + + flag6 |= FILE_FLAG_OVERLAPPED; + + if (osflags & PR_CREATE_FILE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + } + file = CreateFile(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + lpSA, + flags, + flag6, + NULL); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + if (osflags & PR_APPEND) { + if ( SetFilePointer(file, 0, 0, FILE_END) == 0xFFFFFFFF ) { + _PR_MD_MAP_LSEEK_ERROR(GetLastError()); + CloseHandle(file); + return -1; + } + } + + return (PROsfd)file; +} + +PRInt32 +_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) +{ + PROsfd f = fd->secret->md.osfd; + PRUint32 bytes; + int rv, err; + LONG hiOffset = 0; + LONG loOffset; + + if (!fd->secret->md.sync_file_io) { + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, &me->md.overlapped.overlapped.OffsetHigh, FILE_CURRENT); + PR_ASSERT((me->md.overlapped.overlapped.Offset != 0xffffffff) || (GetLastError() == NO_ERROR)); + + if (fd->secret->inheritable == _PR_TRI_TRUE) { + rv = ReadFile((HANDLE)f, + (LPVOID)buf, + len, + &bytes, + &me->md.overlapped.overlapped); + if (rv != 0) { + loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT); + PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR)); + return bytes; + } + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + rv = GetOverlappedResult((HANDLE)f, + &me->md.overlapped.overlapped, &bytes, TRUE); + if (rv != 0) { + loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT); + PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR)); + return bytes; + } + err = GetLastError(); + } + if (err == ERROR_HANDLE_EOF) { + return 0; + } else { + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + } else { + if (!fd->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)f); + PR_ASSERT(rv != 0); + fd->secret->md.io_model_committed = PR_TRUE; + } + + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = f; + + rv = ReadFile((HANDLE)f, + (LPVOID)buf, + len, + &bytes, + &me->md.overlapped.overlapped); + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + if (err == ERROR_HANDLE_EOF) { + return 0; + } + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + if (me->md.blocked_io_error == ERROR_HANDLE_EOF) { + return 0; + } + _PR_MD_MAP_READ_ERROR(me->md.blocked_io_error); + return -1; + } + + SetFilePointer((HANDLE)f, me->md.blocked_io_bytes, 0, FILE_CURRENT); + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; + } + } else { + + rv = ReadFile((HANDLE)f, + (LPVOID)buf, + len, + &bytes, + NULL); + if (rv == 0) { + err = GetLastError(); + /* ERROR_HANDLE_EOF can only be returned by async io */ + PR_ASSERT(err != ERROR_HANDLE_EOF); + if (err == ERROR_BROKEN_PIPE) { + /* The write end of the pipe has been closed. */ + return 0; + } + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + return bytes; + } +} + +PRInt32 +_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) +{ + PROsfd f = fd->secret->md.osfd; + PRInt32 bytes; + int rv, err; + LONG hiOffset = 0; + LONG loOffset; + LARGE_INTEGER offset; /* use for the calculation of the new offset */ + + if (!fd->secret->md.sync_file_io) { + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, &me->md.overlapped.overlapped.OffsetHigh, FILE_CURRENT); + PR_ASSERT((me->md.overlapped.overlapped.Offset != 0xffffffff) || (GetLastError() == NO_ERROR)); + + if (fd->secret->inheritable == _PR_TRI_TRUE) { + rv = WriteFile((HANDLE)f, + (LPVOID)buf, + len, + &bytes, + &me->md.overlapped.overlapped); + if (rv != 0) { + loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT); + PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR)); + return bytes; + } + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + rv = GetOverlappedResult((HANDLE)f, + &me->md.overlapped.overlapped, &bytes, TRUE); + if (rv != 0) { + loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT); + PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR)); + return bytes; + } + err = GetLastError(); + } + _PR_MD_MAP_READ_ERROR(err); + return -1; + } else { + if (!fd->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)f); + PR_ASSERT(rv != 0); + fd->secret->md.io_model_committed = PR_TRUE; + } + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = f; + + rv = WriteFile((HANDLE)f, + buf, + len, + &bytes, + &(me->md.overlapped.overlapped)); + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_WRITE_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_WRITE_ERROR(me->md.blocked_io_error); + return -1; + } + + /* + * Moving the file pointer by a relative offset (FILE_CURRENT) + * does not work with a file on a network drive exported by a + * Win2K system. We still don't know why. A workaround is to + * move the file pointer by an absolute offset (FILE_BEGIN). + * (Bugzilla bug 70765) + */ + offset.LowPart = me->md.overlapped.overlapped.Offset; + offset.HighPart = me->md.overlapped.overlapped.OffsetHigh; + offset.QuadPart += me->md.blocked_io_bytes; + + SetFilePointer((HANDLE)f, offset.LowPart, &offset.HighPart, FILE_BEGIN); + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; + } + } else { + rv = WriteFile((HANDLE)f, + buf, + len, + &bytes, + NULL); + if (rv == 0) { + _PR_MD_MAP_WRITE_ERROR(GetLastError()); + return -1; + } + return bytes; + } +} + +PRInt32 +_PR_MD_SOCKETAVAILABLE(PRFileDesc *fd) +{ + PRInt32 result; + + if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError()); + return -1; + } + return result; +} + +PRInt32 +_PR_MD_PIPEAVAILABLE(PRFileDesc *fd) +{ + if (NULL == fd) + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +PROffset32 +_PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) +{ + DWORD moveMethod; + PROffset32 rv; + + switch (whence) { + case PR_SEEK_SET: + moveMethod = FILE_BEGIN; + break; + case PR_SEEK_CUR: + moveMethod = FILE_CURRENT; + break; + case PR_SEEK_END: + moveMethod = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod); + + /* + * If the lpDistanceToMoveHigh argument (third argument) is + * NULL, SetFilePointer returns 0xffffffff on failure. + */ + if (-1 == rv) { + _PR_MD_MAP_LSEEK_ERROR(GetLastError()); + } + return rv; +} + +PROffset64 +_PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) +{ + DWORD moveMethod; + LARGE_INTEGER li; + DWORD err; + + switch (whence) { + case PR_SEEK_SET: + moveMethod = FILE_BEGIN; + break; + case PR_SEEK_CUR: + moveMethod = FILE_CURRENT; + break; + case PR_SEEK_END: + moveMethod = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + li.QuadPart = offset; + li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd, + li.LowPart, &li.HighPart, moveMethod); + + if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(err); + li.QuadPart = -1; + } + return li.QuadPart; +} + +/* + * This is documented to succeed on read-only files, but Win32's + * FlushFileBuffers functions fails with "access denied" in such a + * case. So we only signal an error if the error is *not* "access + * denied". + */ +PRInt32 +_PR_MD_FSYNC(PRFileDesc *fd) +{ + /* + * From the documentation: + * + * On Windows NT, the function FlushFileBuffers fails if hFile + * is a handle to console output. That is because console + * output is not buffered. The function returns FALSE, and + * GetLastError returns ERROR_INVALID_HANDLE. + * + * On the other hand, on Win95, it returns without error. I cannot + * assume that 0, 1, and 2 are console, because if someone closes + * System.out and then opens a file, they might get file descriptor + * 1. An error on *that* version of 1 should be reported, whereas + * an error on System.out (which was the original 1) should be + * ignored. So I use isatty() to ensure that such an error was + * because of this, and if it was, I ignore the error. + */ + + BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd); + + if (!ok) { + DWORD err = GetLastError(); + + if (err != ERROR_ACCESS_DENIED) { /* from winerror.h */ + _PR_MD_MAP_FSYNC_ERROR(err); + return -1; + } + } + return 0; +} + +PRInt32 +_PR_MD_CLOSE(PROsfd osfd, PRBool socket) +{ + PRInt32 rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (socket) { + rv = closesocket((SOCKET)osfd); + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError()); + } else { + rv = CloseHandle((HANDLE)osfd)?0:-1; + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(GetLastError()); + } + + if (rv == 0 && me->io_suspended) { + if (me->io_fd == osfd) { + PRBool fWait; + + _PR_THREAD_LOCK(me); + me->state = _PR_IO_WAIT; + /* The IO could have completed on another thread just after + * calling closesocket while the io_suspended flag was true. + * So we now grab the lock to do a safe check on io_pending to + * see if we need to wait or not. + */ + fWait = me->io_pending; + me->io_suspended = PR_FALSE; + me->md.interrupt_disabled = PR_TRUE; + _PR_THREAD_UNLOCK(me); + + if (fWait) + _NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(me->io_suspended == PR_FALSE); + PR_ASSERT(me->io_pending == PR_FALSE); + /* + * I/O operation is no longer pending; the thread can now + * run on any cpu + */ + _PR_THREAD_LOCK(me); + me->md.interrupt_disabled = PR_FALSE; + me->md.thr_bound_cpu = NULL; + me->io_suspended = PR_FALSE; + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(me); + } + } + return rv; +} + +PRStatus +_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) +{ + BOOL rv; + + if (fd->secret->md.io_model_committed) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + rv = SetHandleInformation( + (HANDLE)fd->secret->md.osfd, + HANDLE_FLAG_INHERIT, + inheritable ? HANDLE_FLAG_INHERIT : 0); + if (0 == rv) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void +_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) +{ + if (imported) { + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + fd->secret->inheritable = _PR_TRI_FALSE; + } +} + +void +_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) +{ + DWORD flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + if (fd->secret->md.io_model_committed) { + return; + } + if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) { + if (flags & HANDLE_FLAG_INHERIT) { + fd->secret->inheritable = _PR_TRI_TRUE; + } else { + fd->secret->inheritable = _PR_TRI_FALSE; + } + } +} + + +/* --- DIR IO ------------------------------------------------------------ */ +#define GetFileFromDIR(d) (d)->d_entry.cFileName +#define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + +void FlipSlashes(char *cp, int len) +{ + while (--len >= 0) { + if (cp[0] == '/') { + cp[0] = PR_DIRECTORY_SEPARATOR; + } + cp = _mbsinc(cp); + } +} /* end FlipSlashes() */ + +/* +** +** Local implementations of standard Unix RTL functions which are not provided +** by the VC RTL. +** +*/ + +PRStatus +_PR_MD_CLOSE_DIR(_MDDir *d) +{ + if ( d ) { + if (FindClose( d->d_hdl )) { + d->magic = (PRUint32)-1; + return PR_SUCCESS; + } else { + _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; +} + + +PRStatus +_PR_MD_OPEN_DIR(_MDDir *d, const char *name) +{ + char filename[ MAX_PATH ]; + int len; + + len = strlen(name); + /* Need 5 bytes for \*.* and the trailing null byte. */ + if (len + 5 > MAX_PATH) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return PR_FAILURE; + } + strcpy(filename, name); + + /* + * If 'name' ends in a slash or backslash, do not append + * another backslash. + */ + if (IsPrevCharSlash(filename, filename + len)) { + len--; + } + strcpy(&filename[len], "\\*.*"); + FlipSlashes( filename, strlen(filename) ); + + d->d_hdl = FindFirstFile( filename, &(d->d_entry) ); + if ( d->d_hdl == INVALID_HANDLE_VALUE ) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + d->firstEntry = PR_TRUE; + d->magic = _MD_MAGIC_DIR; + return PR_SUCCESS; +} + +char * +_PR_MD_READ_DIR(_MDDir *d, PRIntn flags) +{ + PRInt32 err; + BOOL rv; + char *fileName; + + if ( d ) { + while (1) { + if (d->firstEntry) { + d->firstEntry = PR_FALSE; + rv = 1; + } else { + rv = FindNextFile(d->d_hdl, &(d->d_entry)); + } + if (rv == 0) { + break; + } + fileName = GetFileFromDIR(d); + if ( (flags & PR_SKIP_DOT) && + (fileName[0] == '.') && (fileName[1] == '\0')) + continue; + if ( (flags & PR_SKIP_DOT_DOT) && + (fileName[0] == '.') && (fileName[1] == '.') && + (fileName[2] == '\0')) + continue; + if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) + continue; + return fileName; + } + err = GetLastError(); + PR_ASSERT(NO_ERROR != err); + _PR_MD_MAP_READDIR_ERROR(err); + return NULL; + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; +} + +PRInt32 +_PR_MD_DELETE(const char *name) +{ + if (DeleteFile(name)) { + return 0; + } else { + _PR_MD_MAP_DELETE_ERROR(GetLastError()); + return -1; + } +} + +void +_PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm) +{ + PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime)); + CopyMemory(prtm, filetime, sizeof(PRTime)); +#ifdef __GNUC__ + *prtm = (*prtm - _pr_filetime_offset) / 10LL; +#else + *prtm = (*prtm - _pr_filetime_offset) / 10i64; +#endif + +#ifdef DEBUG + /* Doublecheck our calculation. */ + { + SYSTEMTIME systime; + PRExplodedTime etm; + PRTime cmp; /* for comparison */ + BOOL rv; + + rv = FileTimeToSystemTime(filetime, &systime); + PR_ASSERT(0 != rv); + + /* + * PR_ImplodeTime ignores wday and yday. + */ + etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC; + etm.tm_sec = systime.wSecond; + etm.tm_min = systime.wMinute; + etm.tm_hour = systime.wHour; + etm.tm_mday = systime.wDay; + etm.tm_month = systime.wMonth - 1; + etm.tm_year = systime.wYear; + /* + * It is not well-documented what time zone the FILETIME's + * are in. WIN32_FIND_DATA is documented to be in UTC (GMT). + * But BY_HANDLE_FILE_INFORMATION is unclear about this. + * By our best judgement, we assume that FILETIME is in UTC. + */ + etm.tm_params.tp_gmt_offset = 0; + etm.tm_params.tp_dst_offset = 0; + cmp = PR_ImplodeTime(&etm); + + /* + * SYSTEMTIME is in milliseconds precision, so we convert PRTime's + * microseconds to milliseconds before doing the comparison. + */ + PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC)); + } +#endif /* DEBUG */ +} + +PRInt32 +_PR_MD_STAT(const char *fn, struct stat *info) +{ + PRInt32 rv; + + rv = _stat(fn, (struct _stat *)info); + if (-1 == rv) { + /* + * Check for MSVC runtime library _stat() bug. + * (It's really a bug in FindFirstFile().) + * If a pathname ends in a backslash or slash, + * e.g., c:\temp\ or c:/temp/, _stat() will fail. + * Note: a pathname ending in a slash (e.g., c:/temp/) + * can be handled by _stat() on NT but not on Win95. + * + * We remove the backslash or slash at the end and + * try again. + */ + + int len = strlen(fn); + if (len > 0 && len <= _MAX_PATH + && IsPrevCharSlash(fn, fn + len)) { + char newfn[_MAX_PATH + 1]; + + strcpy(newfn, fn); + newfn[len - 1] = '\0'; + rv = _stat(newfn, (struct _stat *)info); + } + } + + if (-1 == rv) { + _PR_MD_MAP_STAT_ERROR(errno); + } + return rv; +} + +#define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\') + +static PRBool +IsPrevCharSlash(const char *str, const char *current) +{ + const char *prev; + + if (str >= current) + return PR_FALSE; + prev = _mbsdec(str, current); + return (prev == current - 1) && _PR_IS_SLASH(*prev); +} + +/* + * IsRootDirectory -- + * + * Return PR_TRUE if the pathname 'fn' is a valid root directory, + * else return PR_FALSE. The char buffer pointed to by 'fn' must + * be writable. During the execution of this function, the contents + * of the buffer pointed to by 'fn' may be modified, but on return + * the original contents will be restored. 'buflen' is the size of + * the buffer pointed to by 'fn'. + * + * Root directories come in three formats: + * 1. / or \, meaning the root directory of the current drive. + * 2. C:/ or C:\, where C is a drive letter. + * 3. \\\\ or + * \\\, meaning the root directory + * of a UNC (Universal Naming Convention) name. + */ + +static PRBool +IsRootDirectory(char *fn, size_t buflen) +{ + char *p; + PRBool slashAdded = PR_FALSE; + PRBool rv = PR_FALSE; + + if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') { + return PR_TRUE; + } + + if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2]) + && fn[3] == '\0') { + rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; + return rv; + } + + /* The UNC root directory */ + + if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) { + /* The 'server' part should have at least one character. */ + p = &fn[2]; + if (*p == '\0' || _PR_IS_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the next slash */ + do { + p = _mbsinc(p); + } while (*p != '\0' && !_PR_IS_SLASH(*p)); + if (*p == '\0') { + return PR_FALSE; + } + + /* The 'share' part should have at least one character. */ + p++; + if (*p == '\0' || _PR_IS_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the final slash */ + do { + p = _mbsinc(p); + } while (*p != '\0' && !_PR_IS_SLASH(*p)); + if (_PR_IS_SLASH(*p) && p[1] != '\0') { + return PR_FALSE; + } + if (*p == '\0') { + /* + * GetDriveType() doesn't work correctly if the + * path is of the form \\server\share, so we add + * a final slash temporarily. + */ + if ((p + 1) < (fn + buflen)) { + *p++ = '\\'; + *p = '\0'; + slashAdded = PR_TRUE; + } else { + return PR_FALSE; /* name too long */ + } + } + rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; + /* restore the 'fn' buffer */ + if (slashAdded) { + *--p = '\0'; + } + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) +{ + WIN32_FILE_ATTRIBUTE_DATA findFileData; + + if (NULL == fn || '\0' == *fn) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + if (!GetFileAttributesEx(fn, GetFileExInfoStandard, &findFileData)) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + info->type = PR_FILE_DIRECTORY; + } else { + info->type = PR_FILE_FILE; + } + + info->size = findFileData.nFileSizeHigh; + info->size = (info->size << 32) + findFileData.nFileSizeLow; + + _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); + + if (0 == findFileData.ftCreationTime.dwLowDateTime && + 0 == findFileData.ftCreationTime.dwHighDateTime) { + info->creationTime = info->modifyTime; + } else { + _PR_FileTimeToPRTime(&findFileData.ftCreationTime, + &info->creationTime); + } + + return 0; +} + +PRInt32 +_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) +{ + PRFileInfo64 info64; + PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64); + if (0 == rv) + { + info->type = info64.type; + info->size = (PRUint32) info64.size; + info->modifyTime = info64.modifyTime; + info->creationTime = info64.creationTime; + } + return rv; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + int rv; + + BY_HANDLE_FILE_INFORMATION hinfo; + + rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo); + if (rv == FALSE) { + _PR_MD_MAP_FSTAT_ERROR(GetLastError()); + return -1; + } + + if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_FILE; + + info->size = hinfo.nFileSizeHigh; + info->size = (info->size << 32) + hinfo.nFileSizeLow; + + _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) ); + _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) ); + + return 0; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) +{ + int rv; + + BY_HANDLE_FILE_INFORMATION hinfo; + + rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo); + if (rv == FALSE) { + _PR_MD_MAP_FSTAT_ERROR(GetLastError()); + return -1; + } + + if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_FILE; + + info->size = hinfo.nFileSizeLow; + + _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) ); + _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) ); + + return 0; +} + +PRInt32 +_PR_MD_RENAME(const char *from, const char *to) +{ + /* Does this work with dot-relative pathnames? */ + if (MoveFile(from, to)) { + return 0; + } else { + _PR_MD_MAP_RENAME_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_ACCESS(const char *name, PRAccessHow how) +{ + PRInt32 rv; + + switch (how) { + case PR_ACCESS_WRITE_OK: + rv = _access(name, 02); + break; + case PR_ACCESS_READ_OK: + rv = _access(name, 04); + break; + case PR_ACCESS_EXISTS: + rv = _access(name, 00); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (rv < 0) { + _PR_MD_MAP_ACCESS_ERROR(errno); + } + return rv; +} + +PRInt32 +_PR_MD_MKDIR(const char *name, PRIntn mode) +{ + /* XXXMB - how to translate the "mode"??? */ + if (CreateDirectory(name, NULL)) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_MAKE_DIR(const char *name, PRIntn mode) +{ + BOOL rv; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + rv = CreateDirectory(name, lpSA); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (rv) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_RMDIR(const char *name) +{ + if (RemoveDirectory(name)) { + return 0; + } else { + _PR_MD_MAP_RMDIR_ERROR(GetLastError()); + return -1; + } +} + +PRStatus +_PR_MD_LOCKFILE(PROsfd f) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + + rv = LockFileEx((HANDLE)f, + LOCKFILE_EXCLUSIVE_LOCK, + 0, + 0x7fffffff, + 0, + &me->md.overlapped.overlapped); + + if (_native_threads_only) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + if (rv == FALSE) { + err = GetLastError(); + PR_ASSERT(err != ERROR_IO_PENDING); + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; + } + + /* HACK AROUND NT BUG + * NT 3.51 has a bug. In NT 3.51, if LockFileEx returns true, you + * don't get any completion on the completion port. This is a bug. + * + * They fixed it on NT4.0 so that you do get a completion. + * + * If we pretend we won't get a completion, NSPR gets confused later + * when the unexpected completion arrives. If we assume we do get + * a completion, we hang on 3.51. Worse, Microsoft informs me that the + * behavior varies on 3.51 depending on if you are using a network + * file system or a local disk! + * + * Solution: For now, _nt_version_gets_lockfile_completion is set + * depending on whether or not this system is EITHER + * - running NT 4.0 + * - running NT 3.51 with a service pack greater than 5. + * + * In the meantime, this code may not work on network file systems. + * + */ + + if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } +#ifdef _NEED_351_FILE_LOCKING_HACK + else if (rv) { + /* If this is NT 3.51 and the file is local, then we won't get a + * completion back from LockFile when it succeeded. + */ + if (_nt_version_gets_lockfile_completion == PR_FALSE) { + if ( IsFileLocal((HANDLE)f) == _PR_LOCAL_FILE) { + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + return PR_SUCCESS; + } + } + } +#endif /* _NEED_351_FILE_LOCKING_HACK */ + + if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +PRStatus +_PR_MD_TLOCKFILE(PROsfd f) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + + rv = LockFileEx((HANDLE)f, + LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK, + 0, + 0x7fffffff, + 0, + &me->md.overlapped.overlapped); + if (_native_threads_only) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + if (rv == FALSE) { + err = GetLastError(); + PR_ASSERT(err != ERROR_IO_PENDING); + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; + } + if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } +#ifdef _NEED_351_FILE_LOCKING_HACK + else if (rv) { + /* If this is NT 3.51 and the file is local, then we won't get a + * completion back from LockFile when it succeeded. + */ + if (_nt_version_gets_lockfile_completion == PR_FALSE) { + if ( IsFileLocal((HANDLE)f) == _PR_LOCAL_FILE) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + return PR_SUCCESS; + } + } + } +#endif /* _NEED_351_FILE_LOCKING_HACK */ + + if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + return PR_FAILURE; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + + +PRStatus +_PR_MD_UNLOCKFILE(PROsfd f) +{ + PRInt32 rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + rv = UnlockFileEx((HANDLE)f, + 0, + 0x7fffffff, + 0, + &me->md.overlapped.overlapped); + + if (rv) + return PR_SUCCESS; + else { + int err = GetLastError(); + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } +} + +void +_PR_MD_MAKE_NONBLOCK(PRFileDesc *f) +{ + /* + * On NT, we either call _md_Associate() or _md_MakeNonblock(), + * depending on whether the socket is blocking or not. + * + * Once we associate a socket with the io completion port, + * there is no way to disassociate it from the io completion + * port. So we have to call _md_Associate/_md_MakeNonblock + * lazily. + */ +} + +#ifdef _NEED_351_FILE_LOCKING_HACK +/*************** +** +** Lockfile hacks +** +** The following code is a hack to work around a microsoft bug with lockfile. +** The problem is that on NT 3.51, if LockFileEx() succeeds, you never +** get a completion back for files that are on local disks. So, we need to +** know if a file is local or remote so we can tell if we should expect +** a completion. +** +** The only way to check if a file is local or remote based on the handle is +** to get the serial number for the volume it is mounted on and then to +** compare that with mounted drives. This code caches the volume numbers of +** fixed disks and does a relatively quick check. +** +** Locking: Since the only thing we ever do when multithreaded is a 32bit +** assignment, we probably don't need locking. It is included just +** case anyway. +** +** Limitations: Does not work on floppies because they are too slow +** Unknown if it will work on wierdo 3rd party file systems +** +**************** +*/ + +/* There can only be 26 drive letters on NT */ +#define _PR_MAX_DRIVES 26 + +_MDLock cachedVolumeLock; +DWORD dwCachedVolumeSerialNumbers[_PR_MAX_DRIVES] = {0}; +DWORD dwLastCachedDrive = 0; +DWORD dwRemoveableDrivesToCheck = 0; /* bitmask for removeable drives */ + +PRBool IsFileLocalInit() +{ + TCHAR lpBuffer[_PR_MAX_DRIVES*5]; + DWORD nBufferLength = _PR_MAX_DRIVES*5; + DWORD nBufferNeeded = GetLogicalDriveStrings(0, NULL); + DWORD dwIndex = 0; + DWORD dwDriveType; + DWORD dwVolumeSerialNumber; + DWORD dwDriveIndex = 0; + DWORD oldmode = (DWORD) -1; + + _MD_NEW_LOCK(&cachedVolumeLock); + + nBufferNeeded = GetLogicalDriveStrings(nBufferLength, lpBuffer); + if (nBufferNeeded == 0 || nBufferNeeded > nBufferLength) + return PR_FALSE; + + // Calling GetVolumeInformation on a removeable drive where the + // disk is currently removed will cause a dialog box to the + // console. This is not good. + // Temporarily disable the SEM_FAILCRITICALERRORS to avoid the + // damn dialog. + + dwCachedVolumeSerialNumbers[dwDriveIndex] = 0; + oldmode = SetErrorMode(SEM_FAILCRITICALERRORS); + + // now loop through the logical drives + while(lpBuffer[dwIndex] != TEXT('\0')) + { + // skip the floppy drives. This is *SLOW* + if ((lpBuffer[dwIndex] == TEXT('A')) || (lpBuffer[dwIndex] == TEXT('B'))) + /* Skip over floppies */; + else + { + dwDriveIndex = (lpBuffer[dwIndex] - TEXT('A')); + + dwDriveType = GetDriveType(&lpBuffer[dwIndex]); + + switch(dwDriveType) + { + // Ignore these drive types + case 0: + case 1: + case DRIVE_REMOTE: + default: // If the drive type is unknown, ignore it. + break; + + // Removable media drives can have different serial numbers + // at different times, so cache the current serial number + // but keep track of them so they can be rechecked if necessary. + case DRIVE_REMOVABLE: + + // CDROM is a removable media + case DRIVE_CDROM: + + // no idea if ramdisks can change serial numbers or not + // but it doesn't hurt to treat them as removable. + + case DRIVE_RAMDISK: + + + // Here is where we keep track of removable drives. + dwRemoveableDrivesToCheck |= 1 << dwDriveIndex; + + // removable drives fall through to fixed drives and get cached. + + case DRIVE_FIXED: + + // cache volume serial numbers. + if (GetVolumeInformation( + &lpBuffer[dwIndex], + NULL, 0, + &dwVolumeSerialNumber, + NULL, NULL, NULL, 0) + ) + { + if (dwLastCachedDrive < dwDriveIndex) + dwLastCachedDrive = dwDriveIndex; + dwCachedVolumeSerialNumbers[dwDriveIndex] = dwVolumeSerialNumber; + } + + break; + } + } + + dwIndex += lstrlen(&lpBuffer[dwIndex]) +1; + } + + if (oldmode != (DWORD) -1) { + SetErrorMode(oldmode); + oldmode = (DWORD) -1; + } + + return PR_TRUE; +} + +PRInt32 IsFileLocal(HANDLE hFile) +{ + DWORD dwIndex = 0, dwMask; + BY_HANDLE_FILE_INFORMATION Info; + TCHAR szDrive[4] = TEXT("C:\\"); + DWORD dwVolumeSerialNumber; + DWORD oldmode = (DWORD) -1; + int rv = _PR_REMOTE_FILE; + + if (!GetFileInformationByHandle(hFile, &Info)) + return -1; + + // look to see if the volume serial number has been cached. + _MD_LOCK(&cachedVolumeLock); + while(dwIndex <= dwLastCachedDrive) + if (dwCachedVolumeSerialNumbers[dwIndex++] == Info.dwVolumeSerialNumber) + return _PR_LOCAL_FILE; + _MD_UNLOCK(&cachedVolumeLock); + + // volume serial number not found in the cache. Check removable files. + // removable drives are noted as a bitmask. If the bit associated with + // a specific drive is set, then we should query its volume serial number + // as its possible it has changed. + dwMask = dwRemoveableDrivesToCheck; + dwIndex = 0; + + while(dwMask) + { + while(!(dwMask & 1)) + { + dwIndex++; + dwMask = dwMask >> 1; + } + + szDrive[0] = TEXT('A')+ (TCHAR) dwIndex; + + // Calling GetVolumeInformation on a removeable drive where the + // disk is currently removed will cause a dialog box to the + // console. This is not good. + // Temporarily disable the SEM_FAILCRITICALERRORS to avoid the + // dialog. + + oldmode = SetErrorMode(SEM_FAILCRITICALERRORS); + + if (GetVolumeInformation( + szDrive, + NULL, 0, + &dwVolumeSerialNumber, + NULL, NULL, NULL, 0) + ) + { + if (dwVolumeSerialNumber == Info.dwVolumeSerialNumber) + { + _MD_LOCK(&cachedVolumeLock); + if (dwLastCachedDrive < dwIndex) + dwLastCachedDrive = dwIndex; + dwCachedVolumeSerialNumbers[dwIndex] = dwVolumeSerialNumber; + _MD_UNLOCK(&cachedVolumeLock); + rv = _PR_LOCAL_FILE; + } + } + if (oldmode != (DWORD) -1) { + SetErrorMode(oldmode); + oldmode = (DWORD) -1; + } + + if (rv == _PR_LOCAL_FILE) + return _PR_LOCAL_FILE; + + dwIndex++; + dwMask = dwMask >> 1; + } + + return _PR_REMOTE_FILE; +} +#endif /* _NEED_351_FILE_LOCKING_HACK */ + +PR_IMPLEMENT(PRStatus) PR_NT_CancelIo(PRFileDesc *fd) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRBool fWait; + PRFileDesc *bottom; + + bottom = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER); + if (!me->io_suspended || (NULL == bottom) || + (me->io_fd != bottom->secret->md.osfd)) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + /* + * The CancelIO operation has to be issued by the same NT thread that + * issued the I/O operation + */ + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || (me->cpu == me->md.thr_bound_cpu)); + if (me->io_pending) { + if (!CancelIo((HANDLE)bottom->secret->md.osfd)) { + PR_SetError(PR_INVALID_STATE_ERROR, GetLastError()); + return PR_FAILURE; + } + } + _PR_THREAD_LOCK(me); + fWait = me->io_pending; + me->io_suspended = PR_FALSE; + me->state = _PR_IO_WAIT; + me->md.interrupt_disabled = PR_TRUE; + _PR_THREAD_UNLOCK(me); + if (fWait) + _NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(me->io_suspended == PR_FALSE); + PR_ASSERT(me->io_pending == PR_FALSE); + + _PR_THREAD_LOCK(me); + me->md.interrupt_disabled = PR_FALSE; + me->md.thr_bound_cpu = NULL; + me->io_suspended = PR_FALSE; + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(me); + return PR_SUCCESS; +} + +static PROsfd _nt_nonblock_accept(PRFileDesc *fd, struct sockaddr *addr, int *addrlen, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + SOCKET sock; + 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 ((sock = accept(osfd, addr, addrlen)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + if ((rv = _PR_NTFiberSafeSelect(0, &rd, NULL, NULL, + NULL)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } + } else { + _PR_MD_MAP_ACCEPT_ERROR(err); + break; + } + } + } else if (timeout == PR_INTERVAL_NO_WAIT) { + if ((sock = accept(osfd, addr, addrlen)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } else { + _PR_MD_MAP_ACCEPT_ERROR(err); + } + } + } else { +retry: + if ((sock = accept(osfd, addr, addrlen)) == -1) { + 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 = _PR_NTFiberSafeSelect(0, &rd, NULL, NULL, tvp); + if (rv > 0) { + goto retry; + } else if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } else { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + } + } else { + _PR_MD_MAP_ACCEPT_ERROR(err); + } + } + } + return (PROsfd)sock; +} + +static PRInt32 _nt_nonblock_connect(PRFileDesc *fd, struct sockaddr *addr, int addrlen, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv; + int err; + fd_set wr, ex; + struct timeval tv, *tvp; + int len; + + if ((rv = connect(osfd, addr, addrlen)) == -1) { + if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) { + 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(&wr); + FD_ZERO(&ex); + FD_SET((SOCKET)osfd, &wr); + FD_SET((SOCKET)osfd, &ex); + if ((rv = _PR_NTFiberSafeSelect(0, NULL, &wr, &ex, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return rv; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + /* Call Sleep(0) to work around a Winsock timeing 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; + } + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; + } + PR_ASSERT(FD_ISSET((SOCKET)osfd, &wr)); + rv = 0; + } else { + _PR_MD_MAP_CONNECT_ERROR(err); + } + } + return rv; +} + +static PRInt32 _nt_nonblock_recv(PRFileDesc *fd, char *buf, int len, int flags, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + struct timeval tv, *tvp; + fd_set rd; + int osflags; + + if (0 == flags) { + osflags = 0; + } else { + PR_ASSERT(PR_MSG_PEEK == flags); + osflags = MSG_PEEK; + } + while ((rv = recv(osfd,buf,len,osflags)) == -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 = _PR_NTFiberSafeSelect(0, &rd, NULL, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } else if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } + } else { + _PR_MD_MAP_RECV_ERROR(err); + break; + } + } + return(rv); +} + +static PRInt32 _nt_nonblock_send(PRFileDesc *fd, char *buf, int len, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + struct timeval tv, *tvp; + fd_set wd; + PRInt32 bytesSent = 0; + + while(bytesSent < len) { + while ((rv = send(osfd,buf,len,0)) == -1) { + 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 = _PR_NTFiberSafeSelect(0, NULL, &wd, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return -1; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + } else { + _PR_MD_MAP_SEND_ERROR(err); + return -1; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) { + break; + } + if (bytesSent < len) { + 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 = _PR_NTFiberSafeSelect(0, NULL, &wd, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return -1; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + } + } + return bytesSent; +} + +static PRInt32 _nt_nonblock_writev(PRFileDesc *fd, const PRIOVec *iov, int size, PRIntervalTime timeout) +{ + int index; + int sent = 0; + int rv; + + for (index=0; index 0) + sent += rv; + if ( rv != iov[index].iov_len ) { + if (rv < 0) { + if (fd->secret->nonblocking + && (PR_GetError() == PR_WOULD_BLOCK_ERROR) + && (sent > 0)) { + return sent; + } else { + return -1; + } + } + /* Only a nonblocking socket can have partial sends */ + PR_ASSERT(fd->secret->nonblocking); + return sent; + } + } + + return sent; +} + +static PRInt32 _nt_nonblock_sendto( + PRFileDesc *fd, const char *buf, int len, + const struct sockaddr *addr, int addrlen, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + struct timeval tv, *tvp; + fd_set wd; + PRInt32 bytesSent = 0; + + while(bytesSent < len) { + while ((rv = sendto(osfd,buf,len,0, addr, addrlen)) == -1) { + 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 = _PR_NTFiberSafeSelect(0, NULL, &wd, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return -1; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + } else { + _PR_MD_MAP_SENDTO_ERROR(err); + return -1; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) { + break; + } + if (bytesSent < len) { + 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 = _PR_NTFiberSafeSelect(0, NULL, &wd, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return -1; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + } + } + return bytesSent; +} + +static PRInt32 _nt_nonblock_recvfrom(PRFileDesc *fd, char *buf, int len, struct sockaddr *addr, int *addrlen, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + struct timeval tv, *tvp; + fd_set rd; + + while ((rv = recvfrom(osfd,buf,len,0,addr, addrlen)) == -1) { + 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(&rd); + FD_SET((SOCKET)osfd, &rd); + if ((rv = _PR_NTFiberSafeSelect(0, &rd, NULL, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } else if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } + } else { + _PR_MD_MAP_RECVFROM_ERROR(err); + break; + } + } + return(rv); +} + +/* + * UDP support: the continuation thread functions and recvfrom and sendto. + */ + +static void pt_InsertTimedInternal(pt_Continuation *op) +{ + PRInt32 delta = 0; + pt_Continuation *t_op = NULL; + PRIntervalTime now = PR_IntervalNow(), op_tmo, qd_tmo; + + /* + * If this element operation isn't timed, it gets queued at the + * end of the list (just after pt_tq.tail) and we're + * finishd early. + */ + if (PR_INTERVAL_NO_TIMEOUT == op->timeout) + { + t_op = pt_tq.tail; /* put it at the end */ + goto done; + } + + /* + * The rest of this routine actaully deals with timed ops. + */ + + if (NULL != pt_tq.op) + { + /* + * To find where in the list to put the new operation, form + * the absolute time the operations in question will expire. + * + * The new operation ('op') will expire at now() + op->timeout. + * + * The operation that will time out furthest in the future will + * do so at pt_tq.epoch + pt_tq.op->timeout. + * + * Subsequently earlier timeouts are computed based on the latter + * knowledge by subracting the timeout deltas that are stored in + * the operation list. There are operation[n]->timeout ticks + * between the expiration of operation[n-1] and operation[n].e e + * + * Therefore, the operation[n-1] will expire operation[n]->timeout + * ticks prior to operation[n]. + * + * This should be easy! + */ + t_op = pt_tq.op; /* running pointer to queued op */ + op_tmo = now + op->timeout; /* that's in absolute ticks */ + qd_tmo = pt_tq.epoch + t_op->timeout; /* likewise */ + + do + { + /* + * If 'op' expires later than t_op, then insert 'op' just + * ahead of t_op. Otherwise, compute when operation[n-1] + * expires and try again. + * + * The actual different between the expiriation of 'op' + * and the current operation what becomes the new operaton's + * timeout interval. That interval is also subtracted from + * the interval of the operation immediately following where + * we stick 'op' (unless the next one isn't timed). The new + * timeout assigned to 'op' takes into account the values of + * now() and when the previous intervals were compured. + */ + delta = op_tmo - qd_tmo; + if (delta >= 0) + { + op->timeout += (now - pt_tq.epoch); + goto done; + } + + qd_tmo -= t_op->timeout; /* previous operaton expiration */ + t_op = t_op->prev; /* point to previous operation */ + if (NULL != t_op) qd_tmo += t_op->timeout; + } while (NULL != t_op); + + /* + * If we got here we backed off the head of the list. That means that + * this timed entry has to go at the head of the list. This is just + * about like having an empty timer list. + */ + delta = op->timeout; /* $$$ is this right? */ + } + +done: + + /* + * Insert 'op' into the queue just after t_op or if t_op is null, + * at the head of the list. + * + * If t_op is NULL, the list is currently empty and this is pretty + * easy. + */ + if (NULL == t_op) + { + op->prev = NULL; + op->next = pt_tq.head; + pt_tq.head = op; + if (NULL == pt_tq.tail) pt_tq.tail = op; + else op->next->prev = op; + } + else + { + op->prev = t_op; + op->next = t_op->next; + if (NULL != op->prev) + op->prev->next = op; + if (NULL != op->next) + op->next->prev = op; + if (t_op == pt_tq.tail) + pt_tq.tail = op; + } + + /* + * Are we adjusting our epoch, etc? Are we replacing + * what was previously the element due to expire furthest + * out in the future? Is this even a timed operation? + */ + if (PR_INTERVAL_NO_TIMEOUT != op->timeout) + { + if ((NULL == pt_tq.op) /* we're the one and only */ + || (t_op == pt_tq.op)) /* we're replacing */ + { + pt_tq.op = op; + pt_tq.epoch = now; + } + } + + pt_tq.op_count += 1; + +} /* pt_InsertTimedInternal */ + +/* + * function: pt_FinishTimed + * + * Takes the finished operation out of the timed queue. It + * notifies the initiating thread that the opertions is + * complete and returns to the caller the value of the next + * operation in the list (or NULL). + */ +static pt_Continuation *pt_FinishTimedInternal(pt_Continuation *op) +{ + pt_Continuation *next; + + /* remove this one from the list */ + if (NULL == op->prev) pt_tq.head = op->next; + else op->prev->next = op->next; + if (NULL == op->next) pt_tq.tail = op->prev; + else op->next->prev = op->prev; + + /* did we happen to hit the timed op? */ + if (op == pt_tq.op) pt_tq.op = op->prev; + + next = op->next; + op->next = op->prev = NULL; + op->status = pt_continuation_done; + + pt_tq.op_count -= 1; +#if defined(DEBUG) + pt_debug.continuationsServed += 1; +#endif + PR_NotifyCondVar(op->complete); + + return next; +} /* pt_FinishTimedInternal */ + +static void ContinuationThread(void *arg) +{ + /* initialization */ + fd_set readSet, writeSet, exceptSet; + struct timeval tv; + SOCKET *pollingList = 0; /* list built for polling */ + PRIntn pollingListUsed; /* # entries used in the list */ + PRIntn pollingListNeeded; /* # entries needed this time */ + PRIntn pollingSlotsAllocated = 0; /* # entries available in list */ + PRIntervalTime mx_select_ticks = PR_MillisecondsToInterval(PT_DEFAULT_SELECT_MSEC); + + /* do some real work */ + while (1) + { + PRIntn rv; + PRStatus status; + PRIntn pollIndex; + pt_Continuation *op; + PRIntervalTime now = PR_IntervalNow(); + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + + PR_Lock(pt_tq.ml); + while (NULL == pt_tq.head) + { + status = PR_WaitCondVar(pt_tq.new_op, PR_INTERVAL_NO_TIMEOUT); + if ((PR_FAILURE == status) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + } + pollingListNeeded = pt_tq.op_count; + PR_Unlock(pt_tq.ml); + + /* Okay. We're history */ + if ((PR_FAILURE == status) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + + /* + * 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. + */ + + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + FD_ZERO(&exceptSet); + pollingListNeeded += 10; + if (pollingListNeeded > pollingSlotsAllocated) + { + if (NULL != pollingList) PR_DELETE(pollingList); + pollingList = PR_MALLOC(pollingListNeeded * sizeof(PRPollDesc)); + PR_ASSERT(NULL != pollingList); + pollingSlotsAllocated = pollingListNeeded; + } + +#if defined(DEBUG) + if (pollingListNeeded > pt_debug.pollingListMax) + pt_debug.pollingListMax = pollingListUsed; +#endif + + /* + * Build up a polling list. + * This list is sorted on time. Operations that have been + * interrupted are completed and not included in the list. + * There is an assertion that the operation is in progress. + */ + pollingListUsed = 0; + PR_Lock(pt_tq.ml); + + for (op = pt_tq.head; NULL != op;) + { + if (pt_continuation_abort == op->status) + { + op->result.code = -1; + op->syserrno = WSAEINTR; + op = pt_FinishTimedInternal(op); + } + else + { + PR_ASSERT(pt_continuation_done != op->status); + op->status = pt_continuation_inprogress; + if (op->event & PR_POLL_READ) { + FD_SET(op->arg1.osfd, &readSet); + } + if (op->event & PR_POLL_WRITE) { + FD_SET(op->arg1.osfd, &writeSet); + } + if (op->event & PR_POLL_EXCEPT) { + FD_SET(op->arg1.osfd, &exceptSet); + } + pollingList[pollingListUsed] = op->arg1.osfd; + pollingListUsed += 1; + if (pollingListUsed == pollingSlotsAllocated) break; + op = op->next; + } + } + + PR_Unlock(pt_tq.ml); + + /* + * If 'op' isn't NULL at this point, then we didn't get to + * 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) + { +#if defined(DEBUG) + pt_debug.predictionsFoiled += 1; /* keep track */ +#endif + continue; /* make it rethink things */ + } + + /* there's a chance that all ops got blown away */ + if (NULL == pt_tq.head) continue; + /* if not, we know this is the shortest timeout */ + timeout = pt_tq.head->timeout; + + /* + * We don't want to wait forever on this poll. So keep + * the interval down. The operations, if they are timed, + * still have to timeout, while those that are not timed + * should persist forever. But they may be aborted. That's + * what this anxiety is all about. + */ + if (timeout > mx_select_ticks) timeout = mx_select_ticks; + + if (PR_INTERVAL_NO_TIMEOUT != pt_tq.head->timeout) + pt_tq.head->timeout -= timeout; + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC; + + rv = select(0, &readSet, &writeSet, &exceptSet, &tv); + + if (0 == rv) /* poll timed out - what about leading op? */ + { + if (0 == pt_tq.head->timeout) + { + /* + * The leading element of the timed queue has timed + * out. Get rid of it. In any case go around the + * loop again, computing the polling list, checking + * for interrupted operations. + */ + PR_Lock(pt_tq.ml); + do + { + pt_tq.head->result.code = -1; + pt_tq.head->syserrno = WSAETIMEDOUT; + op = pt_FinishTimedInternal(pt_tq.head); + } while ((NULL != op) && (0 == op->timeout)); + PR_Unlock(pt_tq.ml); + } + continue; + } + + if (-1 == rv && (WSAGetLastError() == WSAEINTR + || WSAGetLastError() == WSAEINPROGRESS)) + { + continue; /* go around the loop again */ + } + + /* + * select() says that something in our list is ready for some more + * action or is an invalid fd. Find it, load up the operation and + * see what happens. + */ + + PR_ASSERT(rv > 0 || WSAGetLastError() == WSAENOTSOCK); + + + /* + * $$$ There's a problem here. I'm running the operations list + * and I'm not holding any locks. I don't want to hold the lock + * and do the operation, so this is really messed up.. + * + * This may work out okay. The rule is that only this thread, + * the continuation thread, can remove elements from the list. + * Therefore, the list is at worst, longer than when we built + * the polling list. + */ + op = pt_tq.head; + for (pollIndex = 0; pollIndex < pollingListUsed; ++pollIndex) + { + PRInt16 revents = 0; + + PR_ASSERT(NULL != op); + + /* + * 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 operation on. + */ + while (pollingList[pollIndex] != op->arg1.osfd ) + { + op = op->next; + PR_ASSERT(NULL != op); + } + + if (FD_ISSET(op->arg1.osfd, &readSet)) { + revents |= PR_POLL_READ; + } + if (FD_ISSET(op->arg1.osfd, &writeSet)) { + revents |= PR_POLL_WRITE; + } + if (FD_ISSET(op->arg1.osfd, &exceptSet)) { + revents |= PR_POLL_EXCEPT; + } + + /* + * Sip 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 (revents && (pt_continuation_inprogress == op->status) + && (op->function(op, revents))) + { + PR_Lock(pt_tq.ml); + op = pt_FinishTimedInternal(op); + PR_Unlock(pt_tq.ml); + } + } + } + if (NULL != pollingList) PR_DELETE(pollingList); +} /* ContinuationThread */ + +static int pt_Continue(pt_Continuation *op) +{ + PRStatus rv; + /* Finish filling in the blank slots */ + op->status = pt_continuation_sumbitted; + op->complete = PR_NewCondVar(pt_tq.ml); + + PR_Lock(pt_tq.ml); /* we provide the locking */ + + pt_InsertTimedInternal(op); /* insert in the structure */ + + PR_NotifyCondVar(pt_tq.new_op); /* notify the continuation thread */ + + while (pt_continuation_done != op->status) /* wait for completion */ + { + rv = PR_WaitCondVar(op->complete, PR_INTERVAL_NO_TIMEOUT); + /* + * If we get interrupted, we set state the continuation thread will + * see and allow it to finish the I/O operation w/ error. That way + * the rule that only the continuation thread is removing elements + * from the list is still valid. + * + * Don't call interrupt on the continuation thread. That'll just + * piss him off. He's cycling around at least every mx_select_ticks + * anyhow and should notice the request in there. + */ + if ((PR_FAILURE == rv) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) + op->status = pt_continuation_abort; /* our status */ + } + + PR_Unlock(pt_tq.ml); /* we provide the locking */ + + PR_DestroyCondVar(op->complete); + + return op->result.code; /* and the primary answer */ +} /* pt_Continue */ + +static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn bytes = sendto( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags, + (struct sockaddr*)op->arg5.addr, sizeof(*(op->arg5.addr))); + op->syserrno = WSAGetLastError(); + if (bytes > 0) /* this is progress */ + { + char *bp = op->arg2.buffer; + bp += bytes; /* adjust the buffer pointer */ + op->arg2.buffer = bp; + op->result.code += bytes; /* accumulate the number sent */ + op->arg3.amount -= bytes; /* and reduce the required count */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else return ((-1 == bytes) && (WSAEWOULDBLOCK == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_sendto_cont */ + +static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn addr_len = sizeof(*(op->arg5.addr)); + op->result.code = recvfrom( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, + op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len); + op->syserrno = WSAGetLastError(); + return ((-1 == op->result.code) && (WSAEWOULDBLOCK == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_recvfrom_cont */ + +static PRInt32 pt_SendTo( + SOCKET osfd, const void *buf, + PRInt32 amount, PRInt32 flags, const PRNetAddr *addr, + PRIntn addrlen, PRIntervalTime timeout) +{ + PRInt32 bytes = -1, err; + PRBool fNeedContinue = PR_FALSE; + + bytes = sendto( + osfd, buf, amount, flags, + (struct sockaddr*)addr, PR_NETADDR_SIZE(addr)); + if (bytes == -1) { + if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) + fNeedContinue = PR_TRUE; + else + _PR_MD_MAP_SENDTO_ERROR(err); + } + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = osfd; + op.arg2.buffer = (void*)buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.arg5.addr = (PRNetAddr*)addr; + op.timeout = timeout; + op.result.code = 0; /* initialize the number sent */ + op.function = pt_sendto_cont; + op.event = PR_POLL_WRITE | PR_POLL_EXCEPT; + bytes = pt_Continue(&op); + if (bytes < 0) { + WSASetLastError(op.syserrno); + _PR_MD_MAP_SENDTO_ERROR(op.syserrno); + } + } + return bytes; +} /* pt_SendTo */ + +static PRInt32 pt_RecvFrom(SOCKET osfd, void *buf, PRInt32 amount, + PRInt32 flags, PRNetAddr *addr, PRIntn *addr_len, PRIntervalTime timeout) +{ + PRInt32 bytes = -1, err; + PRBool fNeedContinue = PR_FALSE; + + bytes = recvfrom( + osfd, buf, amount, flags, + (struct sockaddr*)addr, addr_len); + if (bytes == -1) { + if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) + fNeedContinue = PR_TRUE; + else + _PR_MD_MAP_RECVFROM_ERROR(err); + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = osfd; + op.arg2.buffer = buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.arg5.addr = addr; + op.timeout = timeout; + op.function = pt_recvfrom_cont; + op.event = PR_POLL_READ | PR_POLL_EXCEPT; + bytes = pt_Continue(&op); + if (bytes < 0) { + WSASetLastError(op.syserrno); + _PR_MD_MAP_RECVFROM_ERROR(op.syserrno); + } + } + return bytes; +} /* pt_RecvFrom */ diff --git a/nsprpub/pr/src/md/windows/ntmisc.c b/nsprpub/pr/src/md/windows/ntmisc.c new file mode 100644 index 00000000000..b8c09de635a --- /dev/null +++ b/nsprpub/pr/src/md/windows/ntmisc.c @@ -0,0 +1,867 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * ntmisc.c + * + */ + +#include "primpl.h" + +char *_PR_MD_GET_ENV(const char *name) +{ + return getenv(name); +} + +/* +** _PR_MD_PUT_ENV() -- add or change environment variable +** +** +*/ +PRIntn _PR_MD_PUT_ENV(const char *name) +{ + return(putenv(name)); +} + + +/* + ************************************************************************** + ************************************************************************** + ** + ** Date and time routines + ** + ************************************************************************** + ************************************************************************** + */ + +/* + *----------------------------------------------------------------------- + * + * PR_Now -- + * + * Returns the current time in microseconds since the epoch. + * The epoch is midnight January 1, 1970 GMT. + * The implementation is machine dependent. This is the + * implementation for Windows. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRTime) +PR_Now(void) +{ + PRTime prt; + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + _PR_FileTimeToPRTime(&ft, &prt); + return prt; +} + +/* + *********************************************************************** + *********************************************************************** + * + * Process creation routines + * + *********************************************************************** + *********************************************************************** + */ + +/* + * Assemble the command line by concatenating the argv array. + * On success, this function returns 0 and the resulting command + * line is returned in *cmdLine. On failure, it returns -1. + */ +static int assembleCmdLine(char *const *argv, char **cmdLine) +{ + char *const *arg; + char *p, *q; + size_t cmdLineSize; + int numBackslashes; + int i; + int argNeedQuotes; + + /* + * Find out how large the command line buffer should be. + */ + cmdLineSize = 0; + for (arg = argv; *arg; arg++) { + /* + * \ and " need to be escaped by a \. In the worst case, + * every character is a \ or ", so the string of length + * may double. If we quote an argument, that needs two ". + * Finally, we need a space between arguments, and + * a null byte at the end of command line. + */ + cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */ + + 2 /* we quote every argument */ + + 1; /* space in between, or final null */ + } + p = *cmdLine = PR_MALLOC((PRUint32) cmdLineSize); + if (p == NULL) { + return -1; + } + + for (arg = argv; *arg; arg++) { + /* Add a space to separates the arguments */ + if (arg != argv) { + *p++ = ' '; + } + q = *arg; + numBackslashes = 0; + argNeedQuotes = 0; + + /* + * If the argument is empty or contains white space, it needs to + * be quoted. + */ + if (**arg == '\0' || strpbrk(*arg, " \f\n\r\t\v")) { + argNeedQuotes = 1; + } + + if (argNeedQuotes) { + *p++ = '"'; + } + while (*q) { + if (*q == '\\') { + numBackslashes++; + q++; + } else if (*q == '"') { + if (numBackslashes) { + /* + * Double the backslashes since they are followed + * by a quote + */ + for (i = 0; i < 2 * numBackslashes; i++) { + *p++ = '\\'; + } + numBackslashes = 0; + } + /* To escape the quote */ + *p++ = '\\'; + *p++ = *q++; + } else { + if (numBackslashes) { + /* + * Backslashes are not followed by a quote, so + * don't need to double the backslashes. + */ + for (i = 0; i < numBackslashes; i++) { + *p++ = '\\'; + } + numBackslashes = 0; + } + *p++ = *q++; + } + } + + /* Now we are at the end of this argument */ + if (numBackslashes) { + /* + * Double the backslashes if we have a quote string + * delimiter at the end. + */ + if (argNeedQuotes) { + numBackslashes *= 2; + } + for (i = 0; i < numBackslashes; i++) { + *p++ = '\\'; + } + } + if (argNeedQuotes) { + *p++ = '"'; + } + } + + *p = '\0'; + return 0; +} + +/* + * Assemble the environment block by concatenating the envp array + * (preserving the terminating null byte in each array element) + * and adding a null byte at the end. + * + * Returns 0 on success. The resulting environment block is returned + * in *envBlock. Note that if envp is NULL, a NULL pointer is returned + * in *envBlock. Returns -1 on failure. + */ +static int assembleEnvBlock(char **envp, char **envBlock) +{ + char *p; + char *q; + char **env; + char *curEnv; + char *cwdStart, *cwdEnd; + size_t envBlockSize; + + if (envp == NULL) { + *envBlock = NULL; + return 0; + } + + curEnv = GetEnvironmentStrings(); + + cwdStart = curEnv; + while (*cwdStart) { + if (cwdStart[0] == '=' && cwdStart[1] != '\0' + && cwdStart[2] == ':' && cwdStart[3] == '=') { + break; + } + cwdStart += strlen(cwdStart) + 1; + } + cwdEnd = cwdStart; + if (*cwdEnd) { + cwdEnd += strlen(cwdEnd) + 1; + while (*cwdEnd) { + if (cwdEnd[0] != '=' || cwdEnd[1] == '\0' + || cwdEnd[2] != ':' || cwdEnd[3] != '=') { + break; + } + cwdEnd += strlen(cwdEnd) + 1; + } + } + envBlockSize = cwdEnd - cwdStart; + + for (env = envp; *env; env++) { + envBlockSize += strlen(*env) + 1; + } + envBlockSize++; + + p = *envBlock = PR_MALLOC((PRUint32) envBlockSize); + if (p == NULL) { + FreeEnvironmentStrings(curEnv); + return -1; + } + + q = cwdStart; + while (q < cwdEnd) { + *p++ = *q++; + } + FreeEnvironmentStrings(curEnv); + + for (env = envp; *env; env++) { + q = *env; + while (*q) { + *p++ = *q++; + } + *p++ = '\0'; + } + *p = '\0'; + return 0; +} + +/* + * For qsort. We sort (case-insensitive) the environment strings + * before generating the environment block. + */ +static int compare(const void *arg1, const void *arg2) +{ + return _stricmp(* (char**)arg1, * (char**)arg2); +} + +PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + STARTUPINFO startupInfo; + PROCESS_INFORMATION procInfo; + BOOL retVal; + char *cmdLine = NULL; + char *envBlock = NULL; + char **newEnvp = NULL; + const char *cwd = NULL; /* current working directory */ + PRProcess *proc = NULL; + PRBool hasFdInheritBuffer; + + proc = PR_NEW(PRProcess); + if (!proc) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + if (assembleCmdLine(argv, &cmdLine) == -1) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + /* + * If attr->fdInheritBuffer is not NULL, we need to insert + * it into the envp array, so envp cannot be NULL. + */ + hasFdInheritBuffer = (attr && attr->fdInheritBuffer); + if ((envp == NULL) && hasFdInheritBuffer) { + envp = environ; + } + + if (envp != NULL) { + int idx; + int numEnv; + PRBool found = PR_FALSE; + + numEnv = 0; + while (envp[numEnv]) { + numEnv++; + } + newEnvp = (char **) PR_MALLOC((numEnv + 2) * sizeof(char *)); + for (idx = 0; idx < numEnv; idx++) { + newEnvp[idx] = envp[idx]; + if (hasFdInheritBuffer && !found + && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) { + newEnvp[idx] = attr->fdInheritBuffer; + found = PR_TRUE; + } + } + if (hasFdInheritBuffer && !found) { + newEnvp[idx++] = attr->fdInheritBuffer; + } + newEnvp[idx] = NULL; + qsort((void *) newEnvp, (size_t) idx, sizeof(char *), compare); + } + if (assembleEnvBlock(newEnvp, &envBlock) == -1) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + ZeroMemory(&startupInfo, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + + if (attr) { + PRBool redirected = PR_FALSE; + + /* + * XXX the default value for stdin, stdout, and stderr + * should probably be the console input and output, not + * those of the parent process. + */ + startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if (attr->stdinFd) { + startupInfo.hStdInput = (HANDLE) attr->stdinFd->secret->md.osfd; + redirected = PR_TRUE; + } + if (attr->stdoutFd) { + startupInfo.hStdOutput = (HANDLE) attr->stdoutFd->secret->md.osfd; + redirected = PR_TRUE; + } + if (attr->stderrFd) { + startupInfo.hStdError = (HANDLE) attr->stderrFd->secret->md.osfd; + redirected = PR_TRUE; + } + if (redirected) { + startupInfo.dwFlags |= STARTF_USESTDHANDLES; + } + cwd = attr->currentDirectory; + } + + retVal = CreateProcess(NULL, + cmdLine, + NULL, /* security attributes for the new + * process */ + NULL, /* security attributes for the primary + * thread in the new process */ + TRUE, /* inherit handles */ + 0, /* creation flags */ + envBlock, /* an environment block, consisting + * of a null-terminated block of + * null-terminated strings. Each + * string is in the form: + * name=value + * XXX: usually NULL */ + cwd, /* current drive and directory */ + &startupInfo, + &procInfo + ); + if (retVal == FALSE) { + /* XXX what error code? */ + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + goto errorExit; + } + + CloseHandle(procInfo.hThread); + proc->md.handle = procInfo.hProcess; + proc->md.id = procInfo.dwProcessId; + + PR_DELETE(cmdLine); + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (envBlock) { + PR_DELETE(envBlock); + } + return proc; + +errorExit: + if (cmdLine) { + PR_DELETE(cmdLine); + } + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (envBlock) { + PR_DELETE(envBlock); + } + if (proc) { + PR_DELETE(proc); + } + return NULL; +} /* _PR_CreateWindowsProcess */ + +PRStatus _PR_DetachWindowsProcess(PRProcess *process) +{ + CloseHandle(process->md.handle); + PR_DELETE(process); + return PR_SUCCESS; +} + +/* + * XXX: This implementation is a temporary quick solution. + * It can be called by native threads only (not by fibers). + */ +PRStatus _PR_WaitWindowsProcess(PRProcess *process, + PRInt32 *exitCode) +{ + DWORD dwRetVal; + + dwRetVal = WaitForSingleObject(process->md.handle, INFINITE); + if (dwRetVal == WAIT_FAILED) { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } + PR_ASSERT(dwRetVal == WAIT_OBJECT_0); + if (exitCode != NULL && + GetExitCodeProcess(process->md.handle, exitCode) == FALSE) { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } + CloseHandle(process->md.handle); + PR_DELETE(process); + return PR_SUCCESS; +} + +PRStatus _PR_KillWindowsProcess(PRProcess *process) +{ + /* + * On Unix, if a process terminates normally, its exit code is + * between 0 and 255. So here on Windows, we use the exit code + * 256 to indicate that the process is killed. + */ + if (TerminateProcess(process->md.handle, 256)) { + return PR_SUCCESS; + } + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; +} + +PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen) +{ + PRIntn rv; + PRInt32 syserror; + + rv = gethostname(name, (PRInt32) namelen); + if (0 == rv) { + return PR_SUCCESS; + } + syserror = WSAGetLastError(); + PR_ASSERT(WSANOTINITIALISED != syserror); + _PR_MD_MAP_GETHOSTNAME_ERROR(syserror); + return PR_FAILURE; +} + +PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen) +{ + OSVERSIONINFO osvi; + + PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE)); + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if (! GetVersionEx (&osvi) ) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + + switch (osvi.dwPlatformId) { + case VER_PLATFORM_WIN32_NT: + if (PR_SI_SYSNAME == cmd) + (void)PR_snprintf(name, namelen, "Windows_NT"); + else if (PR_SI_RELEASE == cmd) + (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, + osvi.dwMinorVersion); + break; + case VER_PLATFORM_WIN32_WINDOWS: + if (PR_SI_SYSNAME == cmd) { + if ((osvi.dwMajorVersion > 4) || + ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion > 0))) + (void)PR_snprintf(name, namelen, "Windows_98"); + else + (void)PR_snprintf(name, namelen, "Windows_95"); + } else if (PR_SI_RELEASE == cmd) { + (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, + osvi.dwMinorVersion); + } + break; + default: + if (PR_SI_SYSNAME == cmd) + (void)PR_snprintf(name, namelen, "Windows_Unknown"); + else if (PR_SI_RELEASE == cmd) + (void)PR_snprintf(name, namelen, "%d.%d",0,0); + break; + } + return PR_SUCCESS; +} + +PRStatus _MD_WindowsGetReleaseName(char *name, PRUint32 namelen) +{ + OSVERSIONINFO osvi; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if (! GetVersionEx (&osvi) ) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + + switch (osvi.dwPlatformId) { + case VER_PLATFORM_WIN32_NT: + case VER_PLATFORM_WIN32_WINDOWS: + (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, + osvi.dwMinorVersion); + break; + default: + (void)PR_snprintf(name, namelen, "%d.%d",0,0); + break; + } + return PR_SUCCESS; +} + +/* + ********************************************************************** + * + * Memory-mapped files + * + ********************************************************************** + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ + DWORD dwHi, dwLo; + DWORD flProtect; + PROsfd osfd; + + osfd = ( fmap->fd == (PRFileDesc*)-1 )? -1 : fmap->fd->secret->md.osfd; + + dwLo = (DWORD) (size & 0xffffffff); + dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff); + + if (fmap->prot == PR_PROT_READONLY) { + flProtect = PAGE_READONLY; + fmap->md.dwAccess = FILE_MAP_READ; + } else if (fmap->prot == PR_PROT_READWRITE) { + flProtect = PAGE_READWRITE; + fmap->md.dwAccess = FILE_MAP_WRITE; + } else { + PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY); + flProtect = PAGE_WRITECOPY; + fmap->md.dwAccess = FILE_MAP_COPY; + } + + fmap->md.hFileMap = CreateFileMapping( + (HANDLE) osfd, + NULL, + flProtect, + dwHi, + dwLo, + NULL); + + if (fmap->md.hFileMap == NULL) { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRInt32 _MD_GetMemMapAlignment(void) +{ + SYSTEM_INFO info; + GetSystemInfo(&info); + return info.dwAllocationGranularity; +} + +extern PRLogModuleInfo *_pr_shma_lm; + +void * _MD_MemMap( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len) +{ + DWORD dwHi, dwLo; + void *addr; + + dwLo = (DWORD) (offset & 0xffffffff); + dwHi = (DWORD) (((PRUint64) offset >> 32) & 0xffffffff); + if ((addr = MapViewOfFile(fmap->md.hFileMap, fmap->md.dwAccess, + dwHi, dwLo, len)) == NULL) { + { + LPVOID lpMsgBuf; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, ("md_memmap(): %s", lpMsgBuf )); + } + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + } + return addr; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ + if (UnmapViewOfFile(addr)) { + return PR_SUCCESS; + } else { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ + CloseHandle(fmap->md.hFileMap); + PR_DELETE(fmap); + return PR_SUCCESS; +} + +/* + *********************************************************************** + * + * Atomic increment and decrement operations for x86 processors + * + * We don't use InterlockedIncrement and InterlockedDecrement + * because on NT 3.51 and Win95, they return a number with + * the same sign as the incremented/decremented result, rather + * than the result itself. On NT 4.0 these functions do return + * the incremented/decremented result. + * + * The result is returned in the eax register by the inline + * assembly code. We disable the harmless "no return value" + * warning (4035) for these two functions. + * + *********************************************************************** + */ + +#if defined(_M_IX86) || defined(_X86_) + +#pragma warning(disable: 4035) +PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ +#if defined(__GNUC__) + PRInt32 result; + asm volatile ("lock ; xadd %0, %1" + : "=r"(result), "=m"(*val) + : "0"(1), "m"(*val)); + return result + 1; +#else + __asm + { + mov ecx, val + mov eax, 1 + lock xadd dword ptr [ecx], eax + inc eax + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#pragma warning(disable: 4035) +PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ +#if defined(__GNUC__) + PRInt32 result; + asm volatile ("lock ; xadd %0, %1" + : "=r"(result), "=m"(*val) + : "0"(-1), "m"(*val)); + //asm volatile("lock ; xadd %0, %1" : "=m" (val), "=a" (result) : "-1" (1)); + return result - 1; +#else + __asm + { + mov ecx, val + mov eax, 0ffffffffh + lock xadd dword ptr [ecx], eax + dec eax + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#pragma warning(disable: 4035) +PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *intp, PRInt32 val) +{ +#if defined(__GNUC__) + PRInt32 result; + //asm volatile("lock ; xadd %1, %0" : "=m" (intp), "=a" (result) : "1" (val)); + asm volatile ("lock ; xadd %0, %1" + : "=r"(result), "=m"(*intp) + : "0"(val), "m"(*intp)); + return result + val; +#else + __asm + { + mov ecx, intp + mov eax, val + mov edx, eax + lock xadd dword ptr [ecx], eax + add eax, edx + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#ifdef _PR_HAVE_ATOMIC_CAS + +#pragma warning(disable: 4035) +void +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ +#if defined(__GNUC__) + void **tos = (void **) stack; + void *tmp; + + retry: + if (*tos == (void *) -1) + goto retry; + + __asm__("xchg %0,%1" + : "=r" (tmp), "=m"(*tos) + : "0" (-1), "m"(*tos)); + + if (tmp == (void *) -1) + goto retry; + + *(void **)stack_elem = tmp; + __asm__("" : : : "memory"); + *tos = stack_elem; +#else + __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 + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#pragma warning(disable: 4035) +PRStackElem * +PR_StackPop(PRStack *stack) +{ +#if defined(__GNUC__) + void **tos = (void **) stack; + void *tmp; + + retry: + if (*tos == (void *) -1) + goto retry; + + __asm__("xchg %0,%1" + : "=r" (tmp), "=m"(*tos) + : "0" (-1), "m"(*tos)); + + if (tmp == (void *) -1) + goto retry; + + if (tmp != (void *) 0) + { + void *next = *(void **)tmp; + *tos = next; + *(void **)tmp = 0; + } + else + *tos = tmp; + + return tmp; +#else + __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: + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#endif /* _PR_HAVE_ATOMIC_CAS */ + +#endif /* x86 processors */ diff --git a/nsprpub/pr/src/md/windows/ntsec.c b/nsprpub/pr/src/md/windows/ntsec.c new file mode 100644 index 00000000000..89ac1dfbc9e --- /dev/null +++ b/nsprpub/pr/src/md/windows/ntsec.c @@ -0,0 +1,279 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/* + * ntsec.c + * + * Implement the POSIX-style mode bits (access permissions) for + * files and other securable objects in Windows NT using Windows + * NT's security descriptors with appropriate discretionary + * access-control lists. + */ + +/* + * The security identifiers (SIDs) for owner, primary group, + * and the Everyone (World) group. + * + * These SIDs are looked up during NSPR initialization and + * saved in this global structure (see _PR_NT_InitSids) so + * that _PR_NT_MakeSecurityDescriptorACL doesn't need to + * look them up every time. + */ +static struct { + PSID owner; + PSID group; + PSID everyone; +} _pr_nt_sids; + +/* + * Initialize the SIDs for owner, primary group, and the Everyone + * group in the _pr_nt_sids structure. + * + * This function needs to be called by NSPR initialization. + */ +void _PR_NT_InitSids(void) +{ + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; + HANDLE hToken = NULL; /* initialized to an arbitrary value to + * silence a Purify UMR warning */ + UCHAR infoBuffer[1024]; + PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) infoBuffer; + PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup + = (PTOKEN_PRIMARY_GROUP) infoBuffer; + DWORD dwLength; + BOOL rv; + + /* + * Look up and make a copy of the owner and primary group + * SIDs in the access token of the calling process. + */ + rv = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); + if (rv == 0) { + /* + * On non-NT systems, this function is not implemented + * (error code ERROR_CALL_NOT_IMPLEMENTED), and neither are + * the other security functions. There is no point in + * going further. + * + * A process with insufficient access permissions may fail + * with the error code ERROR_ACCESS_DENIED. + */ + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("_PR_NT_InitSids: OpenProcessToken() failed. Error: %d", + GetLastError())); + return; + } + + rv = GetTokenInformation(hToken, TokenOwner, infoBuffer, + sizeof(infoBuffer), &dwLength); + PR_ASSERT(rv != 0); + dwLength = GetLengthSid(pTokenOwner->Owner); + _pr_nt_sids.owner = (PSID) PR_Malloc(dwLength); + PR_ASSERT(_pr_nt_sids.owner != NULL); + rv = CopySid(dwLength, _pr_nt_sids.owner, pTokenOwner->Owner); + PR_ASSERT(rv != 0); + + rv = GetTokenInformation(hToken, TokenPrimaryGroup, infoBuffer, + sizeof(infoBuffer), &dwLength); + PR_ASSERT(rv != 0); + dwLength = GetLengthSid(pTokenPrimaryGroup->PrimaryGroup); + _pr_nt_sids.group = (PSID) PR_Malloc(dwLength); + PR_ASSERT(_pr_nt_sids.group != NULL); + rv = CopySid(dwLength, _pr_nt_sids.group, + pTokenPrimaryGroup->PrimaryGroup); + PR_ASSERT(rv != 0); + + rv = CloseHandle(hToken); + PR_ASSERT(rv != 0); + + /* Create a well-known SID for the Everyone group. */ + rv = AllocateAndInitializeSid(&SIDAuthWorld, 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &_pr_nt_sids.everyone); + PR_ASSERT(rv != 0); +} + +/* + * Free the SIDs for owner, primary group, and the Everyone group + * in the _pr_nt_sids structure. + * + * This function needs to be called by NSPR cleanup. + */ +void +_PR_NT_FreeSids(void) +{ + if (_pr_nt_sids.owner) { + PR_Free(_pr_nt_sids.owner); + } + if (_pr_nt_sids.group) { + PR_Free(_pr_nt_sids.group); + } + if (_pr_nt_sids.everyone) { + FreeSid(_pr_nt_sids.everyone); + } +} + +/* + * Construct a security descriptor whose discretionary access-control + * list implements the specified mode bits. The SIDs for owner, group, + * and everyone are obtained from the global _pr_nt_sids structure. + * Both the security descriptor and access-control list are returned + * and should be freed by a _PR_NT_FreeSecurityDescriptorACL call. + * + * The accessTable array maps NSPR's read, write, and execute access + * rights to the corresponding NT access rights for the securable + * object. + */ +PRStatus +_PR_NT_MakeSecurityDescriptorACL( + PRIntn mode, + DWORD accessTable[], + PSECURITY_DESCRIPTOR *resultSD, + PACL *resultACL) +{ + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + DWORD cbACL; /* size of ACL */ + DWORD accessMask; + + if (_pr_nt_sids.owner == NULL) { + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; + } + + pSD = (PSECURITY_DESCRIPTOR) PR_Malloc(SECURITY_DESCRIPTOR_MIN_LENGTH); + if (pSD == NULL) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + if (!SetSecurityDescriptorOwner(pSD, _pr_nt_sids.owner, FALSE)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + if (!SetSecurityDescriptorGroup(pSD, _pr_nt_sids.group, FALSE)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + + /* + * Construct a discretionary access-control list with three + * access-control entries, one each for owner, primary group, + * and Everyone. + */ + + cbACL = sizeof(ACL) + + 3 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + + GetLengthSid(_pr_nt_sids.owner) + + GetLengthSid(_pr_nt_sids.group) + + GetLengthSid(_pr_nt_sids.everyone); + pACL = (PACL) PR_Malloc(cbACL); + if (pACL == NULL) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + accessMask = 0; + if (mode & 00400) accessMask |= accessTable[0]; + if (mode & 00200) accessMask |= accessTable[1]; + if (mode & 00100) accessMask |= accessTable[2]; + if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, + _pr_nt_sids.owner)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + accessMask = 0; + if (mode & 00040) accessMask |= accessTable[0]; + if (mode & 00020) accessMask |= accessTable[1]; + if (mode & 00010) accessMask |= accessTable[2]; + if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, + _pr_nt_sids.group)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + accessMask = 0; + if (mode & 00004) accessMask |= accessTable[0]; + if (mode & 00002) accessMask |= accessTable[1]; + if (mode & 00001) accessMask |= accessTable[2]; + if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, + _pr_nt_sids.everyone)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + + if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + + *resultSD = pSD; + *resultACL = pACL; + return PR_SUCCESS; + +failed: + if (pSD) { + PR_Free(pSD); + } + if (pACL) { + PR_Free(pACL); + } + return PR_FAILURE; +} + +/* + * Free the specified security descriptor and access-control list + * previously created by _PR_NT_MakeSecurityDescriptorACL. + */ +void +_PR_NT_FreeSecurityDescriptorACL(PSECURITY_DESCRIPTOR pSD, PACL pACL) +{ + if (pSD) { + PR_Free(pSD); + } + if (pACL) { + PR_Free(pACL); + } +} diff --git a/nsprpub/pr/src/md/windows/ntsem.c b/nsprpub/pr/src/md/windows/ntsem.c new file mode 100644 index 00000000000..b25fac6200a --- /dev/null +++ b/nsprpub/pr/src/md/windows/ntsem.c @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * NT-specific semaphore handling code. + * + */ + + +#include "primpl.h" + + +void +_PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value) +{ + md->sem = CreateSemaphore(NULL, value, 0x7fffffff, NULL); +} + +void +_PR_MD_DESTROY_SEM(_MDSemaphore *md) +{ + CloseHandle(md->sem); +} + +PRStatus +_PR_MD_TIMED_WAIT_SEM(_MDSemaphore *md, PRIntervalTime ticks) +{ + int rv; + + rv = WaitForSingleObject(md->sem, PR_IntervalToMilliseconds(ticks)); + + if (rv == WAIT_OBJECT_0) + return PR_SUCCESS; + else + return PR_FAILURE; +} + +PRStatus +_PR_MD_WAIT_SEM(_MDSemaphore *md) +{ + return _PR_MD_TIMED_WAIT_SEM(md, PR_INTERVAL_NO_TIMEOUT); +} + +void +_PR_MD_POST_SEM(_MDSemaphore *md) +{ + int old_count; + + ReleaseSemaphore(md->sem, 1, &old_count); +} diff --git a/nsprpub/pr/src/md/windows/ntthread.c b/nsprpub/pr/src/md/windows/ntthread.c new file mode 100644 index 00000000000..4c8fa62439f --- /dev/null +++ b/nsprpub/pr/src/md/windows/ntthread.c @@ -0,0 +1,560 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include /* for _beginthreadex() */ + +/* --- globals ------------------------------------------------ */ +PRLock *_pr_schedLock = NULL; +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; + +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; +DWORD _pr_currentFiberIndex; +DWORD _pr_lastFiberIndex; +DWORD _pr_currentCPUIndex; +DWORD _pr_intsOffIndex; + +_MDLock _nt_idleLock; +PRCList _nt_idleList; +PRUint32 _nt_idleCount; + +extern __declspec(thread) PRThread *_pr_io_restarted_io; +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 = \ + (_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) +{ + /* After the switch we can resume an IO if needed. + * XXXMB - this needs to be done in create thread, since that could + * be the result for a context switch too.. + */ + PR_ASSERT(restarted_io->io_suspended == PR_TRUE); + PR_ASSERT(restarted_io->md.thr_bound_cpu == restarted_io->cpu); + + _PR_THREAD_LOCK(restarted_io); + if (restarted_io->io_pending == PR_FALSE) { + + /* The IO already completed, put us back on the runq. */ + int pri = restarted_io->priority; + + restarted_io->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(restarted_io->cpu); + _PR_ADD_RUNQ(restarted_io, restarted_io->cpu, pri); + _PR_RUNQ_UNLOCK(restarted_io->cpu); + } else { + _PR_SLEEPQ_LOCK(restarted_io->cpu); + _PR_ADD_SLEEPQ(restarted_io, restarted_io->sleep); + _PR_SLEEPQ_UNLOCK(restarted_io->cpu); + } + restarted_io->io_suspended = PR_FALSE; + restarted_io->md.thr_bound_cpu = NULL; + + _PR_THREAD_UNLOCK(restarted_io); + + if (_pr_use_static_tls) { + _pr_io_restarted_io = NULL; + } else { + TlsSetValue(_pr_io_restartedIOIndex, NULL); + } +} + +void +_PR_MD_EARLY_INIT() +{ + _MD_NEW_LOCK( &_nt_idleLock ); + _nt_idleCount = 0; + PR_INIT_CLIST(&_nt_idleList); + +#if 0 + /* Make the clock tick at least once per millisecond */ + if ( timeBeginPeriod(1) == TIMERR_NOCANDO) { + /* deep yoghurt; clock doesn't tick fast enough! */ + PR_ASSERT(0); + } +#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) +{ + _PR_NT_FreeSids(); + + WSACleanup(); + + if (!_pr_use_static_tls) { + TlsFree(_pr_currentFiberIndex); + TlsFree(_pr_lastFiberIndex); + TlsFree(_pr_currentCPUIndex); + TlsFree(_pr_intsOffIndex); + TlsFree(_pr_io_restartedIOIndex); + } +} + +PRStatus +_PR_MD_INIT_THREAD(PRThread *thread) +{ + thread->md.overlapped.ioModel = _MD_BlockingIO; + thread->md.overlapped.data.mdThread = &thread->md; + + if (thread->flags & _PR_GLOBAL_SCOPE) { + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + /* + ** Warning: + ** -------- + ** NSPR requires a real handle to every thread. + ** GetCurrentThread() returns a pseudo-handle which + ** is not suitable for some thread operations (e.g., + ** suspending). Therefore, get a real handle from + ** the pseudo handle via DuplicateHandle(...) + */ + DuplicateHandle( + GetCurrentProcess(), /* Process of source handle */ + GetCurrentThread(), /* Pseudo Handle to dup */ + GetCurrentProcess(), /* Process of handle */ + &(thread->md.handle), /* resulting handle */ + 0L, /* access flags */ + FALSE, /* Inheritable */ + DUPLICATE_SAME_ACCESS); /* Options */ + } + + /* Create the blocking IO semaphore */ + thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL); + if (thread->md.blocked_sema == NULL) { + return PR_FAILURE; + } + if (_native_threads_only) { + /* Create the blocking IO semaphore */ + thread->md.thr_event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (thread->md.thr_event == NULL) { + return PR_FAILURE; + } + } + } + + return PR_SUCCESS; +} + +static unsigned __stdcall +pr_root(void *arg) +{ + PRThread *thread = (PRThread *)arg; + thread->md.start(thread); + return 0; +} + +PRStatus +_PR_MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + + thread->md.start = start; + thread->md.handle = (HANDLE) _beginthreadex( + NULL, + thread->stack->stackSize, + pr_root, + (void *)thread, + CREATE_SUSPENDED, + &(thread->id)); + if(!thread->md.handle) { + PRErrorCode prerror; + thread->md.fiber_last_error = GetLastError(); + switch (errno) { + case ENOMEM: + prerror = PR_OUT_OF_MEMORY_ERROR; + break; + case EAGAIN: + prerror = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, errno); + return PR_FAILURE; + } + + thread->md.id = thread->id; + /* + * On windows, a thread is created with a thread priority of + * THREAD_PRIORITY_NORMAL. + */ + if (priority != PR_PRIORITY_NORMAL) { + _PR_MD_SET_PRIORITY(&(thread->md), priority); + } + + /* Activate the thread */ + if ( ResumeThread( thread->md.handle ) != -1) + return PR_SUCCESS; + + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; +} + +void +_PR_MD_JOIN_THREAD(_MDThread *md) +{ + DWORD rv; + + rv = WaitForSingleObject(md->handle, INFINITE); + PR_ASSERT(WAIT_OBJECT_0 == rv); +} + +void +_PR_MD_END_THREAD(void) +{ + _endthreadex(0); +} + +void +_PR_MD_YIELD(void) +{ + /* Can NT really yield at all? */ + Sleep(0); +} + +void +_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) +{ + int nativePri; + BOOL rv; + + if (newPri < PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } else if (newPri > PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } + switch (newPri) { + case PR_PRIORITY_LOW: + nativePri = THREAD_PRIORITY_BELOW_NORMAL; + break; + case PR_PRIORITY_NORMAL: + nativePri = THREAD_PRIORITY_NORMAL; + break; + case PR_PRIORITY_HIGH: + nativePri = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case PR_PRIORITY_URGENT: + nativePri = THREAD_PRIORITY_HIGHEST; + } + rv = SetThreadPriority(thread->handle, nativePri); + PR_ASSERT(rv); + if (!rv) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: can't set thread priority\n")); + } + return; +} + +void +_PR_MD_CLEAN_THREAD(PRThread *thread) +{ + BOOL rv; + + if (thread->md.acceptex_buf) { + PR_DELETE(thread->md.acceptex_buf); + } + + if (thread->md.xmit_bufs) { + PR_DELETE(thread->md.xmit_bufs); + } + + if (thread->md.blocked_sema) { + rv = CloseHandle(thread->md.blocked_sema); + PR_ASSERT(rv); + thread->md.blocked_sema = 0; + } + if (_native_threads_only) { + if (thread->md.thr_event) { + rv = CloseHandle(thread->md.thr_event); + PR_ASSERT(rv); + thread->md.thr_event = 0; + } + } + + if (thread->md.handle) { + rv = CloseHandle(thread->md.handle); + PR_ASSERT(rv); + thread->md.handle = 0; + } + + /* Don't call DeleteFiber on current fiber or we'll kill the whole thread. + * Don't call free(thread) until we've switched off the thread. + * So put this fiber (or thread) on a list to be deleted by the idle + * fiber next time we have a chance. + */ + if (!(thread->flags & (_PR_ATTACHED|_PR_GLOBAL_SCOPE))) { + _MD_LOCK(&_nt_idleLock); + _nt_idleCount++; + PR_APPEND_LINK(&thread->links, &_nt_idleList); + _MD_UNLOCK(&_nt_idleLock); + } +} + +void +_PR_MD_EXIT_THREAD(PRThread *thread) +{ + BOOL rv; + + if (thread->md.acceptex_buf) { + PR_DELETE(thread->md.acceptex_buf); + } + + if (thread->md.xmit_bufs) { + PR_DELETE(thread->md.xmit_bufs); + } + + if (thread->md.blocked_sema) { + rv = CloseHandle(thread->md.blocked_sema); + PR_ASSERT(rv); + thread->md.blocked_sema = 0; + } + + if (_native_threads_only) { + if (thread->md.thr_event) { + rv = CloseHandle(thread->md.thr_event); + PR_ASSERT(rv); + thread->md.thr_event = 0; + } + } + + if (thread->md.handle) { + rv = CloseHandle(thread->md.handle); + PR_ASSERT(rv); + thread->md.handle = 0; + } + + if (thread->flags & _PR_GLOBAL_SCOPE) { + _MD_SET_CURRENT_THREAD(NULL); + } +} + + +void +_PR_MD_EXIT(PRIntn status) +{ + _exit(status); +} + +#ifdef HAVE_FIBERS + +void +_pr_fiber_mainline(void *unused) +{ + PRThread *fiber = _PR_MD_CURRENT_THREAD(); + + POST_SWITCH_WORK(); + + fiber->md.fiber_fn(fiber->md.fiber_arg); +} + +PRThread *_PR_MD_CREATE_USER_THREAD( + PRUint32 stacksize, void (*start)(void *), void *arg) +{ + PRThread *thread; + + if ( (thread = PR_NEW(PRThread)) == NULL ) { + return NULL; + } + + memset(thread, 0, sizeof(PRThread)); + thread->md.fiber_fn = start; + thread->md.fiber_arg = arg; + thread->md.fiber_stacksize = stacksize; + return thread; +} + +void +_PR_MD_CREATE_PRIMORDIAL_USER_THREAD(PRThread *thread) +{ + thread->md.fiber_id = ConvertThreadToFiber(NULL); + PR_ASSERT(thread->md.fiber_id); + _MD_SET_CURRENT_THREAD(thread); + _MD_SET_LAST_THREAD(thread); + thread->no_sched = 1; + return; +} + +void +_PR_MD_INIT_CONTEXT(PRThread *thread, char *top, void (*start) (void), PRBool *status) +{ + thread->md.fiber_fn = (void (*)(void *))start; + thread->md.fiber_id = CreateFiber(thread->md.fiber_stacksize, + (LPFIBER_START_ROUTINE)_pr_fiber_mainline, NULL); + if (thread->md.fiber_id != 0) + *status = PR_TRUE; + else { + DWORD oserror = GetLastError(); + PRErrorCode prerror; + if (oserror == ERROR_NOT_ENOUGH_MEMORY) { + prerror = PR_OUT_OF_MEMORY_ERROR; + } else { + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, oserror); + *status = PR_FALSE; + } +} + +void +_PR_MD_SWITCH_CONTEXT(PRThread *thread) +{ + PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); + + thread->md.fiber_last_error = GetLastError(); + _PR_Schedule(); +} + +void +_PR_MD_RESTORE_CONTEXT(PRThread *thread) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); + + /* The user-level code for yielding will happily add ourselves to the runq + * and then switch to ourselves; the NT fibers can't handle switching to + * ourselves. + */ + if (thread != me) { + SetLastError(thread->md.fiber_last_error); + _MD_SET_CURRENT_THREAD(thread); + _PR_MD_SET_LAST_THREAD(me); + thread->no_sched = 1; + SwitchToFiber(thread->md.fiber_id); + POST_SWITCH_WORK(); + } +} + + +#endif /* HAVE_FIBERS */ + +PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) +{ + int rv; + + rv = SetThreadAffinityMask(thread->md.handle, mask); + + return rv?0:-1; +} + +PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) +{ + PRInt32 rv, system_mask; + + rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask); + + return rv?0:-1; +} + +void +_PR_MD_SUSPEND_CPU(_PRCPU *cpu) +{ + _PR_MD_SUSPEND_THREAD(cpu->thread); +} + +void +_PR_MD_RESUME_CPU(_PRCPU *cpu) +{ + _PR_MD_RESUME_THREAD(cpu->thread); +} + +void +_PR_MD_SUSPEND_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + /* + ** There seems to be some doubt about whether or not SuspendThread + ** is a synchronous function. The test afterwards is to help veriry + ** that it is, which is what Microsoft says it is. + */ + PRUintn rv = SuspendThread(thread->md.handle); + PR_ASSERT(0xffffffffUL != rv); + } +} + +void +_PR_MD_RESUME_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + ResumeThread(thread->md.handle); + } +} + +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/nsprpub/pr/src/md/windows/objs.mk b/nsprpub/pr/src/md/windows/objs.mk new file mode 100644 index 00000000000..36f21a443cf --- /dev/null +++ b/nsprpub/pr/src/md/windows/objs.mk @@ -0,0 +1,94 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +ifeq ($(OS_TARGET),WINNT) +CSRCS = ntmisc.c \ + ntsec.c \ + ntsem.c \ + ntinrval.c \ + ntgc.c \ + ntio.c \ + ntthread.c \ + ntdllmn.c \ + win32_errors.c \ + w32ipcsem.c \ + w32poll.c \ + w32rng.c \ + w32shm.c +else +ifeq ($(OS_TARGET),WIN95) +CSRCS = ntmisc.c \ + ntsec.c \ + ntsem.c \ + ntinrval.c \ + ntgc.c \ + w95thred.c \ + w95io.c \ + w95cv.c \ + w95sock.c \ + win32_errors.c \ + w32ipcsem.c \ + w32poll.c \ + w32rng.c \ + w32shm.c \ + w95dllmain.c +else +ifeq ($(OS_TARGET),WIN16) +CSRCS = w16null.c \ + w16thred.c \ + w16proc.c \ + w16fmem.c \ + w16sock.c \ + w16mem.c \ + w16io.c \ + w16gc.c \ + w16error.c \ + w16stdio.c \ + w16callb.c \ + ntinrval.c +endif # win16 +endif # win95 +endif # winnt + +CSRCS += $(PR_MD_CSRCS) +ASFILES += $(PR_MD_ASFILES) + +OBJS += $(addprefix md/windows/$(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix md/windows/$(OBJDIR)/,$(ASFILES:.s=.$(OBJ_SUFFIX))) + + diff --git a/nsprpub/pr/src/md/windows/w16callb.c b/nsprpub/pr/src/md/windows/w16callb.c new file mode 100644 index 00000000000..3f7b4eeae79 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16callb.c @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** w16callb.c -- Implement Win16 Callback functions +** +** Functions here are to replace functions normally in +** LIBC which are not implemented in MSVC's LIBC. +** Some clients of NSPR expect to statically link +** to NSPR and get these functions. +** +** Some are implemented as callbacks to the .EXE +** some are implemented directly in this module. +** +*/ + +#include "primpl.h" +#include "windowsx.h" + +/* +** _pr_callback_funcs -- This is where clients register the +** callback function structure. +*/ +struct PRMethodCallbackStr * _pr_callback_funcs; + +/* +** PR_MDInitWin16() -- Register the PRMethodCallback table pointer +** +*/ +void PR_MDRegisterCallbacks(struct PRMethodCallbackStr *f) +{ + _pr_callback_funcs = f; +} + +/* +** NSPR re-implenentations of various C runtime functions: +*/ + +/* +** PR_MD_printf() -- exported as printf() +** +*/ +int PR_MD_printf(const char *fmt, ...) +{ + char buffer[1024]; + int ret = 0; + va_list args; + + va_start(args, fmt); + +#ifdef DEBUG + PR_vsnprintf(buffer, sizeof(buffer), fmt, args); + { + if (_pr_callback_funcs != NULL && _pr_callback_funcs->auxOutput != NULL) { + (* _pr_callback_funcs->auxOutput)(buffer); + } else { + OutputDebugString(buffer); + } + } +#endif + + va_end(args); + return ret; +} + +/* +** PR_MD_sscanf() -- exported as sscanf() +** +*/ +int PR_MD_sscanf(const char *buf, const char *fmt, ...) +{ + int retval; + va_list arglist; + + va_start(arglist, fmt); + retval = vsscanf((const unsigned char *)buf, (const unsigned char *)fmt, arglist); + va_end(arglist); + return retval; +} + +/* +** PR_MD_strftime() -- exported as strftime +** +*/ +size_t PR_MD_strftime(char *s, size_t len, const char *fmt, const struct tm *p) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->strftime)(s, len, fmt, p); + } else { + PR_ASSERT(0); + return 0; + } +} + + +/* +** PR_MD_malloc() -- exported as malloc() +** +*/ +void *PR_MD_malloc( size_t size ) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->malloc)( size ); + } else { + return GlobalAllocPtr(GPTR, (DWORD)size); + } +} /* end malloc() */ + +/* +** PR_MD_calloc() -- exported as calloc() +** +*/ +void *PR_MD_calloc( size_t n, size_t size ) +{ + void *p; + size_t sz; + + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->calloc)( n, size ); + } else { + sz = n * size; + p = GlobalAllocPtr(GPTR, (DWORD)sz ); + memset( p, 0x00, sz ); + return p; + } +} /* end calloc() */ + +/* +** PR_MD_realloc() -- exported as realloc() +** +*/ +void *PR_MD_realloc( void* old_blk, size_t size ) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->realloc)( old_blk, size ); + } else { + return GlobalReAllocPtr( old_blk, (DWORD)size, GPTR); + } +} /* end realloc */ + +/* +** PR_MD_free() -- exported as free() +** +*/ +void PR_MD_free( void *ptr ) +{ + if( _pr_callback_funcs ) { + (*_pr_callback_funcs->free)( ptr ); + return; + } else { + GlobalFreePtr( ptr ); + return; + } +} /* end free() */ + +/* +** PR_MD_getenv() -- exported as getenv() +** +*/ +char *PR_MD_getenv( const char *name ) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->getenv)( name ); + } else { + return 0; + } +} /* end getenv() */ + + +/* +** PR_MD_perror() -- exported as perror() +** +** well, not really (lth. 12/5/97). +** XXX hold this thought. +** +*/ +void PR_MD_perror( const char *prefix ) +{ + return; +} /* end perror() */ + +/* +** PR_MD_putenv() -- exported as putenv() +** +*/ +int PR_MD_putenv(const char *assoc) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->putenv)(assoc); + } else { + PR_ASSERT(0); + return NULL; + } +} + +/* +** PR_MD_fprintf() -- exported as fprintf() +** +*/ +int PR_MD_fprintf(FILE *fPtr, const char *fmt, ...) +{ + char buffer[1024]; + va_list args; + + va_start(args, fmt); + PR_vsnprintf(buffer, sizeof(buffer), fmt, args); + + if (fPtr == NULL) + { + if (_pr_callback_funcs != NULL && _pr_callback_funcs->auxOutput != NULL) + { + (* _pr_callback_funcs->auxOutput)(buffer); + } + else + { + OutputDebugString(buffer); + } + } + else + { + fwrite(buffer, 1, strlen(buffer), fPtr); /* XXX Is this a sec. hole? */ + } + + va_end(args); + return 0; +} + +/* end w16callb.c */ diff --git a/nsprpub/pr/src/md/windows/w16error.c b/nsprpub/pr/src/md/windows/w16error.c new file mode 100644 index 00000000000..72d1725b318 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16error.c @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Note: A single error mapping function is provided. +** +*/ +#include "prerror.h" +#include +#include + + +void _PR_MD_map_error( int err ) +{ + + switch ( err ) + { + case ENOENT: /* No such file or directory */ + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case E2BIG: /* Argument list too big */ + PR_SetError( PR_INVALID_ARGUMENT_ERROR, err ); + break; + case ENOEXEC: /* Exec format error */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EBADF: /* Bad file number */ + PR_SetError( PR_BAD_DESCRIPTOR_ERROR, err ); + break; + case ENOMEM: /* Not enough Memory */ + PR_SetError( PR_OUT_OF_MEMORY_ERROR, err ); + break; + case EACCES: /* Permission denied */ + PR_SetError( PR_NO_ACCESS_RIGHTS_ERROR, err ); + break; + case EEXIST: /* File exists */ + + /* RESTART here */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EXDEV: /* Cross device link */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EINVAL: /* Invalid argument */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENFILE: /* File table overflow */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EMFILE: /* Too many open files */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOSPC: /* No space left on device */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + /* math errors */ + case EDOM: /* Argument too large */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ERANGE: /* Result too large */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + /* file locking error */ + case EDEADLK: /* Resource deadlock would occur */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EINTR: /* Interrupt */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ECHILD: /* Child does not exist */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + /* POSIX errors */ + case EAGAIN: /* Resource unavailable, try again */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EBUSY: /* Device or Resource is busy */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EFBIG: /* File too large */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EIO: /* I/O error */ + PR_SetError( PR_IO_ERROR, err ); + break; + case EISDIR: /* Is a directory */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOTDIR: /* Not a directory */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EMLINK: /* Too many links */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOTBLK: /* Block device required */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOTTY: /* Not a character device */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENXIO: /* No such device or address */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EPERM: /* Not owner */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EPIPE: /* Broken pipe */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EROFS: /* Read only file system */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ESPIPE: /* Illegal seek */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ESRCH: /* No such process */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ETXTBSY: /* Text file busy */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EFAULT: /* Bad address */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENAMETOOLONG: /* Name too long */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENODEV: /* No such device */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOLCK: /* No locks available on system */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOSYS: /* Unknown system call */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOTEMPTY: /* Directory not empty */ + /* Normative Addendum error */ + case EILSEQ: /* Multibyte/widw character encoding error */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + + /* WinSock errors */ + case WSAEACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case WSAEADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case WSAEADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case WSAEAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case WSAEBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case WSAECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case WSAEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case WSAEINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case WSAEISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case WSAEMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case WSAENETDOWN: + case WSAENETUNREACH: + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err); + break; + case WSAENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case WSAENOPROTOOPT: + case WSAEMSGSIZE: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case WSAENOTCONN: + PR_SetError(PR_NOT_CONNECTED_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 WSAEPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case WSAETIMEDOUT: + PR_SetError(PR_IO_TIMEOUT_ERROR, err); + break; + case WSAEINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err ); + break; + case WSASYSNOTREADY: + case WSAVERNOTSUPPORTED: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case WSAEWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + + default: + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + } + return; +} /* end _MD_map_win16_error() */ + + diff --git a/nsprpub/pr/src/md/windows/w16fmem.c b/nsprpub/pr/src/md/windows/w16fmem.c new file mode 100644 index 00000000000..55df5128537 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16fmem.c @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/* + ********************************************************************** + * + * Memory-mapped files are not implemented on Win16. + * + ********************************************************************** + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRInt32 _MD_GetMemMapAlignment(void) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +void * _MD_MemMap( + PRFileMap *fmap, + PRInt64 offset, + PRUint32 len) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + diff --git a/nsprpub/pr/src/md/windows/w16gc.c b/nsprpub/pr/src/md/windows/w16gc.c new file mode 100644 index 00000000000..cd3a65284f0 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16gc.c @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include + +PRWord * +_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) + { + _MD_SAVE_CONTEXT(t); + } + /* + ** In Win16 because the premption is "cooperative" it can never be the + ** case that a register holds the sole reference to an object. It + ** will always have been pushed onto the stack before the thread + ** switch... So don't bother to scan the registers... + */ + *np = 0; + + return (PRWord *) CONTEXT(t); +} + +#if 0 +#ifndef SPORT_MODEL + +#define MAX_SEGMENT_SIZE (65536l - 4096l) + +/************************************************************************/ +/* +** Machine dependent GC Heap management routines: +** _MD_GrowGCHeap +*/ +/************************************************************************/ + +extern void * +_MD_GrowGCHeap(uint32 *sizep) +{ + void *addr; + + if( *sizep > MAX_SEGMENT_SIZE ) { + *sizep = MAX_SEGMENT_SIZE; + } + + addr = malloc((size_t)*sizep); + return addr; +} + +#endif /* SPORT_MODEL */ +#endif /* 0 */ + diff --git a/nsprpub/pr/src/md/windows/w16io.c b/nsprpub/pr/src/md/windows/w16io.c new file mode 100644 index 00000000000..6089d3992d3 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16io.c @@ -0,0 +1,855 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include +#include +#include +#include + + +/* +** Sleep this many milliseconds on each I/O operation +** to cause an intentional thread switch. +*/ +#define _PR_MD_WIN16_DELAY 1 + + +/* +** PR_MD_RegisterW16StdioCallbacks() -- Register Win16 stdio callback functions +** +** This public function call is unique to Win16. +** ... Sigh ... So much for platform independence. +** +** To get stdio to work from a command line executable, the stdio stream +** calls must be issued from the .EXE file; calling them from the .DLL +** sends the output to the bit-bucket. Therefore, the .EXE wanting to +** do stdio to the console window (must be built as a "quickwin" application) +** must have the wrapper functions defined in this module statically linked +** into the .EXE. +** +** There appears to be nothing you can do to get stdio to work from a +** Win16 GUI application. Oh Well! +** +*/ +PRStdinRead _pr_md_read_stdin = 0; +PRStdoutWrite _pr_md_write_stdout = 0; +PRStderrWrite _pr_md_write_stderr = 0; + +PRStatus +PR_MD_RegisterW16StdioCallbacks( PRStdinRead inReadf, PRStdoutWrite outWritef, PRStderrWrite errWritef ) +{ + _pr_md_write_stdout = outWritef; + _pr_md_write_stderr = errWritef; + _pr_md_read_stdin = inReadf; + + return(PR_SUCCESS); +} /* end PR_MD_RegisterW16StdioCallbacks() */ + + +/* +** _PR_MD_OPEN() -- Open a file +** +** Returns: a fileHandle or -1 +** +** +*/ +PRInt32 +_PR_MD_OPEN(const char *name, PRIntn osflags, int mode) +{ + PRInt32 file; + int access = O_BINARY; + int rights = 0; + + + /* + ** Map NSPR open flags to os open flags + */ + if (osflags & PR_RDONLY ) + access |= O_RDONLY; + if (osflags & PR_WRONLY ) + access |= O_WRONLY; + if (osflags & PR_RDWR ) + access |= O_RDWR; + if (osflags & PR_CREATE_FILE ) + { + access |= O_CREAT; + rights |= S_IRWXU; + } + if (osflags & PR_TRUNCATE) + access |= O_TRUNC; + if (osflags & PR_APPEND) + access |= O_APPEND; + else + access |= O_RDONLY; + + /* + ** Open the file + */ + file = (PRInt32) sopen( name, access, SH_DENYNO, rights ); + if ( -1 == (PRInt32)file ) + { + _PR_MD_MAP_OPEN_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return file; +} + +/* +** _PR_MD_READ() - Read something +** +** Returns: bytes read or -1 +** +*/ +PRInt32 +_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) +{ + PRInt32 rv; + + if ( (PR_GetDescType(fd) == PR_DESC_FILE) && + ( fd->secret->md.osfd == PR_StandardInput ) && + ( _pr_md_write_stdout )) + { + rv = (*_pr_md_read_stdin)( buf, len); + } + else + { + rv = read( fd->secret->md.osfd, buf, len ); + } + + if ( rv == -1) + { + _PR_MD_MAP_READ_ERROR( errno ); + } + + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} + +/* +** _PR_MD_WRITE() - Write something +** +** Returns: bytes written or -1 +** +** Note: for file handles 1 and 2 (stdout and stderr) +** call the Win16 NSPR stdio callback functions, if they are +** registered. +** +*/ +PRInt32 +_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) +{ + PRInt32 rv; + + if ( (PR_GetDescType(fd) == PR_DESC_FILE)) + { + switch ( fd->secret->md.osfd ) + { + case PR_StandardOutput : + if ( _pr_md_write_stdout ) + rv = (*_pr_md_write_stdout)( (void *)buf, len); + else + rv = len; /* fake success */ + break; + + case PR_StandardError : + if ( _pr_md_write_stderr ) + rv = (*_pr_md_write_stderr)( (void *)buf, len); + else + rv = len; /* fake success */ + break; + + default: + rv = write( fd->secret->md.osfd, buf, len ); + if ( rv == -1 ) + { + _PR_MD_MAP_WRITE_ERROR( errno ); + } + break; + } + } + else + { + rv = write( fd->secret->md.osfd, buf, len ); + if ( rv == -1 ) + { + _PR_MD_MAP_WRITE_ERROR( errno ); + } + } + + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} /* --- end _PR_MD_WRITE() --- */ + +/* +** _PR_MD_LSEEK() - Seek to position in a file +** +** Note: 'whence' maps directly to PR_... +** +** Returns: +** +*/ +PRInt32 +_PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, int whence) +{ + PRInt32 rv; + + rv = lseek( fd->secret->md.osfd, offset, whence ); + if ( rv == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return( rv ); +} + +/* +** _PR_MD_LSEEK64() -- Seek to position in file, 64bit offset. +** +*/ +PRInt64 +_PR_MD_LSEEK64( PRFileDesc *fd, PRInt64 offset, int whence ) +{ + PRInt64 test; + PRInt32 rv, off; + LL_SHR(test, offset, 32); + if (!LL_IS_ZERO(test)) + { + PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); + LL_I2L(test, -1); + return test; + } + LL_L2I(off, offset); + rv = _PR_MD_LSEEK(fd, off, whence); + LL_I2L(test, rv); + return test; +} /* end _PR_MD_LSEEK64() */ + +/* +** _PR_MD_FSYNC() - Flush file buffers. +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_FSYNC(PRFileDesc *fd) +{ + PRInt32 rv; + + rv = (PRInt32) fsync( fd->secret->md.osfd ); + if ( rv == -1 ) + { + _PR_MD_MAP_FSYNC_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + +/* +** _PR_MD_CLOSE() - Close an open file handle +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_CLOSE_FILE(PRInt32 osfd) +{ + PRInt32 rv; + + rv = (PRInt32) close( osfd ); + if ( rv == -1 ) + { + _PR_MD_MAP_CLOSE_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} /* --- end _MD_CloseFile() --- */ + + +/* --- DIR IO ------------------------------------------------------------ */ +#define GetFileFromDIR(d) (d)->d_entry.cFileName + +/* +** FlipSlashes() - Make forward slashes ('/') into backslashes +** +** Returns: void +** +** +*/ +void FlipSlashes(char *cp, int len) +{ + while (--len >= 0) { + if (cp[0] == '/') { + cp[0] = PR_DIRECTORY_SEPARATOR; + } + cp++; + } +} + + +/* +** _PR_MD_OPEN_DIR() - Open a Directory. +** +** Returns: +** +** +*/ +PRStatus +_PR_MD_OPEN_DIR(_MDDir *d, const char *name) +{ + d->dir = opendir( name ); + + if ( d->dir == NULL ) + { + _PR_MD_MAP_OPENDIR_ERROR( errno ); + return( PR_FAILURE ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return( PR_SUCCESS ); +} + + +/* +** _PR_MD_READ_DIR() - read next directory entry +** +** +*/ +char * +_PR_MD_READ_DIR(_MDDir *d, PRIntn flags) +{ + struct dirent *de; + int err; + + for (;;) + { + de = readdir( d->dir ); + if ( de == NULL ) { + _PR_MD_MAP_READDIR_ERROR( errno); + 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; + break; + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return de->d_name; +} + +/* +** _PR_MD_CLOSE_DIR() - Close a directory. +** +** +*/ +PRInt32 +_PR_MD_CLOSE_DIR(_MDDir *d) +{ + PRInt32 rv; + + if ( d->dir ) + { + rv = closedir( d->dir ); + if (rv != 0) + { + _PR_MD_MAP_CLOSEDIR_ERROR( errno ); + } + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} + + +/* +** _PR_MD_DELETE() - Delete a file. +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_DELETE(const char *name) +{ + PRInt32 rv; + + rv = (PRInt32) remove( name ); + if ( rv != 0 ) + { + _PR_MD_MAP_DELETE_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + + +/* +** _PR_MD_STAT() - Get file attributes by filename +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_STAT(const char *fn, struct stat *info) +{ + PRInt32 rv; + + rv = _stat(fn, (struct _stat *)info); + if ( rv == -1 ) + { + _PR_MD_MAP_STAT_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return( rv ); +} + +/* +** _PR_MD_GETFILEINFO() - Get file attributes by filename +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) +{ + struct _stat sb; + 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; + LL_I2L(info->modifyTime, sb.st_mtime); + LL_I2L(info->creationTime, sb.st_ctime); + } + } + else + { + _PR_MD_MAP_STAT_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) +{ + PRFileInfo info32; + + PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32); + if (0 == rv) + { + info->type = info32.type; + info->modifyTime = info32.modifyTime; + info->creationTime = info32.creationTime; + LL_I2L(info->size, info32.size); + } + return(rv); +} + +/* +** _PR_MD_GETOPENFILEINFO() - Get file attributes from an open file handle +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) +{ + struct stat statBuf; + PRInt32 rv = PR_SUCCESS; + + rv = fstat( fd->secret->md.osfd, &statBuf ); + if ( rv == 0) + { + if (statBuf.st_mode & S_IFREG ) + info->type = PR_FILE_FILE; + else if ( statBuf.st_mode & S_IFDIR ) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + info->size = statBuf.st_size; + LL_I2L(info->modifyTime, statBuf.st_mtime); + LL_I2L(info->creationTime, statBuf.st_ctime); + + } + else + { + _PR_MD_MAP_FSTAT_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + +PRInt32 +_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + PRFileInfo info32; + + PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32); + if (0 == rv) + { + info->type = info32.type; + info->modifyTime = info32.modifyTime; + info->creationTime = info32.creationTime; + LL_I2L(info->size, info32.size); + } + return(rv); +} + +/* +** _PR_MD_RENAME() - Rename a file +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_RENAME(const char *from, const char *to) +{ + PRInt32 rv; + + rv = rename( from, to ); + if ( rv == -1 ) + { + _PR_MD_MAP_RENAME_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return( rv ); +} + +/* +** _PR_MD_ACCESS() - Return file acesss attribute. +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_ACCESS(const char *name, PRIntn how) +{ + PRInt32 rv; + int mode = 0; + + if ( how & PR_ACCESS_WRITE_OK ) + mode |= W_OK; + if ( how & PR_ACCESS_READ_OK ) + mode |= R_OK; + + rv = (PRInt32) access( name, mode ); + if ( rv == -1 ) + { + _PR_MD_MAP_ACCESS_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + +/* +** _PR_MD_MKDIR() - Make a directory +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_MKDIR(const char *name, PRIntn mode) +{ + PRInt32 rv; + + rv = mkdir( name ); + if ( rv == 0 ) + { + PR_Sleep( _PR_MD_WIN16_DELAY ); + return PR_SUCCESS; + } + else + { + _PR_MD_MAP_MKDIR_ERROR( errno ); + PR_Sleep( _PR_MD_WIN16_DELAY ); + return PR_FAILURE; + } +} + +/* +** _PR_MD_RMDIR() - Delete a directory +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_RMDIR(const char *name) +{ + PRInt32 rv; + + rv = (PRInt32) rmdir( name ); + if ( rv == -1 ) + { + _PR_MD_MAP_RMDIR_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + +/* +** _PR_MD_LOCKFILE() - Lock a file. +** +** The _locking() call locks relative to the current file pointer. +** This function is required to lock all of the file, so, +** 1. Seek to the beginning of the file, preserving the original position. +** 2. Lock the file, pausing if it is locked by someone else, and +** try again. +** 3. Re-position to the original position in the file. +** +** For unlocking, a similar protocol of positioning is required. +** +*/ +PRStatus +_PR_MD_LOCKFILE(PRInt32 f) +{ + PRInt32 rv = PR_SUCCESS; /* What we return to our caller */ + long seekOrigin; /* original position in file */ + PRInt32 rc; /* what the system call returns to us */ + + /* + ** Seek to beginning of file, saving original position. + */ + seekOrigin = lseek( f, 0l, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + return( PR_FAILURE ); + } + + /* + ** Attempt to lock the file. + ** If someone else has it, Sleep-a-while and try again. + */ + for( rc = -1; rc != 0; ) + { + rc = _locking( f, _LK_NBLCK , 0x7fffffff ); + if ( rc == -1 ) + { + if ( errno == EACCES ) + { + PR_Sleep( 100 ); + continue; + } + else + { + _PR_MD_MAP_LOCKF_ERROR( errno ); + rv = PR_FAILURE; + break; + } + } + } /* end for() */ + + /* + ** Now that the file is locked, re-position to + ** the original file position. + ** + */ + rc = lseek( f, seekOrigin, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + rv = PR_FAILURE; + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return PR_SUCCESS; +} /* end _PR_MD_LOCKFILE() */ + +/* +** _PR_MD_TLOCKFILE() - Test and Lock file. +** +** The _locking() call locks relative to the current file pointer. +** This function is required to lock all of the file, so, +** 1. Seek to the beginning of the file, preserving the original position. +** 2. Attempt to Lock the file. +** If the file is locked by someone else, try NO MORE. +** 3. Re-position to the original position in the file. +** +** See the discussion of _PR_MD_LOCKFILE +** +** +*/ +PRStatus +_PR_MD_TLOCKFILE(PRInt32 f) +{ + PRInt32 rv = PR_SUCCESS; /* What we return */ + long seekOrigin; /* original position in file */ + PRInt32 rc; /* return value from system call */ + + /* + ** Seek to beginning of file, saving original position. + */ + seekOrigin = lseek( f, 0l, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + return( PR_FAILURE ); + } + + /* + ** Attempt to lock the file. One ping; one ping only, Vasily. + ** If someone else has it, Reposition and return failure. + */ + rc = _locking( f, _LK_NBLCK , 0x7fffffff ); + if ( rc == -1 ) + { + if ( errno != EACCES ) + _PR_MD_MAP_LOCKF_ERROR( errno ); + rv = PR_FAILURE; + } + + /* + ** Now that the file is locked, maybe, re-position to + ** the original file position. + */ + rc = lseek( f, seekOrigin, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + rv = PR_FAILURE; + } + + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} /* end _PR_MD_TLOCKFILE() */ + + +/* +** _PR_MD_UNLOCKFILE() - Unlock a file. +** +** See the discussion of _PR_MD_LOCKFILE +** +*/ +PRStatus +_PR_MD_UNLOCKFILE(PRInt32 f) +{ + PRInt32 rv = PR_SUCCESS; /* What we return */ + long seekOrigin; /* original position in file */ + PRInt32 rc; /* return value from system call */ + + /* + ** Seek to beginning of file, saving original position. + */ + seekOrigin = lseek( f, 0l, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + return( PR_FAILURE ); + } + + /* + ** Unlock the file. + */ + rc = _locking( f, _LK_UNLCK , 0x7fffffff ); + if ( rc == -1 ) + { + _PR_MD_MAP_LOCKF_ERROR( errno ); + rv = PR_FAILURE; + } + + /* + ** Now that the file is unlocked, re-position to + ** the original file position. + */ + rc = lseek( f, seekOrigin, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + rv = PR_FAILURE; + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} /* end _PR_MD_UNLOCKFILE() */ + +/* +** PR_Stat() -- Return status on a file +** +** This is a hack! ... See BugSplat: 98516 +** Basically, this hack takes a name and stat buffer as input. +** The input stat buffer is presumed to be a Microsoft stat buffer. +** The functions does a Watcom stat() then maps the result to +** the MS stat buffer. ... +** +*/ +PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf) +{ + PRInt32 rv; + _MDMSStat *mssb = (_MDMSStat*) buf; /* this is Microsoft's stat buffer */ + struct stat statBuf; /* this is Watcom's stat buffer */ + + /* First, get Watcom's idea of stat + ** then reformat it into a Microsoft idea of stat + */ + rv = (PRInt32) _stat( name, &statBuf); + if (rv == 0l ) + { + mssb->st_dev = statBuf.st_dev; + mssb->st_ino = statBuf.st_ino; /* not used, really */ + mssb->st_mode = statBuf.st_mode; + mssb->st_nlink = 1; /* always 1, says MS */ + mssb->st_uid = statBuf.st_uid; + mssb->st_gid = statBuf.st_gid; + mssb->st_rdev = statBuf.st_rdev; /* please Gh0d! Let these be the same */ + mssb->st_size = statBuf.st_size; + mssb->st_atime = statBuf.st_atime; + mssb->st_mtime = statBuf.st_mtime; + mssb->st_ctime = statBuf.st_ctime; + } + return rv; +} /* end PR_Stat() */ + + + +/* $$ end W16io.c */ diff --git a/nsprpub/pr/src/md/windows/w16mem.c b/nsprpub/pr/src/md/windows/w16mem.c new file mode 100644 index 00000000000..1c07099d021 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16mem.c @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/******************************************************************* +** w16mem.c -- Implement memory segment functions. +** +** +******************************************************************** +*/ +#include "primpl.h" + + +/* +** Allocate a new memory segment. +** +** Return the segment's access rights and size. +*/ +PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr) +{ + PR_ASSERT(seg != 0); + PR_ASSERT(size != 0); + PR_ASSERT(vaddr == 0); + + /* + ** Take the actual memory for the segment out of our Figment heap. + */ + + seg->vaddr = (char *)malloc(size); + + if (seg->vaddr == NULL) { + return PR_FAILURE; + } + + seg->size = size; + + return PR_SUCCESS; +} /* --- end _MD_AllocSegment() --- */ + + +/* +** Free previously allocated memory segment. +*/ +void _MD_FreeSegment(PRSegment *seg) +{ + PR_ASSERT((seg->flags & _PR_SEG_VM) == 0); + + if (seg->vaddr != NULL) + free( seg->vaddr ); + return; +} /* --- end _MD_FreeSegment() --- */ diff --git a/nsprpub/pr/src/md/windows/w16null.c b/nsprpub/pr/src/md/windows/w16null.c new file mode 100644 index 00000000000..7f4c5fc173d --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16null.c @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include + + +struct _MDLock _pr_ioq_lock; +HINSTANCE _pr_hInstance = NULL; +char * _pr_top_of_task_stack; +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; + +/* + *----------------------------------------------------------------------- + * + * PR_Now -- + * + * Returns the current time in microseconds since the epoch. + * The epoch is midnight January 1, 1970 GMT. + * The implementation is machine dependent. This is the + * implementation for Windows. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +#if defined(HAVE_WATCOM_BUG_2) +PRTime __pascal __export __loadds +#else +PR_IMPLEMENT(PRTime) +#endif +PR_Now(void) +{ + PRInt64 s, ms, ms2us, s2us; + struct timeb b; + + ftime(&b); + LL_I2L(ms2us, PR_USEC_PER_MSEC); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, b.time); + LL_I2L(ms, (PRInt32)b.millitm); + LL_MUL(ms, ms, ms2us); + LL_MUL(s, s, s2us); + LL_ADD(s, s, ms); + return s; +} + + + +char *_PR_MD_GET_ENV(const char *name) +{ + return NULL; +} + +PRIntn +_PR_MD_PUT_ENV(const char *name) +{ + return NULL; +} + +int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpszCmdLine ) +{ + _pr_hInstance = hInst; + return TRUE; +} + + + +void +_PR_MD_EARLY_INIT() +{ + _tzset(); + return; +} + +void +_PR_MD_WAKEUP_CPUS( void ) +{ + return; +} + diff --git a/nsprpub/pr/src/md/windows/w16proc.c b/nsprpub/pr/src/md/windows/w16proc.c new file mode 100644 index 00000000000..f1a9eab8279 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16proc.c @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include + + +/* +** Create Process. +*/ +PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _PR_DetachWindowsProcess(PRProcess *process) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_WaitWindowsProcess(PRProcess *process, + PRInt32 *exitCode) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_KillWindowsProcess(PRProcess *process) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + diff --git a/nsprpub/pr/src/md/windows/w16sock.c b/nsprpub/pr/src/md/windows/w16sock.c new file mode 100644 index 00000000000..78e95906bf7 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16sock.c @@ -0,0 +1,1170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +static int winsockNotPresent = 0; + +void +_PR_MD_INIT_IO() +{ + int rv; + + WORD WSAVersion = 0x0101; + WSADATA WSAData; + + rv = WSAStartup( WSAVersion, &WSAData ); + if ( rv != 0 ) + { + _PR_MD_MAP_WSASTARTUP_ERROR(WSAGetLastError()); + winsockNotPresent = 1; + } + return; +} + +void +_PR_MD_CLEANUP_BEFORE_EXIT(void) +{ + int rv; + int err; + + rv = WSACleanup(); + if ( rv == SOCKET_ERROR ) + { + err = WSAGetLastError(); + PR_ASSERT(0); + } + return; +} /* end _PR_MD_CLEANUP_BEFORE_EXIT() */ + +/* --- SOCKET IO --------------------------------------------------------- */ + +PRStatus +_MD_WindowsGetHostName(char *name, PRUint32 namelen) +{ + PRIntn rv; + PRInt32 syserror; + + rv = gethostname(name, (PRInt32) namelen); + if (0 == rv) { + return PR_SUCCESS; + } + syserror = WSAGetLastError(); + PR_ASSERT(WSANOTINITIALISED != syserror); + _PR_MD_MAP_GETHOSTNAME_ERROR(syserror); + return PR_FAILURE; +} + + +PRInt32 +_PR_MD_SOCKET(int af, int type, int flags) +{ + SOCKET sock; + PRUint32 one = 1; + PRInt32 rv; + PRInt32 err; + + if ( winsockNotPresent ) + return( (PRInt32)INVALID_SOCKET ); + + sock = socket(af, type, flags); + + if (sock == INVALID_SOCKET ) + { + int rv = GetLastError(); + closesocket(sock); + _PR_MD_MAP_SOCKET_ERROR(rv); + return (PRInt32)INVALID_SOCKET; + } + + /* + ** Make the socket Non-Blocking + */ + rv = ioctlsocket( sock, FIONBIO, &one); + if ( rv != 0 ) + { + err = WSAGetLastError(); + return -1; + } + + return (PRInt32)sock; +} + + +PRInt32 +_PR_MD_SOCKETAVAILABLE(PRFileDesc *fd) +{ + PRUint32 result; + + if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError()); + return -1; + } + return result; +} + + +/* +** _MD_CloseSocket() -- Close a socket +** +*/ +PRInt32 +_PR_MD_CLOSE_SOCKET(PRInt32 osfd) +{ + PRInt32 rv; + + rv = closesocket((SOCKET) osfd ); + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError()); + + return rv; +} + +PRInt32 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + int rv, err; + + rv = listen(fd->secret->md.osfd, backlog); + if ( rv == SOCKET_ERROR ) { + _PR_MD_MAP_LISTEN_ERROR(WSAGetLastError()); + return(-1); + } + return(rv); +} + +PRInt32 +_PR_MD_ACCEPT(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout ) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 err; + PRIntn rv; + + MD_ASSERTINT( *addrlen ); + + while ((rv = (SOCKET)accept(osfd, (struct sockaddr *) addr, + (int *)addrlen)) == INVALID_SOCKET ) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_READ, 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); + } + rv = -1; + 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 ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_ACCEPT_ERROR(err); + } +done: + if ( rv == INVALID_SOCKET ) + return(-1 ); + else + return(rv); +} /* end _MD_Accept() */ + + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { + err = WSAGetLastError(); + if (err == WSAEISCONN) { + rv = 0; + break; + } + /* for winsock1.1, it reports EALREADY as EINVAL */ + if ((err == WSAEWOULDBLOCK) + ||(err == WSAEALREADY) + || (err = WSAEINVAL)) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(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); + } + rv = -1; + 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 ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + + if (rv < 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + } +done: + return rv; +} + +PRInt32 +_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv; + int one = 1; + + rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen); + + if (rv == SOCKET_ERROR) { + _PR_MD_MAP_BIND_ERROR(WSAGetLastError()); + return -1; + } + + return 0; +} + + +PRInt32 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((rv = recv(osfd,buf,amount,flags)) == -1) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_READ, 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); + } + rv = -1; + 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 ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECV_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((rv = send(osfd,buf,amount,flags)) == -1) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(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); + } + rv = -1; + 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 ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } +done: + return rv; +} + +PRInt32 +_PR_MD_SENDTO(PRFileDesc*fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(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); + } + rv = -1; + 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 ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } +done: + return rv; +} + +PRInt32 +_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((*addrlen = PR_NETADDR_SIZE(addr)), + ((rv = recvfrom(osfd, buf, amount, flags, + (struct sockaddr FAR *) addr,(int FAR *)addrlen)) == -1)) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_READ, 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); + } + rv = -1; + 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 ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECVFROM_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +{ + int index; + int sent = 0; + int rv; + + for (index=0; index < iov_size; index++) + { + +/* + * XXX To be fixed + * should call PR_Send + */ + + rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout); + if (rv > 0) + sent += rv; + if ( rv != iov[index].iov_len ) + { + if (sent <= 0) + return -1; + return -1; + } + } + return sent; +} + +PRInt32 +_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; +} + +PRStatus +_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, (int *)len); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, (int*)len); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +{ + PRInt32 rv; + + rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, (int*)optlen); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +{ + 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; + } +} + +void +_PR_MD_MAKE_NONBLOCK(PRFileDesc *f) +{ + return; // do nothing! +} + +/* +** Wait for I/O on a single descriptor. + * + * return 0, if timed-out, else return 1 +*/ +PRInt32 +_PR_WaitForFD(PRInt32 osfd, PRUintn how, PRIntervalTime timeout) +{ + _PRWin16PollDesc *pd; + PRPollQueue *pq; + PRIntn is; + PRInt32 rv = 1; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); + + pd = &me->md.thr_pd; + pq = &me->md.thr_pq; + if (timeout == PR_INTERVAL_NO_WAIT) return 0; + + pd->osfd = osfd; + pd->in_flags = how; + pd->out_flags = 0; + + pq->pds = pd; + pq->npds = 1; + + _PR_INTSOFF(is); + _PR_MD_IOQ_LOCK(); + _PR_THREAD_LOCK(me); + + if (_PR_PENDING_INTERRUPT(me)) { + _PR_THREAD_UNLOCK(me); + _PR_MD_IOQ_UNLOCK(); + return 0; + } + + pq->thr = me; + pq->on_ioq = PR_TRUE; + pq->timeout = timeout; + _PR_ADD_TO_IOQ((*pq), me->cpu); + 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]++; + } + 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; + + _PR_THREAD_LOCK(me); + + _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; + + /* + ** If we timed out the pollq might still be on the ioq. Remove it + ** before continuing. + */ + if (pq->on_ioq) { + _PR_INTSOFF(is); + _PR_MD_IOQ_LOCK(); + /* + * Need to check pq.on_ioq again + */ + if (pq->on_ioq) { + PR_REMOVE_LINK(&pq->links); + 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)); + } + } + _PR_MD_IOQ_UNLOCK(); + rv = 0; + } + _PR_FAST_INTSON(is); + return(rv); +} + +/* + * Unblock threads waiting for I/O + * used when interrupting threads + * + * NOTE: The thread lock should held when this function is called. + * On return, the thread lock is released. + */ +void _PR_Unblock_IO_Wait(PRThread *thr) +{ + int pri = thr->priority; + _PRCPU *cpu = thr->cpu; + + PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)); + _PR_SLEEPQ_LOCK(cpu); + _PR_DEL_SLEEPQ(thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(cpu); + + PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD)); + thr->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(thr); + _PR_MD_WAKEUP_WAITER(thr); +} + +/* +** 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(); + int sockOpt; + int sockOptLen = sizeof(sockOpt); + + 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; + _PRWin16PollDesc *pds = pq->pds; + _PRWin16PollDesc *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 ( getsockopt(osfd, + (int)SOL_SOCKET, + SO_TYPE, + (char*)&sockOpt, + &sockOptLen) == SOCKET_ERROR ) + { + if ( WSAGetLastError() == WSAENOTSOCK ) + { + 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); + 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)); + } + } + + _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; + } + } +} /* end FindBadFDs() */ + +/* +** Called by the scheduler when there is nothing to do. This means that +** all threads are blocked on some monitor somewhere. +** +** Pause the current CPU. longjmp to the cpu's pause stack +*/ +PRInt32 _PR_MD_PAUSE_CPU( PRIntervalTime ticks) +{ + PRThread *me = _MD_CURRENT_THREAD(); + struct timeval timeout, *tvp; + fd_set r, w, e; + fd_set *rp, *wp, *ep; + PRInt32 max_osfd, nfd; + PRInt32 rv; + PRCList *q; + PRUint32 min_timeout; + + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + + /* + * 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); + + rp = &r; + wp = &w; + ep = &e; + + max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1; + min_timeout = _PR_IOQ_TIMEOUT(me->cpu); + /* + ** 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; + + 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 (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; + } + + _PR_MD_IOQ_UNLOCK(); + _MD_CHECK_FOR_EXIT(); + /* + * check for i/o operations + */ + + nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp); + + _MD_CHECK_FOR_EXIT(); + _PR_MD_IOQ_LOCK(); + /* + ** Notify monitors that are associated with the selected descriptors. + */ + 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; + _PRWin16PollDesc *pds = pq->pds; + _PRWin16PollDesc *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; + + 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)); + } + } + 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); + } + _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; + } + } + } else if (nfd < 0) { + if ( WSAGetLastError() == WSAENOTSOCK ) + { + FindBadFDs(); + } else { + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d", + errno)); + } + } + _PR_MD_IOQ_UNLOCK(); + return(0); + +} /* end _PR_MD_PAUSE_CPU() */ + + +/* +** _MD_pr_poll() -- Implement MD polling +** +** The function was snatched (re-used) from the unix implementation. +** +** The native thread stuff was deleted. +** The pollqueue is instantiated on the mdthread structure +** to keep the stack frame from being corrupted when this +** thread is waiting on the poll. +** +*/ +extern PRInt32 +_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, + PRIntervalTime timeout) +{ + PRPollDesc *pd, *epd; + PRInt32 n, err, pdcnt; + PRIntn is; + _PRWin16PollDesc *spds, *spd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRPollQueue *pq; + + pq = &me->md.thr_pq; + + /* + * XXX + * PRPollDesc has a PRFileDesc field, fd, while the IOQ + * is a list of PRPollQueue structures, each of which contains + * a _PRWin16PollDesc. A _PRWin16PollDesc struct contains + * the OS file descriptor, osfd, and not a PRFileDesc. + * So, we have allocate memory for _PRWin16PollDesc structures, + * copy the flags information from the pds list and have pq + * point to this list of _PRWin16PollDesc structures. + * + * It would be better if the memory allocation can be avoided. + */ + + spds = (_PRWin16PollDesc*) PR_MALLOC(npds * sizeof(_PRWin16PollDesc)); + if (!spds) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + spd = spds; + + _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_DELETE(spds); + 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; + + 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); + + spd->osfd = osfd; + spd->in_flags = pd->in_flags; + spd++; + pdcnt++; + + 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]++; + } + 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; + + + pq->pds = spds; + pq->npds = pdcnt; + + pq->thr = me; + 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; + + /* + * Copy the out_flags from the _PRWin16PollDesc structures to the + * user's PRPollDesc structures and free the allocated memory + */ + spd = spds; + for (pd = pds, epd = pd + npds; pd < epd; pd++) { + if ((NULL == pd->fd) || (pd->in_flags == 0)) { + pd->out_flags = 0; + continue; + } + pd->out_flags = spd->out_flags; + spd++; + } + PR_DELETE(spds); + + /* + ** If we timed out the pollq might still be on the ioq. Remove it + ** before continuing. + */ + if (pq->on_ioq) { + _PR_INTSOFF(is); + _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); + 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)); + } + } + } + _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; + } +} /* end _MD_pr_poll() */ diff --git a/nsprpub/pr/src/md/windows/w16stdio.c b/nsprpub/pr/src/md/windows/w16stdio.c new file mode 100644 index 00000000000..52d34cfe726 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16stdio.c @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** w16stdio.c -- Callback functions for Win16 stdio read/write. +** +** +*/ +#include "primpl.h" + +/* +** _PL_MDStdioWrite() -- Win16 hackery to get console output +** +** Returns: number of bytes written. +** +*/ +PRInt32 +_PL_W16StdioWrite( void *buf, PRInt32 amount ) +{ + int rc; + + rc = fputs( buf, stdout ); + if ( rc == EOF ) + { + // something about errno + return(PR_FAILURE); + } + return( strlen(buf)); +} /* end _PL_fputs() */ + +/* +** _PL_W16StdioRead() -- Win16 hackery to get console input +** +*/ +PRInt32 +_PL_W16StdioRead( void *buf, PRInt32 amount ) +{ + char *bp; + + bp = fgets( buf, (int) amount, stdin ); + if ( bp == NULL ) + { + // something about errno + return(PR_FAILURE); + } + + return( strlen(buf)); +} /* end _PL_fgets() */ +/* --- end w16stdio.c --- */ + +/* +** Wrappers, linked into the client, that call +** functions in LibC +** +*/ + +/* +** _PL_W16CallBackPuts() -- Wrapper for puts() +** +*/ +int PR_CALLBACK _PL_W16CallBackPuts( const char *outputString ) +{ + return( puts( outputString )); +} /* end _PL_W16CallBackPuts() */ + +/* +** _PL_W16CallBackStrftime() -- Wrapper for strftime() +** +*/ +size_t PR_CALLBACK _PL_W16CallBackStrftime( + char *s, + size_t len, + const char *fmt, + const struct tm *p ) +{ + return( strftime( s, len, fmt, p )); +} /* end _PL_W16CallBackStrftime() */ + +/* +** _PL_W16CallBackMalloc() -- Wrapper for malloc() +** +*/ +void * PR_CALLBACK _PL_W16CallBackMalloc( size_t size ) +{ + return( malloc( size )); +} /* end _PL_W16CallBackMalloc() */ + +/* +** _PL_W16CallBackCalloc() -- Wrapper for calloc() +** +*/ +void * PR_CALLBACK _PL_W16CallBackCalloc( size_t n, size_t size ) +{ + return( calloc( n, size )); +} /* end _PL_W16CallBackCalloc() */ + +/* +** _PL_W16CallBackRealloc() -- Wrapper for realloc() +** +*/ +void * PR_CALLBACK _PL_W16CallBackRealloc( + void *old_blk, + size_t size ) +{ + return( realloc( old_blk, size )); +} /* end _PL_W16CallBackRealloc() */ + +/* +** _PL_W16CallBackFree() -- Wrapper for free() +** +*/ +void PR_CALLBACK _PL_W16CallBackFree( void *ptr ) +{ + free( ptr ); + return; +} /* end _PL_W16CallBackFree() */ + +/* +** _PL_W16CallBackGetenv() -- Wrapper for getenv() +** +*/ +void * PR_CALLBACK _PL_W16CallBackGetenv( const char *name ) +{ + return( getenv( name )); +} /* end _PL_W16CallBackGetenv */ + + +/* +** _PL_W16CallBackPutenv() -- Wrapper for putenv() +** +*/ +int PR_CALLBACK _PL_W16CallBackPutenv( const char *assoc ) +{ + return( putenv( assoc )); +} /* end _PL_W16CallBackGetenv */ diff --git a/nsprpub/pr/src/md/windows/w16thred.c b/nsprpub/pr/src/md/windows/w16thred.c new file mode 100644 index 00000000000..85531318b8e --- /dev/null +++ b/nsprpub/pr/src/md/windows/w16thred.c @@ -0,0 +1,426 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include +#include + +/* +** DispatchTrace -- define a thread dispatch trace entry +** +** The DispatchTrace oject(s) are instantiated in a single +** array. Think of the array as a push-down stack; entry +** zero is the most recent, entry one the next most recent, etc. +** For each time PR_MD_RESTORE_CONTEXT() is called, the array +** is Pushed down and entry zero is overwritten with data +** for the newly dispatched thread. +** +** Function TraceDispatch() manages the DispatchTrace array. +** +*/ +typedef struct DispatchTrace +{ + PRThread * thread; + PRUint32 state; + PRInt16 mdThreadNumber; + PRInt16 unused; + PRThreadPriority priority; + +} DispatchTrace, *DispatchTracePtr ; + +static void TraceDispatch( PRThread *thread ); + + +PRThread *_pr_primordialThread; + +/* +** Note: the static variables must be on the data-segment because +** the stack is destroyed during shadow-stack copy operations. +** +*/ +static char * pSource; /* ptr to sourc of a "shadow-stack" copy */ +static char * pTarget; /* ptr to target of a "shadow-stack" copy */ +static int cxByteCount; /* number of bytes for "shadow-stack" copy */ +static int bytesMoved; /* instrumentation: WRT "shadow-stack" copy */ +static FILE * file1 = 0; /* instrumentation: WRT debug */ + +#define NUM_DISPATCHTRACE_OBJECTS 24 +static DispatchTrace dt[NUM_DISPATCHTRACE_OBJECTS] = {0}; /* instrumentation: WRT dispatch */ +static PRUint32 dispatchCount = 0; /* instrumentation: number of thread dispatches */ + +static int OldPriorityOfPrimaryThread = -1; +static int TimeSlicesOnNonPrimaryThread = 0; +static PRUint32 threadNumber = 1; /* Instrumentation: monotonically increasing number */ + + + +/* +** _PR_MD_FINAL_INIT() -- Final MD Initialization +** +** Poultry Problems! ... The stack, as allocated by PR_NewStack() +** is called from here, late in initialization, because PR_NewStack() +** requires lots of things working. When some elements of the +** primordial thread are created, early in initialization, the +** shadow stack is not one of these things. The "shadow stack" is +** created here, late in initiailization using PR_NewStack(), to +** ensure consistency in creation of the related objects. +** +** A new ThreadStack, and all its affiliated structures, is allocated +** via the call to PR_NewStack(). The PRThread structure in the +** new stack is ignored; the old PRThread structure is used (why?). +** The old PRThreadStack structure is abandoned. +** +*/ +void +_PR_MD_FINAL_INIT() +{ + PRThreadStack * stack = 0; + PRInt32 stacksize = 0; + PRThread * me = _PR_MD_CURRENT_THREAD(); + + _PR_ADJUST_STACKSIZE( stacksize ); + stack = _PR_NewStack( stacksize ); + + me->stack = stack; + stack->thr = me; + + return; +} /* --- end _PR_MD_FINAL_INIT() --- */ + + +void +_MD_INIT_RUNNING_CPU( struct _PRCPU *cpu ) +{ + PR_INIT_CLIST(&(cpu->md.ioQ)); + cpu->md.ioq_max_osfd = -1; + cpu->md.ioq_timeout = PR_INTERVAL_NO_TIMEOUT; +} + + +void +_PR_MD_YIELD( void ) +{ + PR_ASSERT(0); +} + +/* +** _PR_MD_INIT_STACK() -- Win16 specific Stack initialization. +** +** +*/ + +void +_PR_MD_INIT_STACK( PRThreadStack *ts, PRIntn redzone ) +{ + ts->md.stackTop = ts->stackTop - sizeof(PRThread); + ts->md.cxByteCount = 0; + + return; +} /* --- end _PR_MD_INIT_STACK() --- */ + +/* +** _PR_MD_INIT_THREAD() -- Win16 specific Thread initialization. +** +*/ +PRStatus +_PR_MD_INIT_THREAD(PRThread *thread) +{ + if ( thread->flags & _PR_PRIMORDIAL) + { + _pr_primordialThread = thread; + thread->md.threadNumber = 1; + } + else + { + thread->md.threadNumber = ++threadNumber; + } + + thread->md.magic = _MD_MAGIC_THREAD; + strcpy( thread->md.guardBand, "GuardBand" ); + + return PR_SUCCESS; +} + + +PRStatus +_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + _MD_SWITCH_CONTEXT( thread ); + + return( PR_SUCCESS ); +} + +void *PR_W16GetExceptionContext(void) +{ + return _MD_CURRENT_THREAD()->md.exceptionContext; +} + +void +PR_W16SetExceptionContext(void *context) +{ + _MD_CURRENT_THREAD()->md.exceptionContext = context; +} + + + + +/* +** _MD_RESTORE_CONTEXT() -- Resume execution of thread 't'. +** +** Win16 threading is based on the NSPR 2.0 general model of +** user threads. It differs from the general model in that a +** single "real" stack segment is used for execution of all +** threads. The context of the suspended threads is preserved +** in the md.context [and related members] of the PRThread +** structure. The stack context of the suspended thread is +** preserved in a "shadow stack" object. +** +** _MD_RESTORE_CONTEXT() implements most of the thread switching +** for NSPR's implementation of Win16 theads. +** +** Operations Notes: +** +** Function PR_NewStack() in prustack.c allocates a new +** PRThreadStack, PRStack, PRSegment, and a "shadow" stack +** for a thread. These structures are wired together to +** form the basis of Win16 threads. The thread and shadow +** stack structures are created as part of PR_CreateThread(). +** +** Note! Some special "magic" is applied to the "primordial" +** thread. The physical layout of the PRThread, PRThreadStack, +** shadow stack, ... is somewhat different. Watch yourself when +** mucking around with it. ... See _PR_MD_FINAL_INIT() for most +** of the special treatment of the primordial thread. +** +** Function _PR_MD_INIT_STACK() initializes the value of +** PRThreadStack member md.cxByteCount to zero; there +** is no context to be restored for a thread's initial +** dispatch. The value of member md.stackTop is set to +** point to the highest usable address on the shadow stack. +** This point corresponds to _pr_top_of_task_stack on the +** system's operating stack. +** +** _pr_top_of_task_stack points to a place on the system stack +** considered to be "close to the top". Stack context is preserved +** relative to this point. +** +** Reminder: In x86 architecture, the stack grows "down". +** That is: the stack pointer (SP register) is decremented +** to push objects onto the stack or when a call is made. +** +** Function _PR_MD_WAIT() invokes macro _MD_SWITCH_CONTEXT(); +** this causes the hardware registers to be preserved in a +** CATCHBUF structure using function Catch() [see _win16.h], +** then calls PR_Schedule() to select a new thread for dispatch. +** PR_Schedule() calls _MD_RESTORE_CONTEXT() to cause the thread +** being suspended's stack to be preserved, to restore the +** stack of the to-be-dispactched thread, and to restore the +** to-be-dispactched thread's hardware registers. +** +** At the moment _PR_MD_RESTORE_CONTEXT() is called, the stack +** pointer (SP) is less than the reference pointer +** _pr_top_of_task_stack. The distance difference between the SP and +** _pr_top_of_task_stack is the amount of stack that must be preserved. +** This value, cxByteCount, is calculated then preserved in the +** PRThreadStack.md.cxByteCount for later use (size of stack +** context to restore) when this thread is dispatched again. +** +** A C language for() loop is used to copy, byte-by-byte, the +** stack data being preserved starting at the "address of t" +** [Note: 't' is the argument passed to _PR_MD_RESTORE_CONTEXT()] +** for the length of cxByteCount. +** +** variables pSource and pTarget are the calculated source and +** destination pointers for the stack copy operation. These +** variables are static scope because they cannot be instantiated +** on the stack itself, since the stack is clobbered by restoring +** the to-be-dispatched thread's stack context. +** +** After preserving the suspended thread's stack and architectural +** context, the to-be-dispatched thread's stack context is copied +** from its shadow stack to the system operational stack. The copy +** is done in a small fragment of in-line assembly language. Note: +** In NSPR 1.0, a while() loop was used to do the copy; when compiled +** with the MS C 1.52c compiler, the short while loop used no +** stack variables. The Watcom compiler, specified for use on NSPR 2.0, +** uses stack variables to implement the same while loop. This is +** a no-no! The copy operation clobbers these variables making the +** results of the copy ... unpredictable ... So, a short piece of +** inline assembly language is used to effect the copy. +** +** Following the restoration of the to-be-dispatched thread's +** stack context, another short inline piece of assemble language +** is used to set the SP register to correspond to what it was +** when the to-be-dispatched thread was suspended. This value +** uses the thread's stack->md.cxByteCount as a negative offset +** from _pr_top_of_task_stack as the new value of SP. +** +** Finally, Function Throw() is called to restore the architectural +** context of the to-be-dispatched thread. +** +** At this point, the newly dispatched thread appears to resume +** execution following the _PR_MD_SWITCH_CONTEXT() macro. +** +** OK, this ain't rocket-science, but it can confuse you easily. +** If you have to work on this stuff, please take the time to +** draw, on paper, the structures (PRThread, PRThreadStack, +** PRSegment, the "shadow stack", the system stack and the related +** global variables). Hand step it thru the debugger to make sure +** you understand it very well before making any changes. ... +** YMMV. +** +*/ +void _MD_RESTORE_CONTEXT(PRThread *t) +{ + dispatchCount++; + TraceDispatch( t ); + /* + ** This is a good opportunity to make sure that the main + ** mozilla thread actually gets some time. If interrupts + ** are on, then we know it is safe to check if the main + ** thread is being starved. If moz has not been scheduled + ** for a long time, then then temporarily bump the fe priority + ** up so that it gets to run at least one. + */ +// #if 0 // lth. condition off for debug. + if (_pr_primordialThread == t) { + if (OldPriorityOfPrimaryThread != -1) { + PR_SetThreadPriority(_pr_primordialThread, OldPriorityOfPrimaryThread); + OldPriorityOfPrimaryThread = -1; + } + TimeSlicesOnNonPrimaryThread = 0; + } else { + TimeSlicesOnNonPrimaryThread++; + } + + if ((TimeSlicesOnNonPrimaryThread >= 20) && (OldPriorityOfPrimaryThread == -1)) { + OldPriorityOfPrimaryThread = PR_GetThreadPriority(_pr_primordialThread); + PR_SetThreadPriority(_pr_primordialThread, 31); + TimeSlicesOnNonPrimaryThread = 0; + } +// #endif + /* + ** Save the Task Stack into the "shadow stack" of the current thread + */ + cxByteCount = (int) ((PRUint32) _pr_top_of_task_stack - (PRUint32) &t ); + pSource = (char *) &t; + pTarget = (char *)((PRUint32)_pr_currentThread->stack->md.stackTop + - (PRUint32)cxByteCount ); + _pr_currentThread->stack->md.cxByteCount = cxByteCount; + + for( bytesMoved = 0; bytesMoved < cxByteCount; bytesMoved++ ) + *(pTarget + bytesMoved ) = *(pSource + bytesMoved ); + + /* Mark the new thread as the current thread */ + _pr_currentThread = t; + + /* + ** Now copy the "shadow stack" of the new thread into the Task Stack + ** + ** REMEMBER: + ** After the stack has been copied, ALL local variables in this function + ** are invalid !! + */ + cxByteCount = t->stack->md.cxByteCount; + pSource = t->stack->md.stackTop - cxByteCount; + pTarget = _pr_top_of_task_stack - cxByteCount; + + errno = (_pr_currentThread)->md.errcode; + + __asm + { + mov cx, cxByteCount + mov si, WORD PTR [pSource] + mov di, WORD PTR [pTarget] + mov ax, WORD PTR [pTarget + 2] + mov es, ax + mov ax, WORD PTR [pSource + 2] + mov bx, ds + mov ds, ax + rep movsb + mov ds, bx + } + + /* + ** IMPORTANT: + ** ---------- + ** SS:SP is now invalid :-( This means that all local variables and + ** function arguments are invalid and NO function calls can be + ** made !!! We must fix up SS:SP so that function calls can safely + ** be made... + */ + + __asm { + mov ax, WORD PTR [_pr_top_of_task_stack] + sub ax, cxByteCount + mov sp, ax + }; + + /* + ** Resume execution of thread: t by restoring the thread's context. + ** + */ + Throw((_pr_currentThread)->md.context, 1); +} /* --- end MD_RESTORE_CONTEXT() --- */ + + +static void TraceDispatch( PRThread *thread ) +{ + int i; + + /* + ** push all DispatchTrace objects to down one slot. + ** Note: the last entry is lost; last-1 becomes last, etc. + */ + for( i = NUM_DISPATCHTRACE_OBJECTS -2; i >= 0; i-- ) + { + dt[i +1] = dt[i]; + } + + /* + ** Build dt[0] from t + */ + dt->thread = thread; + dt->state = thread->state; + dt->mdThreadNumber = thread->md.threadNumber; + dt->priority = thread->priority; + + return; +} /* --- end TraceDispatch() --- */ + + +/* $$ end W16thred.c */ diff --git a/nsprpub/pr/src/md/windows/w32ipcsem.c b/nsprpub/pr/src/md/windows/w32ipcsem.c new file mode 100644 index 00000000000..82201a804cd --- /dev/null +++ b/nsprpub/pr/src/md/windows/w32ipcsem.c @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: w32ipcsem.c + * Description: implements named semaphores for NT and WIN95. + */ + +#include "primpl.h" + +/* + * NSPR-to-NT access right mapping table for semaphore objects. + * + * The SYNCHRONIZE access is required by WaitForSingleObject. + * The SEMAPHORE_MODIFY_STATE access is required by ReleaseSemaphore. + * The OR of these three access masks must equal SEMAPHORE_ALL_ACCESS. + * This is because if a semaphore object with the specified name + * exists, CreateSemaphore requests SEMAPHORE_ALL_ACCESS access to + * the existing object. + */ +static DWORD semAccessTable[] = { + STANDARD_RIGHTS_REQUIRED|0x1, /* read (0x1 is "query state") */ + STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, /* write */ + 0 /* execute */ +}; + +#ifndef _PR_GLOBAL_THREADS_ONLY + +/* + * A fiber cannot call WaitForSingleObject because that + * will block the other fibers running on the same thread. + * If a fiber needs to wait on a (semaphore) handle, we + * create a native thread to call WaitForSingleObject and + * have the fiber join the native thread. + */ + +/* + * Arguments, return value, and error code for WaitForSingleObject + */ +struct WaitSingleArg { + HANDLE handle; + DWORD timeout; + DWORD rv; + DWORD error; +}; + +static void WaitSingleThread(void *arg) +{ + struct WaitSingleArg *warg = (struct WaitSingleArg *) arg; + + warg->rv = WaitForSingleObject(warg->handle, warg->timeout); + if (warg->rv == WAIT_FAILED) { + warg->error = GetLastError(); + } +} + +static DWORD FiberSafeWaitForSingleObject( + HANDLE hHandle, + DWORD dwMilliseconds +) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_IS_NATIVE_THREAD(me)) { + return WaitForSingleObject(hHandle, dwMilliseconds); + } else { + PRThread *waitThread; + struct WaitSingleArg warg; + PRStatus rv; + + warg.handle = hHandle; + warg.timeout = dwMilliseconds; + waitThread = PR_CreateThread( + PR_USER_THREAD, WaitSingleThread, &warg, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (waitThread == NULL) { + return WAIT_FAILED; + } + + rv = PR_JoinThread(waitThread); + PR_ASSERT(rv == PR_SUCCESS); + if (rv == PR_FAILURE) { + return WAIT_FAILED; + } + if (warg.rv == WAIT_FAILED) { + SetLastError(warg.error); + } + return warg.rv; + } +} + +#endif /* !_PR_GLOBAL_THREADS_ONLY */ + +PRSem *_PR_MD_OPEN_SEMAPHORE( + const char *osname, PRIntn flags, PRIntn mode, PRUintn value) +{ + PRSem *sem; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + sem = PR_NEW(PRSem); + if (sem == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + if (flags & PR_SEM_CREATE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, semAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + sem->sem = CreateSemaphore(lpSA, value, 0x7fffffff, osname); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (sem->sem == NULL) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + PR_DELETE(sem); + return NULL; + } + if ((flags & PR_SEM_EXCL) && (GetLastError() == ERROR_ALREADY_EXISTS)) { + PR_SetError(PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS); + CloseHandle(sem->sem); + PR_DELETE(sem); + return NULL; + } + } else { + sem->sem = OpenSemaphore( + SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, FALSE, osname); + if (sem->sem == NULL) { + DWORD err = GetLastError(); + + /* + * If we open a nonexistent named semaphore, NT + * returns ERROR_FILE_NOT_FOUND, while Win95 + * returns ERROR_INVALID_NAME + */ + if (err == ERROR_INVALID_NAME) { + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + } else { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + } + PR_DELETE(sem); + return NULL; + } + } + return sem; +} + +PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem) +{ + DWORD rv; + +#ifdef _PR_GLOBAL_THREADS_ONLY + rv = WaitForSingleObject(sem->sem, INFINITE); +#else + rv = FiberSafeWaitForSingleObject(sem->sem, INFINITE); +#endif + PR_ASSERT(rv == WAIT_FAILED || rv == WAIT_OBJECT_0); + if (rv == WAIT_FAILED) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + if (rv != WAIT_OBJECT_0) { + /* Should not happen */ + PR_SetError(PR_UNKNOWN_ERROR, 0); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem) +{ + if (ReleaseSemaphore(sem->sem, 1, NULL) == FALSE) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem) +{ + if (CloseHandle(sem->sem) == FALSE) { + _PR_MD_MAP_CLOSE_ERROR(GetLastError()); + return PR_FAILURE; + } + PR_DELETE(sem); + return PR_SUCCESS; +} diff --git a/nsprpub/pr/src/md/windows/w32poll.c b/nsprpub/pr/src/md/windows/w32poll.c new file mode 100644 index 00000000000..0bf5203a56d --- /dev/null +++ b/nsprpub/pr/src/md/windows/w32poll.c @@ -0,0 +1,351 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file implements _PR_MD_PR_POLL for Win32. + */ + +/* The default value of FD_SETSIZE is 64. */ +#define FD_SETSIZE 1024 + +#include "primpl.h" + +#if !defined(_PR_GLOBAL_THREADS_ONLY) + +struct select_data_s { + PRInt32 status; + PRInt32 error; + fd_set *rd, *wt, *ex; + const struct timeval *tv; +}; + +static void +_PR_MD_select_thread(void *cdata) +{ + struct select_data_s *cd = (struct select_data_s *)cdata; + + cd->status = select(0, cd->rd, cd->wt, cd->ex, cd->tv); + + if (cd->status == SOCKET_ERROR) { + cd->error = WSAGetLastError(); + } +} + +int _PR_NTFiberSafeSelect( + int nfds, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + const struct timeval *timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + int ready; + + if (_PR_IS_NATIVE_THREAD(me)) { + ready = _MD_SELECT(nfds, readfds, writefds, exceptfds, timeout); + } + else + { + /* + ** Creating a new thread on each call!! + ** I guess web server doesn't use non-block I/O. + */ + PRThread *selectThread; + struct select_data_s data; + data.status = 0; + data.error = 0; + data.rd = readfds; + data.wt = writefds; + data.ex = exceptfds; + data.tv = timeout; + + 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); + ready = data.status; + if (ready == SOCKET_ERROR) WSASetLastError(data.error); + } + return ready; +} + +#endif /* !defined(_PR_GLOBAL_THREADS_ONLY) */ + +PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + int ready, err; + fd_set rd, wt, ex; + fd_set *rdp, *wtp, *exp; + int nrd, nwt, nex; + PRFileDesc *bottom; + PRPollDesc *pd, *epd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + 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; + } + + nrd = nwt = nex = 0; + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); + + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + SOCKET osfd; + 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 = (SOCKET) bottom->secret->md.osfd; + if (in_flags_read & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_READ_SYS_READ; + FD_SET(osfd, &rd); + nrd++; + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + FD_SET(osfd, &wt); + nwt++; + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + FD_SET(osfd, &rd); + nrd++; + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + FD_SET(osfd, &wt); + nwt++; + } + if (pd->in_flags & PR_POLL_EXCEPT) { + FD_SET(osfd, &ex); + nex++; + } + } + } + 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 */ + } + } + } + else + { + pd->out_flags = 0; + } + } + + if (0 != ready) return ready; /* no need to block */ + + if ((nrd > FD_SETSIZE) || (nwt > FD_SETSIZE) || (nex > FD_SETSIZE)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + rdp = (0 == nrd) ? NULL : &rd; + wtp = (0 == nwt) ? NULL : &wt; + exp = (0 == nex) ? NULL : &ex; + + if ((NULL == rdp) && (NULL == wtp) && (NULL == exp)) { + PR_Sleep(timeout); + return 0; + } + + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = timeout / ticksPerSecond; + tv.tv_usec = PR_IntervalToMicroseconds( timeout % ticksPerSecond ); + tvp = &tv; + } + +#if defined(_PR_GLOBAL_THREADS_ONLY) + ready = _MD_SELECT(0, rdp, wtp, exp, tvp); +#else + ready = _PR_NTFiberSafeSelect(0, rdp, wtp, exp, tvp); +#endif + + /* + ** 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)) + { + SOCKET osfd; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + + osfd = (SOCKET) 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 == SOCKET_ERROR) + { + err = WSAGetLastError(); + if (err == WSAENOTSOCK) + { + /* Find the bad fds */ + int optval; + int optlen = sizeof(optval); + 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 (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(ready > 0); + } + else _PR_MD_MAP_SELECT_ERROR(err); + } + + return ready; +} diff --git a/nsprpub/pr/src/md/windows/w32rng.c b/nsprpub/pr/src/md/windows/w32rng.c new file mode 100644 index 00000000000..5232b5fae84 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w32rng.c @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include +#include +#include +#include + +static BOOL +CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow) +{ + LARGE_INTEGER liCount; + + if (!QueryPerformanceCounter(&liCount)) + return FALSE; + + *lpdwHigh = liCount.u.HighPart; + *lpdwLow = liCount.u.LowPart; + return TRUE; +} + +extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) +{ + DWORD dwHigh, dwLow, dwVal; + size_t n = 0; + size_t nBytes; + time_t sTime; + + if (size <= 0) + return 0; + + CurrentClockTickTime(&dwHigh, &dwLow); + + // get the maximally changing bits first + nBytes = sizeof(dwLow) > size ? size : sizeof(dwLow); + memcpy((char *)buf, &dwLow, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + nBytes = sizeof(dwHigh) > size ? size : sizeof(dwHigh); + memcpy(((char *)buf) + n, &dwHigh, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + // get the number of milliseconds that have elapsed since Windows started + dwVal = GetTickCount(); + + nBytes = sizeof(dwVal) > size ? size : sizeof(dwVal); + memcpy(((char *)buf) + n, &dwVal, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + // get the time in seconds since midnight Jan 1, 1970 + time(&sTime); + nBytes = sizeof(sTime) > size ? size : sizeof(sTime); + memcpy(((char *)buf) + n, &sTime, nBytes); + n += nBytes; + + return n; +} + diff --git a/nsprpub/pr/src/md/windows/w32shm.c b/nsprpub/pr/src/md/windows/w32shm.c new file mode 100644 index 00000000000..136b20d2de5 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w32shm.c @@ -0,0 +1,355 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include +#include + +#if defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY) + +extern PRLogModuleInfo *_pr_shm_lm; + +/* + * NSPR-to-NT access right mapping table for file-mapping objects. + * + * The OR of these three access masks must equal FILE_MAP_ALL_ACCESS. + * This is because if a file-mapping object with the specified name + * exists, CreateFileMapping requests full access to the existing + * object. + */ +static DWORD filemapAccessTable[] = { + FILE_MAP_ALL_ACCESS & ~FILE_MAP_WRITE, /* read */ + FILE_MAP_ALL_ACCESS & ~FILE_MAP_READ, /* write */ + 0 /* execute */ +}; + +extern PRSharedMemory * _MD_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +) +{ + char ipcname[PR_IPC_NAME_SIZE]; + PRStatus rc = PR_SUCCESS; + DWORD dwHi, dwLo; + PRSharedMemory *shm; + DWORD flProtect = ( PAGE_READWRITE ); + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + PR_SetError(PR_UNKNOWN_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: name is invalid")); + return(NULL); + } + + shm = PR_NEWZAP( PRSharedMemory ); + if ( NULL == shm ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); + return(NULL); + } + + shm->ipcname = PR_MALLOC( (PRUint32) (strlen( ipcname ) + 1) ); + if ( NULL == shm->ipcname ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); + PR_DELETE(shm); + return(NULL); + } + + /* copy args to struct */ + strcpy( shm->ipcname, ipcname ); + shm->size = size; + shm->mode = mode; + shm->flags = flags; + shm->ident = _PR_SHM_IDENT; + + if (flags & PR_SHM_CREATE ) { + dwHi = (DWORD) (((PRUint64) shm->size >> 32) & 0xffffffff); + dwLo = (DWORD) (shm->size & 0xffffffff); + + if (_PR_NT_MakeSecurityDescriptorACL(mode, filemapAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + shm->handle = CreateFileMapping( + (HANDLE)-1 , + lpSA, + flProtect, + dwHi, + dwLo, + shm->ipcname); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + + if ( NULL == shm->handle ) { + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: CreateFileMapping() failed: %s", + shm->ipcname )); + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_FREEIF( shm->ipcname ) + PR_DELETE( shm ); + return(NULL); + } else { + if (( flags & PR_SHM_EXCL) && ( GetLastError() == ERROR_ALREADY_EXISTS )) { + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: Request exclusive & already exists", + shm->ipcname )); + PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS ); + CloseHandle( shm->handle ); + PR_FREEIF( shm->ipcname ) + PR_DELETE( shm ); + return(NULL); + } else { + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: CreateFileMapping() success: %s, handle: %d", + shm->ipcname, shm->handle )); + return(shm); + } + } + } else { + shm->handle = OpenFileMapping( FILE_MAP_WRITE, TRUE, shm->ipcname ); + if ( NULL == shm->handle ) { + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: OpenFileMapping() failed: %s, error: %d", + shm->ipcname, PR_GetOSError())); + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + return(NULL); + } else { + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: OpenFileMapping() success: %s, handle: %d", + shm->ipcname, shm->handle )); + return(shm); + } + } + /* returns from separate paths */ +} + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ) +{ + PRUint32 access = FILE_MAP_WRITE; + void *addr; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + if ( PR_SHM_READONLY & flags ) + access = FILE_MAP_READ; + + addr = MapViewOfFile( shm->handle, + access, + 0, 0, + shm->size ); + + if ( NULL == addr ) { + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_LOG( _pr_shm_lm, PR_LOG_ERROR, + ("_MD_AttachSharedMemory: MapViewOfFile() failed. OSerror: %d", PR_GetOSError())); + } + + return( addr ); +} /* end _MD_ATTACH_SHARED_MEMORY() */ + + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ) +{ + PRStatus rc = PR_SUCCESS; + BOOL wrc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + wrc = UnmapViewOfFile( addr ); + if ( FALSE == wrc ) + { + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_LOG( _pr_shm_lm, PR_LOG_ERROR, + ("_MD_DetachSharedMemory: UnmapViewOfFile() failed. OSerror: %d", PR_GetOSError())); + rc = PR_FAILURE; + } + + return( rc ); +} + + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ) +{ + PRStatus rc = PR_SUCCESS; + BOOL wrc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + wrc = CloseHandle( shm->handle ); + if ( FALSE == wrc ) + { + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_LOG( _pr_shm_lm, PR_LOG_ERROR, + ("_MD_CloseSharedMemory: CloseHandle() failed. OSerror: %d", PR_GetOSError())); + rc = PR_FAILURE; + } + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + + return( rc ); +} /* end _MD_CLOSE_SHARED_MEMORY() */ + +extern PRStatus _MD_DeleteSharedMemory( const char *name ) +{ + return( PR_SUCCESS ); +} + + +/* +** Windows implementation of anonymous memory (file) map +*/ +extern PRLogModuleInfo *_pr_shma_lm; + +extern PRFileMap* _md_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +) +{ + PRFileMap *fm; + HANDLE hFileMap; + + fm = PR_CreateFileMap( (PRFileDesc*)-1, size, prot ); + if ( NULL == fm ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): PR_CreateFileMap(): failed")); + goto Finished; + } + + /* + ** Make fm->md.hFileMap inheritable. We can't use + ** GetHandleInformation and SetHandleInformation + ** because these two functions fail with + ** ERROR_CALL_NOT_IMPLEMENTED on Win95. + */ + if (DuplicateHandle(GetCurrentProcess(), fm->md.hFileMap, + GetCurrentProcess(), &hFileMap, + 0, TRUE /* inheritable */, + DUPLICATE_SAME_ACCESS) == FALSE) { + PR_SetError( PR_UNKNOWN_ERROR, GetLastError() ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): DuplicateHandle(): failed")); + PR_CloseFileMap( fm ); + fm = NULL; + goto Finished; + } + CloseHandle(fm->md.hFileMap); + fm->md.hFileMap = hFileMap; + +Finished: + return(fm); +} /* end md_OpenAnonFileMap() */ + +/* +** _md_ExportFileMapAsString() +** +*/ +extern PRStatus _md_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufSize, + char *buf +) +{ + PRIntn written; + + written = PR_snprintf( buf, (PRUint32) bufSize, "%d:%" PR_PRIdOSFD ":%ld", + (PRIntn)fm->prot, (PROsfd)fm->md.hFileMap, (PRInt32)fm->md.dwAccess ); + + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ExportFileMapAsString(): prot: %x, hFileMap: %x, dwAccess: %x", + fm->prot, fm->md.hFileMap, fm->md.dwAccess )); + + return((written == -1)? PR_FAILURE : PR_SUCCESS); +} /* end _md_ExportFileMapAsString() */ + + +/* +** _md_ImportFileMapFromString() +** +*/ +extern PRFileMap * _md_ImportFileMapFromString( + const char *fmstring +) +{ + PRIntn prot; + PROsfd hFileMap; + PRInt32 dwAccess; + PRFileMap *fm = NULL; + + PR_sscanf( fmstring, "%d:%" PR_SCNdOSFD ":%ld", + &prot, &hFileMap, &dwAccess ); + + fm = PR_NEWZAP(PRFileMap); + if ( NULL == fm ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): PR_NEWZAP(): Failed")); + return(fm); + } + + fm->prot = (PRFileMapProtect)prot; + fm->md.hFileMap = (HANDLE)hFileMap; + fm->md.dwAccess = (DWORD)dwAccess; + fm->fd = (PRFileDesc*)-1; + + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): fm: %p, prot: %d, hFileMap: %8.8x, dwAccess: %8.8x, fd: %x", + fm, prot, fm->md.hFileMap, fm->md.dwAccess, fm->fd)); + return(fm); +} /* end _md_ImportFileMapFromString() */ + +#else +Error! Why is PR_HAVE_WIN32_NAMED_SHARED_MEMORY not defined? +#endif /* PR_HAVE_WIN32_NAMED_SHARED_MEMORY */ +/* --- end w32shm.c --- */ diff --git a/nsprpub/pr/src/md/windows/w95cv.c b/nsprpub/pr/src/md/windows/w95cv.c new file mode 100644 index 00000000000..975ac4b06ff --- /dev/null +++ b/nsprpub/pr/src/md/windows/w95cv.c @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * w95cv.c -- Windows 95 Machine-Dependent Code for Condition Variables + * + * We implement our own condition variable wait queue. Each thread + * has a semaphore object (thread->md.blocked_sema) to block on while + * waiting on a condition variable. + * + * We use a deferred condition notify algorithm. When PR_NotifyCondVar + * or PR_NotifyAllCondVar is called, the condition notifies are simply + * recorded in the _MDLock structure. We defer the condition notifies + * until right after we unlock the lock. This way the awakened threads + * have a better chance to reaquire the lock. + */ + +#include "primpl.h" + +/* + * AddThreadToCVWaitQueueInternal -- + * + * Add the thread to the end of the condition variable's wait queue. + * The CV's lock must be locked when this function is called. + */ + +static void +AddThreadToCVWaitQueueInternal(PRThread *thred, struct _MDCVar *cv) +{ + PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL) + || (cv->waitTail == NULL && cv->waitHead == NULL)); + cv->nwait += 1; + thred->md.inCVWaitQueue = PR_TRUE; + thred->md.next = NULL; + thred->md.prev = cv->waitTail; + if (cv->waitHead == NULL) { + cv->waitHead = thred; + } else { + cv->waitTail->md.next = thred; + } + cv->waitTail = thred; +} + +/* + * md_UnlockAndPostNotifies -- + * + * Unlock the lock, and then do the deferred condition notifies. + * If waitThred and waitCV are not NULL, waitThred is added to + * the wait queue of waitCV before the lock is unlocked. + * + * This function is called by _PR_MD_WAIT_CV and _PR_MD_UNLOCK, + * the two places where a lock is unlocked. + */ +static void +md_UnlockAndPostNotifies( + _MDLock *lock, + PRThread *waitThred, + _MDCVar *waitCV) +{ + PRIntn index; + _MDNotified post; + _MDNotified *notified, *prev = NULL; + + /* + * Time to actually notify any conditions that were affected + * while the lock was held. Get a copy of the list that's in + * the lock structure and then zero the original. If it's + * linked to other such structures, we own that storage. + */ + post = lock->notified; /* a safe copy; we own the lock */ + +#if defined(DEBUG) + ZeroMemory(&lock->notified, sizeof(_MDNotified)); /* reset */ +#else + lock->notified.length = 0; /* these are really sufficient */ + lock->notified.link = NULL; +#endif + + /* + * Figure out how many threads we need to wake up. + */ + notified = &post; /* this is where we start */ + do { + for (index = 0; index < notified->length; ++index) { + _MDCVar *cv = notified->cv[index].cv; + PRThread *thred; + int i; + + /* Fast special case: no waiting threads */ + if (cv->waitHead == NULL) { + notified->cv[index].notifyHead = NULL; + continue; + } + + /* General case */ + if (-1 == notified->cv[index].times) { + /* broadcast */ + thred = cv->waitHead; + while (thred != NULL) { + thred->md.inCVWaitQueue = PR_FALSE; + thred = thred->md.next; + } + notified->cv[index].notifyHead = cv->waitHead; + cv->waitHead = cv->waitTail = NULL; + cv->nwait = 0; + } else { + thred = cv->waitHead; + i = notified->cv[index].times; + while (thred != NULL && i > 0) { + thred->md.inCVWaitQueue = PR_FALSE; + thred = thred->md.next; + i--; + } + notified->cv[index].notifyHead = cv->waitHead; + cv->waitHead = thred; + if (cv->waitHead == NULL) { + cv->waitTail = NULL; + } else { + if (cv->waitHead->md.prev != NULL) { + cv->waitHead->md.prev->md.next = NULL; + cv->waitHead->md.prev = NULL; + } + } + cv->nwait -= notified->cv[index].times - i; + } + } + notified = notified->link; + } while (NULL != notified); + + if (waitThred) { + AddThreadToCVWaitQueueInternal(waitThred, waitCV); + } + + /* Release the lock before notifying */ + LeaveCriticalSection(&lock->mutex); + + notified = &post; /* this is where we start */ + do { + for (index = 0; index < notified->length; ++index) { + PRThread *thred; + PRThread *next; + + thred = notified->cv[index].notifyHead; + while (thred != NULL) { + BOOL rv; + + next = thred->md.next; + thred->md.prev = thred->md.next = NULL; + + rv = ReleaseSemaphore(thred->md.blocked_sema, 1, NULL); + PR_ASSERT(rv != 0); + thred = next; + } + } + prev = notified; + notified = notified->link; + if (&post != prev) PR_DELETE(prev); + } while (NULL != notified); +} + +/* + * Notifies just get posted to the protecting mutex. The + * actual notification is done when the lock is released so that + * MP systems don't contend for a lock that they can't have. + */ +static void md_PostNotifyToCvar(_MDCVar *cvar, _MDLock *lock, + PRBool broadcast) +{ + PRIntn index = 0; + _MDNotified *notified = &lock->notified; + + while (1) { + for (index = 0; index < notified->length; ++index) { + if (notified->cv[index].cv == cvar) { + if (broadcast) { + notified->cv[index].times = -1; + } else if (-1 != notified->cv[index].times) { + notified->cv[index].times += 1; + } + return; + } + } + /* if not full, enter new CV in this array */ + if (notified->length < _MD_CV_NOTIFIED_LENGTH) break; + + /* if there's no link, create an empty array and link it */ + if (NULL == notified->link) { + notified->link = PR_NEWZAP(_MDNotified); + } + + notified = notified->link; + } + + /* A brand new entry in the array */ + notified->cv[index].times = (broadcast) ? -1 : 1; + notified->cv[index].cv = cvar; + notified->length += 1; +} + +/* + * _PR_MD_NEW_CV() -- Creating new condition variable + * ... Solaris uses cond_init() in similar function. + * + * returns: -1 on failure + * 0 when it succeeds. + * + */ +PRInt32 +_PR_MD_NEW_CV(_MDCVar *cv) +{ + cv->magic = _MD_MAGIC_CV; + /* + * The waitHead, waitTail, and nwait fields are zeroed + * when the PRCondVar structure is created. + */ + return 0; +} + +void _PR_MD_FREE_CV(_MDCVar *cv) +{ + cv->magic = (PRUint32)-1; + return; +} + +/* + * _PR_MD_WAIT_CV() -- Wait on condition variable + */ +void _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout ) +{ + PRThread *thred = _PR_MD_CURRENT_THREAD(); + DWORD rv; + DWORD msecs = (timeout == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(timeout); + + /* + * If we have pending notifies, post them now. + */ + if (0 != lock->notified.length) { + md_UnlockAndPostNotifies(lock, thred, cv); + } else { + AddThreadToCVWaitQueueInternal(thred, cv); + LeaveCriticalSection(&lock->mutex); + } + + /* Wait for notification or timeout; don't really care which */ + rv = WaitForSingleObject(thred->md.blocked_sema, msecs); + + EnterCriticalSection(&(lock->mutex)); + + PR_ASSERT(rv != WAIT_ABANDONED); + PR_ASSERT(rv != WAIT_FAILED); + PR_ASSERT(rv != WAIT_OBJECT_0 || thred->md.inCVWaitQueue == PR_FALSE); + + if (rv == WAIT_TIMEOUT) { + if (thred->md.inCVWaitQueue) { + PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL) + || (cv->waitTail == NULL && cv->waitHead == NULL)); + cv->nwait -= 1; + thred->md.inCVWaitQueue = PR_FALSE; + if (cv->waitHead == thred) { + cv->waitHead = thred->md.next; + if (cv->waitHead == NULL) { + cv->waitTail = NULL; + } else { + cv->waitHead->md.prev = NULL; + } + } else { + PR_ASSERT(thred->md.prev != NULL); + thred->md.prev->md.next = thred->md.next; + if (thred->md.next != NULL) { + thred->md.next->md.prev = thred->md.prev; + } else { + PR_ASSERT(cv->waitTail == thred); + cv->waitTail = thred->md.prev; + } + } + thred->md.next = thred->md.prev = NULL; + } else { + /* + * This thread must have been notified, but the + * ReleaseSemaphore call happens after WaitForSingleObject + * times out. Wait on the semaphore again to make it + * non-signaled. We assume this wait won't take long. + */ + rv = WaitForSingleObject(thred->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + } + PR_ASSERT(thred->md.inCVWaitQueue == PR_FALSE); + return; +} /* --- end _PR_MD_WAIT_CV() --- */ + +void _PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock) +{ + md_PostNotifyToCvar(cv, lock, PR_FALSE); + return; +} + +void _PR_MD_NOTIFYALL_CV(_MDCVar *cv, _MDLock *lock) +{ + md_PostNotifyToCvar(cv, lock, PR_TRUE); + return; +} + +void _PR_MD_UNLOCK(_MDLock *lock) +{ + if (0 != lock->notified.length) { + md_UnlockAndPostNotifies(lock, NULL, NULL); + } else { + LeaveCriticalSection(&lock->mutex); + } + return; +} diff --git a/nsprpub/pr/src/md/windows/w95dllmain.c b/nsprpub/pr/src/md/windows/w95dllmain.c new file mode 100644 index 00000000000..1dafe7a22bb --- /dev/null +++ b/nsprpub/pr/src/md/windows/w95dllmain.c @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * The DLL entry point (DllMain) for NSPR. + * + * This is used to detach threads that were automatically attached by + * nspr. + */ + +#include +#include + +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: + if (_pr_initialized) { + 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/nsprpub/pr/src/md/windows/w95io.c b/nsprpub/pr/src/md/windows/w95io.c new file mode 100644 index 00000000000..0ecf99a898a --- /dev/null +++ b/nsprpub/pr/src/md/windows/w95io.c @@ -0,0 +1,1568 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Masayuki Nakano + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Windows 95 IO module + * + * Assumes synchronous I/O. + * + */ + +#include "primpl.h" +#include +#include +#ifdef MOZ_UNICODE +#include +#endif /* MOZ_UNICODE */ + + +struct _MDLock _pr_ioq_lock; + +/* + * NSPR-to-NT access right mapping table for files. + */ +static DWORD fileAccessTable[] = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE +}; + +/* + * NSPR-to-NT access right mapping table for directories. + */ +static DWORD dirAccessTable[] = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE|FILE_DELETE_CHILD, + FILE_GENERIC_EXECUTE +}; + +/* + * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME. + * We store the value in a PRTime variable for convenience. + * This constant is used by _PR_FileTimeToPRTime(). + */ +#if defined(__MINGW32__) +static const PRTime _pr_filetime_offset = 116444736000000000LL; +#else +static const PRTime _pr_filetime_offset = 116444736000000000i64; +#endif + +typedef BOOL (WINAPI *GetFileAttributesExFn)(LPCTSTR, + GET_FILEEX_INFO_LEVELS, + LPVOID); +static GetFileAttributesExFn getFileAttributesEx; +static void InitGetFileInfo(void); + +static void InitUnicodeSupport(void); + +static PRBool IsPrevCharSlash(const char *str, const char *current); + +void +_PR_MD_INIT_IO() +{ + WORD WSAVersion = 0x0101; + WSADATA WSAData; + int err; + + err = WSAStartup( WSAVersion, &WSAData ); + PR_ASSERT(0 == err); + +#ifdef DEBUG + /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */ + { + SYSTEMTIME systime; + union { + PRTime prt; + FILETIME ft; + } filetime; + BOOL rv; + + systime.wYear = 1970; + systime.wMonth = 1; + /* wDayOfWeek is ignored */ + systime.wDay = 1; + systime.wHour = 0; + systime.wMinute = 0; + systime.wSecond = 0; + systime.wMilliseconds = 0; + + rv = SystemTimeToFileTime(&systime, &filetime.ft); + PR_ASSERT(0 != rv); + PR_ASSERT(filetime.prt == _pr_filetime_offset); + } +#endif /* DEBUG */ + + _PR_NT_InitSids(); + + InitGetFileInfo(); + + InitUnicodeSupport(); + + _PR_MD_InitSockets(); +} + +PRStatus +_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + DWORD rv; + + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(ticks); + rv = WaitForSingleObject(thread->md.blocked_sema, msecs); + switch(rv) + { + case WAIT_OBJECT_0: + return PR_SUCCESS; + break; + case WAIT_TIMEOUT: + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + ; + } else { + if (thread->wait.cvar != NULL) { + thread->wait.cvar = NULL; + _PR_THREAD_UNLOCK(thread); + } else { + /* The CVAR was notified just as the timeout + * occurred. This led to us being notified twice. + * call WaitForSingleObject() to clear the semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, 0); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + } + return PR_SUCCESS; + break; + default: + return PR_FAILURE; + break; + } +} +PRStatus +_PR_MD_WAKEUP_WAITER(PRThread *thread) +{ + if ( _PR_IS_NATIVE_THREAD(thread) ) + { + if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE) + return PR_FAILURE; + else + return PR_SUCCESS; + } +} + + +/* --- FILE IO ----------------------------------------------------------- */ +/* + * _PR_MD_OPEN() -- Open a file + * + * returns: a fileHandle + * + * The NSPR open flags (osflags) are translated into flags for Win95 + * + * Mode seems to be passed in as a unix style file permissions argument + * as in 0666, in the case of opening the logFile. + * + */ +PROsfd +_PR_MD_OPEN(const char *name, PRIntn osflags, int mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) + access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) + access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) { + if (osflags & PR_TRUNCATE) + flags = CREATE_ALWAYS; + else + flags = OPEN_ALWAYS; + } else { + if (osflags & PR_TRUNCATE) + flags = TRUNCATE_EXISTING; + else + flags = OPEN_EXISTING; + } + + file = CreateFile(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + flags, + flag6, + NULL); + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + return (PROsfd)file; +} + +PROsfd +_PR_MD_OPEN_FILE(const char *name, PRIntn osflags, int mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (osflags & PR_CREATE_FILE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + } + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) + access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) + access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) { + if (osflags & PR_TRUNCATE) + flags = CREATE_ALWAYS; + else + flags = OPEN_ALWAYS; + } else { + if (osflags & PR_TRUNCATE) + flags = TRUNCATE_EXISTING; + else + flags = OPEN_EXISTING; + } + + file = CreateFile(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + lpSA, + flags, + flag6, + NULL); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + return (PROsfd)file; +} + +PRInt32 +_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) +{ + PRUint32 bytes; + int rv, err; + + rv = ReadFile((HANDLE)fd->secret->md.osfd, + (LPVOID)buf, + len, + &bytes, + NULL); + + if (rv == 0) + { + err = GetLastError(); + /* ERROR_HANDLE_EOF can only be returned by async io */ + PR_ASSERT(err != ERROR_HANDLE_EOF); + if (err == ERROR_BROKEN_PIPE) + return 0; + else { + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + } + return bytes; +} + +PRInt32 +_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) +{ + PROsfd f = fd->secret->md.osfd; + PRInt32 bytes; + int rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + rv = WriteFile((HANDLE)f, + buf, + len, + &bytes, + NULL ); + + if (rv == 0) + { + _PR_MD_MAP_WRITE_ERROR(GetLastError()); + return -1; + } + return bytes; +} /* --- end _PR_MD_WRITE() --- */ + +PROffset32 +_PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) +{ + DWORD moveMethod; + PROffset32 rv; + + switch (whence) { + case PR_SEEK_SET: + moveMethod = FILE_BEGIN; + break; + case PR_SEEK_CUR: + moveMethod = FILE_CURRENT; + break; + case PR_SEEK_END: + moveMethod = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod); + + /* + * If the lpDistanceToMoveHigh argument (third argument) is + * NULL, SetFilePointer returns 0xffffffff on failure. + */ + if (-1 == rv) { + _PR_MD_MAP_LSEEK_ERROR(GetLastError()); + } + return rv; +} + +PROffset64 +_PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) +{ + DWORD moveMethod; + LARGE_INTEGER li; + DWORD err; + + switch (whence) { + case PR_SEEK_SET: + moveMethod = FILE_BEGIN; + break; + case PR_SEEK_CUR: + moveMethod = FILE_CURRENT; + break; + case PR_SEEK_END: + moveMethod = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + li.QuadPart = offset; + li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd, + li.LowPart, &li.HighPart, moveMethod); + + if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(err); + li.QuadPart = -1; + } + return li.QuadPart; +} + +/* + * This is documented to succeed on read-only files, but Win32's + * FlushFileBuffers functions fails with "access denied" in such a + * case. So we only signal an error if the error is *not* "access + * denied". + */ +PRInt32 +_PR_MD_FSYNC(PRFileDesc *fd) +{ + /* + * From the documentation: + * + * On Windows NT, the function FlushFileBuffers fails if hFile + * is a handle to console output. That is because console + * output is not buffered. The function returns FALSE, and + * GetLastError returns ERROR_INVALID_HANDLE. + * + * On the other hand, on Win95, it returns without error. I cannot + * assume that 0, 1, and 2 are console, because if someone closes + * System.out and then opens a file, they might get file descriptor + * 1. An error on *that* version of 1 should be reported, whereas + * an error on System.out (which was the original 1) should be + * ignored. So I use isatty() to ensure that such an error was due + * to this bogosity, and if it was, I ignore the error. + */ + + BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd); + + if (!ok) { + DWORD err = GetLastError(); + if (err != ERROR_ACCESS_DENIED) { // from winerror.h + _PR_MD_MAP_FSYNC_ERROR(err); + return -1; + } + } + return 0; +} + +PRInt32 +_MD_CloseFile(PROsfd osfd) +{ + PRInt32 rv; + + rv = (CloseHandle((HANDLE)osfd))?0:-1; + if (rv == -1) + _PR_MD_MAP_CLOSE_ERROR(GetLastError()); + return rv; +} + + +/* --- DIR IO ------------------------------------------------------------ */ +#define GetFileFromDIR(d) (d)->d_entry.cFileName +#define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + +void FlipSlashes(char *cp, size_t len) +{ + while (len-- > 0) { + if (cp[0] == '/') { + cp[0] = PR_DIRECTORY_SEPARATOR; + } + cp = _mbsinc(cp); + } +} /* end FlipSlashes() */ + + +/* +** +** Local implementations of standard Unix RTL functions which are not provided +** by the VC RTL. +** +*/ + +PRStatus +_PR_MD_CLOSE_DIR(_MDDir *d) +{ + if ( d ) { + if (FindClose(d->d_hdl)) { + d->magic = (PRUint32)-1; + return PR_SUCCESS; + } else { + _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; +} + + +PRStatus +_PR_MD_OPEN_DIR(_MDDir *d, const char *name) +{ + char filename[ MAX_PATH ]; + size_t len; + + len = strlen(name); + /* Need 5 bytes for \*.* and the trailing null byte. */ + if (len + 5 > MAX_PATH) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return PR_FAILURE; + } + strcpy(filename, name); + + /* + * If 'name' ends in a slash or backslash, do not append + * another backslash. + */ + if (IsPrevCharSlash(filename, filename + len)) { + len--; + } + strcpy(&filename[len], "\\*.*"); + FlipSlashes( filename, strlen(filename) ); + + d->d_hdl = FindFirstFile( filename, &(d->d_entry) ); + if ( d->d_hdl == INVALID_HANDLE_VALUE ) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + d->firstEntry = PR_TRUE; + d->magic = _MD_MAGIC_DIR; + return PR_SUCCESS; +} + +char * +_PR_MD_READ_DIR(_MDDir *d, PRIntn flags) +{ + PRInt32 err; + BOOL rv; + char *fileName; + + if ( d ) { + while (1) { + if (d->firstEntry) { + d->firstEntry = PR_FALSE; + rv = 1; + } else { + rv = FindNextFile(d->d_hdl, &(d->d_entry)); + } + if (rv == 0) { + break; + } + fileName = GetFileFromDIR(d); + if ( (flags & PR_SKIP_DOT) && + (fileName[0] == '.') && (fileName[1] == '\0')) + continue; + if ( (flags & PR_SKIP_DOT_DOT) && + (fileName[0] == '.') && (fileName[1] == '.') && + (fileName[2] == '\0')) + continue; + if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) + continue; + return fileName; + } + err = GetLastError(); + PR_ASSERT(NO_ERROR != err); + _PR_MD_MAP_READDIR_ERROR(err); + return NULL; + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; +} + +PRInt32 +_PR_MD_DELETE(const char *name) +{ + if (DeleteFile(name)) { + return 0; + } else { + _PR_MD_MAP_DELETE_ERROR(GetLastError()); + return -1; + } +} + +void +_PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm) +{ + PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime)); + CopyMemory(prtm, filetime, sizeof(PRTime)); +#if defined(__MINGW32__) + *prtm = (*prtm - _pr_filetime_offset) / 10LL; +#else + *prtm = (*prtm - _pr_filetime_offset) / 10i64; +#endif + +#ifdef DEBUG + /* Doublecheck our calculation. */ + { + SYSTEMTIME systime; + PRExplodedTime etm; + PRTime cmp; /* for comparison */ + BOOL rv; + + rv = FileTimeToSystemTime(filetime, &systime); + PR_ASSERT(0 != rv); + + /* + * PR_ImplodeTime ignores wday and yday. + */ + etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC; + etm.tm_sec = systime.wSecond; + etm.tm_min = systime.wMinute; + etm.tm_hour = systime.wHour; + etm.tm_mday = systime.wDay; + etm.tm_month = systime.wMonth - 1; + etm.tm_year = systime.wYear; + /* + * It is not well-documented what time zone the FILETIME's + * are in. WIN32_FIND_DATA is documented to be in UTC (GMT). + * But BY_HANDLE_FILE_INFORMATION is unclear about this. + * By our best judgement, we assume that FILETIME is in UTC. + */ + etm.tm_params.tp_gmt_offset = 0; + etm.tm_params.tp_dst_offset = 0; + cmp = PR_ImplodeTime(&etm); + + /* + * SYSTEMTIME is in milliseconds precision, so we convert PRTime's + * microseconds to milliseconds before doing the comparison. + */ + PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC)); + } +#endif /* DEBUG */ +} + +PRInt32 +_PR_MD_STAT(const char *fn, struct stat *info) +{ + PRInt32 rv; + + rv = _stat(fn, (struct _stat *)info); + if (-1 == rv) { + /* + * Check for MSVC runtime library _stat() bug. + * (It's really a bug in FindFirstFile().) + * If a pathname ends in a backslash or slash, + * e.g., c:\temp\ or c:/temp/, _stat() will fail. + * Note: a pathname ending in a slash (e.g., c:/temp/) + * can be handled by _stat() on NT but not on Win95. + * + * We remove the backslash or slash at the end and + * try again. + */ + + size_t len = strlen(fn); + if (len > 0 && len <= _MAX_PATH + && IsPrevCharSlash(fn, fn + len)) { + char newfn[_MAX_PATH + 1]; + + strcpy(newfn, fn); + newfn[len - 1] = '\0'; + rv = _stat(newfn, (struct _stat *)info); + } + } + + if (-1 == rv) { + _PR_MD_MAP_STAT_ERROR(errno); + } + return rv; +} + +#define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\') + +static PRBool +IsPrevCharSlash(const char *str, const char *current) +{ + const char *prev; + + if (str >= current) + return PR_FALSE; + prev = _mbsdec(str, current); + return (prev == current - 1) && _PR_IS_SLASH(*prev); +} + +/* + * IsRootDirectory -- + * + * Return PR_TRUE if the pathname 'fn' is a valid root directory, + * else return PR_FALSE. The char buffer pointed to by 'fn' must + * be writable. During the execution of this function, the contents + * of the buffer pointed to by 'fn' may be modified, but on return + * the original contents will be restored. 'buflen' is the size of + * the buffer pointed to by 'fn'. + * + * Root directories come in three formats: + * 1. / or \, meaning the root directory of the current drive. + * 2. C:/ or C:\, where C is a drive letter. + * 3. \\\\ or + * \\\, meaning the root directory + * of a UNC (Universal Naming Convention) name. + */ + +static PRBool +IsRootDirectory(char *fn, size_t buflen) +{ + char *p; + PRBool slashAdded = PR_FALSE; + PRBool rv = PR_FALSE; + + if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') { + return PR_TRUE; + } + + if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2]) + && fn[3] == '\0') { + rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; + return rv; + } + + /* The UNC root directory */ + + if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) { + /* The 'server' part should have at least one character. */ + p = &fn[2]; + if (*p == '\0' || _PR_IS_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the next slash */ + do { + p = _mbsinc(p); + } while (*p != '\0' && !_PR_IS_SLASH(*p)); + if (*p == '\0') { + return PR_FALSE; + } + + /* The 'share' part should have at least one character. */ + p++; + if (*p == '\0' || _PR_IS_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the final slash */ + do { + p = _mbsinc(p); + } while (*p != '\0' && !_PR_IS_SLASH(*p)); + if (_PR_IS_SLASH(*p) && p[1] != '\0') { + return PR_FALSE; + } + if (*p == '\0') { + /* + * GetDriveType() doesn't work correctly if the + * path is of the form \\server\share, so we add + * a final slash temporarily. + */ + if ((p + 1) < (fn + buflen)) { + *p++ = '\\'; + *p = '\0'; + slashAdded = PR_TRUE; + } else { + return PR_FALSE; /* name too long */ + } + } + rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; + /* restore the 'fn' buffer */ + if (slashAdded) { + *--p = '\0'; + } + } + return rv; +} + +/* + * InitGetFileInfo -- + * + * Called during IO init. Checks for the existence of the system function + * GetFileAttributeEx, which when available is used in GETFILEINFO calls. + * If the routine exists, then the address of the routine is stored in the + * variable getFileAttributesEx, which will be used to call the routine. + */ +static void InitGetFileInfo(void) +{ + HMODULE module; + module = GetModuleHandle("Kernel32.dll"); + if (!module) { + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("InitGetFileInfo: GetModuleHandle() failed: %d", + GetLastError())); + return; + } + + getFileAttributesEx = (GetFileAttributesExFn) + GetProcAddress(module, "GetFileAttributesExA"); +} + +/* + * If GetFileAttributeEx doesn't exist, we call FindFirstFile as a + * fallback. + */ +static BOOL +GetFileAttributesExFB(const char *fn, WIN32_FIND_DATA *findFileData) +{ + HANDLE hFindFile; + + /* + * FindFirstFile() expands wildcard characters. So + * we make sure the pathname contains no wildcard. + */ + if (NULL != _mbspbrk(fn, "?*")) { + SetLastError(ERROR_INVALID_NAME); + return FALSE; + } + + hFindFile = FindFirstFile(fn, findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + DWORD len; + char *filePart; + char pathbuf[MAX_PATH + 1]; + + /* + * FindFirstFile() does not work correctly on root directories. + * It also doesn't work correctly on a pathname that ends in a + * slash. So we first check to see if the pathname specifies a + * root directory. If not, and if the pathname ends in a slash, + * we remove the final slash and try again. + */ + + /* + * If the pathname does not contain ., \, and /, it cannot be + * a root directory or a pathname that ends in a slash. + */ + if (NULL == _mbspbrk(fn, ".\\/")) { + return FALSE; + } + len = GetFullPathName(fn, sizeof(pathbuf), pathbuf, + &filePart); + if (0 == len) { + return FALSE; + } + if (len > sizeof(pathbuf)) { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return FALSE; + } + if (IsRootDirectory(pathbuf, sizeof(pathbuf))) { + findFileData->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; + /* The file size doesn't have a meaning for directories. */ + findFileData->nFileSizeHigh = 0; + findFileData->nFileSizeLow = 0; + /* + * For a directory, these timestamps all specify when the + * directory is created. The creation time doesn't make + * sense for root directories, so we set it to (NSPR) time 0. + */ + memcpy(&findFileData->ftCreationTime, &_pr_filetime_offset, 8); + findFileData->ftLastAccessTime = findFileData->ftCreationTime; + findFileData->ftLastWriteTime = findFileData->ftCreationTime; + return TRUE; + } + if (!IsPrevCharSlash(pathbuf, pathbuf + len)) { + return FALSE; + } else { + pathbuf[len - 1] = '\0'; + hFindFile = FindFirstFile(pathbuf, findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + return FALSE; + } + } + } + + FindClose(hFindFile); + return TRUE; +} + +PRInt32 +_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) +{ + WIN32_FIND_DATA findFileData; + BOOL rv; + + if (NULL == fn || '\0' == *fn) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + /* GetFileAttributesEx is supported on Win 2K and up. */ + if (getFileAttributesEx) { + rv = getFileAttributesEx(fn, GetFileExInfoStandard, &findFileData); + } else { + rv = GetFileAttributesExFB(fn, &findFileData); + } + if (!rv) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + info->type = PR_FILE_DIRECTORY; + } else { + info->type = PR_FILE_FILE; + } + + info->size = findFileData.nFileSizeHigh; + info->size = (info->size << 32) + findFileData.nFileSizeLow; + + _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); + + if (0 == findFileData.ftCreationTime.dwLowDateTime && + 0 == findFileData.ftCreationTime.dwHighDateTime) { + info->creationTime = info->modifyTime; + } else { + _PR_FileTimeToPRTime(&findFileData.ftCreationTime, + &info->creationTime); + } + + return 0; +} + +PRInt32 +_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) +{ + PRFileInfo64 info64; + PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64); + if (0 == rv) + { + info->type = info64.type; + info->size = (PRUint32) info64.size; + info->modifyTime = info64.modifyTime; + info->creationTime = info64.creationTime; + } + return rv; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + int rv; + + BY_HANDLE_FILE_INFORMATION hinfo; + + rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo); + if (rv == FALSE) { + _PR_MD_MAP_FSTAT_ERROR(GetLastError()); + return -1; + } + + if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_FILE; + + info->size = hinfo.nFileSizeHigh; + info->size = (info->size << 32) + hinfo.nFileSizeLow; + + _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) ); + _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) ); + + return 0; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) +{ + PRFileInfo64 info64; + int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64); + if (0 == rv) + { + info->type = info64.type; + info->modifyTime = info64.modifyTime; + info->creationTime = info64.creationTime; + LL_L2I(info->size, info64.size); + } + return rv; +} + +PRStatus +_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) +{ + BOOL rv; + + /* + * The SetHandleInformation function fails with the + * ERROR_CALL_NOT_IMPLEMENTED error on Win95. + */ + rv = SetHandleInformation( + (HANDLE)fd->secret->md.osfd, + HANDLE_FLAG_INHERIT, + inheritable ? HANDLE_FLAG_INHERIT : 0); + if (0 == rv) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void +_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) +{ + if (imported) { + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + fd->secret->inheritable = _PR_TRI_FALSE; + } +} + +void +_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) +{ + DWORD flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) { + if (flags & HANDLE_FLAG_INHERIT) { + fd->secret->inheritable = _PR_TRI_TRUE; + } else { + fd->secret->inheritable = _PR_TRI_FALSE; + } + } +} + +PRInt32 +_PR_MD_RENAME(const char *from, const char *to) +{ + /* Does this work with dot-relative pathnames? */ + if (MoveFile(from, to)) { + return 0; + } else { + _PR_MD_MAP_RENAME_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_ACCESS(const char *name, PRAccessHow how) +{ +PRInt32 rv; + switch (how) { + case PR_ACCESS_WRITE_OK: + rv = _access(name, 02); + break; + case PR_ACCESS_READ_OK: + rv = _access(name, 04); + break; + case PR_ACCESS_EXISTS: + return _access(name, 00); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (rv < 0) + _PR_MD_MAP_ACCESS_ERROR(errno); + return rv; +} + +PRInt32 +_PR_MD_MKDIR(const char *name, PRIntn mode) +{ + /* XXXMB - how to translate the "mode"??? */ + if (CreateDirectory(name, NULL)) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_MAKE_DIR(const char *name, PRIntn mode) +{ + BOOL rv; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + rv = CreateDirectory(name, lpSA); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (rv) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_RMDIR(const char *name) +{ + if (RemoveDirectory(name)) { + return 0; + } else { + _PR_MD_MAP_RMDIR_ERROR(GetLastError()); + return -1; + } +} + +PRStatus +_PR_MD_LOCKFILE(PROsfd f) +{ + PRStatus rc = PR_SUCCESS; + DWORD rv; + + rv = LockFile( (HANDLE)f, + 0l, 0l, + 0x0l, 0xffffffffl ); + if ( rv == 0 ) { + DWORD rc = GetLastError(); + PR_LOG( _pr_io_lm, PR_LOG_ERROR, + ("_PR_MD_LOCKFILE() failed. Error: %d", rc )); + rc = PR_FAILURE; + } + + return rc; +} /* end _PR_MD_LOCKFILE() */ + +PRStatus +_PR_MD_TLOCKFILE(PROsfd f) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +} /* end _PR_MD_TLOCKFILE() */ + + +PRStatus +_PR_MD_UNLOCKFILE(PROsfd f) +{ + PRInt32 rv; + + rv = UnlockFile( (HANDLE) f, + 0l, 0l, + 0x0l, 0xffffffffl ); + + if ( rv ) + { + return PR_SUCCESS; + } + else + { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } +} /* end _PR_MD_UNLOCKFILE() */ + +PRInt32 +_PR_MD_PIPEAVAILABLE(PRFileDesc *fd) +{ + if (NULL == fd) + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +#ifdef MOZ_UNICODE + +typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); +static CreateFileWFn createFileW = CreateFileW; +typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW); +static FindFirstFileWFn findFirstFileW = FindFirstFileW; +typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW); +static FindNextFileWFn findNextFileW = FindNextFileW; +typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *); +static GetFullPathNameWFn getFullPathNameW = GetFullPathNameW; +typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR); +static GetDriveTypeWFn getDriveTypeW = GetDriveTypeW; + +#endif /* MOZ_UNICODE */ + +PRBool _pr_useUnicode = PR_FALSE; + +static void InitUnicodeSupport(void) +{ + /* + * The W functions exist on Win9x as stubs that fail with the + * ERROR_CALL_NOT_IMPLEMENTED error. We plan to emulate the + * MSLU W functions on Win9x in the future. + */ + + /* Find out if we are running on a Unicode enabled version of Windows */ + OSVERSIONINFOA osvi = {0}; + + osvi.dwOSVersionInfoSize = sizeof(osvi); + if (GetVersionExA(&osvi)) { + _pr_useUnicode = (osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT); + } else { + _pr_useUnicode = PR_FALSE; + } +#ifdef DEBUG + /* + * In debug builds, allow explicit use of ANSI methods to simulate + * a Win9x environment for testing purposes. + */ + if (getenv("WINAPI_USE_ANSI")) + _pr_useUnicode = PR_FALSE; +#endif +} + +#ifdef MOZ_UNICODE + +/* ================ UTF16 Interfaces ================================ */ +void FlipSlashesW(PRUnichar *cp, size_t len) +{ + while (len-- > 0) { + if (cp[0] == L'/') { + cp[0] = L'\\'; + } + cp++; + } +} /* end FlipSlashesW() */ + +PROsfd +_PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (osflags & PR_CREATE_FILE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + } + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) + access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) + access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) { + if (osflags & PR_TRUNCATE) + flags = CREATE_ALWAYS; + else + flags = OPEN_ALWAYS; + } else { + if (osflags & PR_TRUNCATE) + flags = TRUNCATE_EXISTING; + else + flags = OPEN_EXISTING; + } + + file = createFileW(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + lpSA, + flags, + flag6, + NULL); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + return (PROsfd)file; +} + +PRStatus +_PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name) +{ + PRUnichar filename[ MAX_PATH ]; + int len; + + len = wcslen(name); + /* Need 5 bytes for \*.* and the trailing null byte. */ + if (len + 5 > MAX_PATH) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return PR_FAILURE; + } + wcscpy(filename, name); + + /* + * If 'name' ends in a slash or backslash, do not append + * another backslash. + */ + if (filename[len - 1] == L'/' || filename[len - 1] == L'\\') { + len--; + } + wcscpy(&filename[len], L"\\*.*"); + FlipSlashesW( filename, wcslen(filename) ); + + d->d_hdl = findFirstFileW( filename, &(d->d_entry) ); + if ( d->d_hdl == INVALID_HANDLE_VALUE ) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + d->firstEntry = PR_TRUE; + d->magic = _MD_MAGIC_DIR; + return PR_SUCCESS; +} + +PRUnichar * +_PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags) +{ + PRInt32 err; + BOOL rv; + PRUnichar *fileName; + + if ( d ) { + while (1) { + if (d->firstEntry) { + d->firstEntry = PR_FALSE; + rv = 1; + } else { + rv = findNextFileW(d->d_hdl, &(d->d_entry)); + } + if (rv == 0) { + break; + } + fileName = GetFileFromDIR(d); + if ( (flags & PR_SKIP_DOT) && + (fileName[0] == L'.') && (fileName[1] == L'\0')) + continue; + if ( (flags & PR_SKIP_DOT_DOT) && + (fileName[0] == L'.') && (fileName[1] == L'.') && + (fileName[2] == L'\0')) + continue; + if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) + continue; + return fileName; + } + err = GetLastError(); + PR_ASSERT(NO_ERROR != err); + _PR_MD_MAP_READDIR_ERROR(err); + return NULL; + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; +} + +PRStatus +_PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *d) +{ + if ( d ) { + if (FindClose(d->d_hdl)) { + d->magic = (PRUint32)-1; + return PR_SUCCESS; + } else { + _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; +} + +#define _PR_IS_W_SLASH(ch) ((ch) == L'/' || (ch) == L'\\') + +/* + * IsRootDirectoryW -- + * + * Return PR_TRUE if the pathname 'fn' is a valid root directory, + * else return PR_FALSE. The PRUnichar buffer pointed to by 'fn' must + * be writable. During the execution of this function, the contents + * of the buffer pointed to by 'fn' may be modified, but on return + * the original contents will be restored. 'buflen' is the size of + * the buffer pointed to by 'fn', in PRUnichars. + * + * Root directories come in three formats: + * 1. / or \, meaning the root directory of the current drive. + * 2. C:/ or C:\, where C is a drive letter. + * 3. \\\\ or + * \\\, meaning the root directory + * of a UNC (Universal Naming Convention) name. + */ + +static PRBool +IsRootDirectoryW(PRUnichar *fn, size_t buflen) +{ + PRUnichar *p; + PRBool slashAdded = PR_FALSE; + PRBool rv = PR_FALSE; + + if (_PR_IS_W_SLASH(fn[0]) && fn[1] == L'\0') { + return PR_TRUE; + } + + if (iswalpha(fn[0]) && fn[1] == L':' && _PR_IS_W_SLASH(fn[2]) + && fn[3] == L'\0') { + rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE; + return rv; + } + + /* The UNC root directory */ + + if (_PR_IS_W_SLASH(fn[0]) && _PR_IS_W_SLASH(fn[1])) { + /* The 'server' part should have at least one character. */ + p = &fn[2]; + if (*p == L'\0' || _PR_IS_W_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the next slash */ + do { + p++; + } while (*p != L'\0' && !_PR_IS_W_SLASH(*p)); + if (*p == L'\0') { + return PR_FALSE; + } + + /* The 'share' part should have at least one character. */ + p++; + if (*p == L'\0' || _PR_IS_W_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the final slash */ + do { + p++; + } while (*p != L'\0' && !_PR_IS_W_SLASH(*p)); + if (_PR_IS_W_SLASH(*p) && p[1] != L'\0') { + return PR_FALSE; + } + if (*p == L'\0') { + /* + * GetDriveType() doesn't work correctly if the + * path is of the form \\server\share, so we add + * a final slash temporarily. + */ + if ((p + 1) < (fn + buflen)) { + *p++ = L'\\'; + *p = L'\0'; + slashAdded = PR_TRUE; + } else { + return PR_FALSE; /* name too long */ + } + } + rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE; + /* restore the 'fn' buffer */ + if (slashAdded) { + *--p = L'\0'; + } + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info) +{ + HANDLE hFindFile; + WIN32_FIND_DATAW findFileData; + PRUnichar pathbuf[MAX_PATH + 1]; + + if (NULL == fn || L'\0' == *fn) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + /* + * FindFirstFile() expands wildcard characters. So + * we make sure the pathname contains no wildcard. + */ + if (NULL != wcspbrk(fn, L"?*")) { + PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0); + return -1; + } + + hFindFile = findFirstFileW(fn, &findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + DWORD len; + PRUnichar *filePart; + + /* + * FindFirstFile() does not work correctly on root directories. + * It also doesn't work correctly on a pathname that ends in a + * slash. So we first check to see if the pathname specifies a + * root directory. If not, and if the pathname ends in a slash, + * we remove the final slash and try again. + */ + + /* + * If the pathname does not contain ., \, and /, it cannot be + * a root directory or a pathname that ends in a slash. + */ + if (NULL == wcspbrk(fn, L".\\/")) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + len = getFullPathNameW(fn, sizeof(pathbuf)/sizeof(pathbuf[0]), pathbuf, + &filePart); + if (0 == len) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + if (len > sizeof(pathbuf)/sizeof(pathbuf[0])) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return -1; + } + if (IsRootDirectoryW(pathbuf, sizeof(pathbuf)/sizeof(pathbuf[0]))) { + info->type = PR_FILE_DIRECTORY; + info->size = 0; + /* + * These timestamps don't make sense for root directories. + */ + info->modifyTime = 0; + info->creationTime = 0; + return 0; + } + if (!_PR_IS_W_SLASH(pathbuf[len - 1])) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } else { + pathbuf[len - 1] = L'\0'; + hFindFile = findFirstFileW(pathbuf, &findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + } + } + + FindClose(hFindFile); + + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + info->type = PR_FILE_DIRECTORY; + } else { + info->type = PR_FILE_FILE; + } + + info->size = findFileData.nFileSizeHigh; + info->size = (info->size << 32) + findFileData.nFileSizeLow; + + _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); + + if (0 == findFileData.ftCreationTime.dwLowDateTime && + 0 == findFileData.ftCreationTime.dwHighDateTime) { + info->creationTime = info->modifyTime; + } else { + _PR_FileTimeToPRTime(&findFileData.ftCreationTime, + &info->creationTime); + } + + return 0; +} +/* ================ end of UTF16 Interfaces ================================ */ +#endif /* MOZ_UNICODE */ diff --git a/nsprpub/pr/src/md/windows/w95sock.c b/nsprpub/pr/src/md/windows/w95sock.c new file mode 100644 index 00000000000..fa5cd0d2566 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w95sock.c @@ -0,0 +1,771 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Win95 Sockets module + * + */ + +#include "primpl.h" + +#define READ_FD 1 +#define WRITE_FD 2 +#define CONNECT_FD 3 + +static PRInt32 socket_io_wait( + PROsfd osfd, + PRInt32 fd_type, + PRIntervalTime timeout); + + +/* --- SOCKET IO --------------------------------------------------------- */ + +/* + * we only want to call WSAIoctl() on Vista and later + * so don't pay for it at build time (and avoid including winsock2.h) + */ + +/* from ws2def.h */ +#define IOC_IN 0x80000000 /* copy in parameters */ +#define IOC_VENDOR 0x18000000 +#define _WSAIOW(x,y) (IOC_IN|(x)|(y)) +/* from MSWSockDef.h */ +#define SIO_SET_COMPATIBILITY_MODE _WSAIOW(IOC_VENDOR,300) + +typedef enum _WSA_COMPATIBILITY_BEHAVIOR_ID { + WsaBehaviorAll = 0, + WsaBehaviorReceiveBuffering, + WsaBehaviorAutoTuning +} WSA_COMPATIBILITY_BEHAVIOR_ID, *PWSA_COMPATIBILITY_BEHAVIOR_ID; + +/* from sdkddkver.h */ +#define NTDDI_LONGHORN 0x06000000 + +/* from winsock2.h */ +#define WSAEVENT HANDLE + +#define WSAOVERLAPPED OVERLAPPED +typedef struct _OVERLAPPED * LPWSAOVERLAPPED; + +typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)( + IN DWORD dwError, + IN DWORD cbTransferred, + IN LPWSAOVERLAPPED lpOverlapped, + IN DWORD dwFlags +); + +typedef int (__stdcall * WSAIOCTLPROC) ( + SOCKET s, + DWORD dwIoControlCode, + LPVOID lpvInBuffer, + DWORD cbInBuffer, + LPVOID lpvOutBuffer, + DWORD cbOutBuffer, + LPDWORD lpcbBytesReturned, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine +); + +typedef struct _WSA_COMPATIBILITY_MODE { + WSA_COMPATIBILITY_BEHAVIOR_ID BehaviorId; + ULONG TargetOsVersion; +} WSA_COMPATIBILITY_MODE, *PWSA_COMPATIBILITY_MODE; + +static HMODULE libWinsock2 = NULL; +static WSAIOCTLPROC wsaioctlProc = NULL; +static PRBool socketSetCompatMode = PR_FALSE; + +void _PR_MD_InitSockets(void) +{ + OSVERSIONINFO osvi; + + memset(&osvi, 0, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + GetVersionEx(&osvi); + + /* if Vista or later... */ + if (osvi.dwMajorVersion >= 6) + { + libWinsock2 = LoadLibrary("Ws2_32.dll"); + if (libWinsock2) + { + wsaioctlProc = (WSAIOCTLPROC)GetProcAddress(libWinsock2, + "WSAIoctl"); + if (wsaioctlProc) + { + socketSetCompatMode = PR_TRUE; + } + } + } +} + +void _PR_MD_CleanupSockets(void) +{ + socketSetCompatMode = PR_FALSE; + wsaioctlProc = NULL; + if (libWinsock2) + { + FreeLibrary(libWinsock2); + libWinsock2 = NULL; + } +} + +PROsfd +_PR_MD_SOCKET(int af, int type, int flags) +{ + SOCKET sock; + u_long one = 1; + + sock = socket(af, type, flags); + + if (sock == INVALID_SOCKET ) + { + _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError()); + return (PROsfd)sock; + } + + /* + ** Make the socket Non-Blocking + */ + if (ioctlsocket( sock, FIONBIO, &one) != 0) + { + PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError()); + closesocket(sock); + return -1; + } + + if ((af == AF_INET || af == AF_INET6) && + type == SOCK_STREAM && socketSetCompatMode) + { + WSA_COMPATIBILITY_MODE mode; + char dummy[4]; + int ret_dummy; + + mode.BehaviorId = WsaBehaviorAutoTuning; + mode.TargetOsVersion = NTDDI_LONGHORN; + if (wsaioctlProc(sock, SIO_SET_COMPATIBILITY_MODE, + (char *)&mode, sizeof(mode), + dummy, 4, &ret_dummy, 0, NULL) == SOCKET_ERROR) + { + int err = WSAGetLastError(); + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("WSAIoctl() failed with %d", err)); + + /* SIO_SET_COMPATIBILITY_MODE may not be supported. + ** If the call to WSAIoctl() fails with WSAEOPNOTSUPP, + ** don't close the socket. + */ + } + } + + return (PROsfd)sock; +} + +/* +** _MD_CloseSocket() -- Close a socket +** +*/ +PRInt32 +_MD_CloseSocket(PROsfd osfd) +{ + PRInt32 rv; + + rv = closesocket((SOCKET) osfd ); + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError()); + + return rv; +} + +PRInt32 +_MD_SocketAvailable(PRFileDesc *fd) +{ + PRInt32 result; + + if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError()); + return -1; + } + return result; +} + +PROsfd _MD_Accept( + PRFileDesc *fd, + PRNetAddr *raddr, + PRUint32 *rlen, + PRIntervalTime timeout ) +{ + PROsfd osfd = fd->secret->md.osfd; + SOCKET sock; + PRInt32 rv, err; + + while ((sock = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) + { + err = WSAGetLastError(); + if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking)) + { + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + { + break; + } + } + else + { + _PR_MD_MAP_ACCEPT_ERROR(err); + break; + } + } + return(sock); +} /* end _MD_accept() */ + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv; + int err; + + if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) + { + err = WSAGetLastError(); + if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK)) + { + rv = socket_io_wait(osfd, CONNECT_FD, timeout); + if ( rv < 0 ) + { + return(-1); + } + else + { + PR_ASSERT(rv > 0); + /* it's connected */ + return(0); + } + } + _PR_MD_MAP_CONNECT_ERROR(err); + } + return rv; +} + +PRInt32 +_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv; + + rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen); + + if (rv == SOCKET_ERROR) { + _PR_MD_MAP_BIND_ERROR(WSAGetLastError()); + return -1; + } + + return 0; +} + +PRInt32 +_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv; + + rv = listen(fd->secret->md.osfd, backlog); + + if (rv == SOCKET_ERROR) { + _PR_MD_MAP_DEFAULT_ERROR(WSAGetLastError()); + return -1; + } + + return 0; +} + +PRInt32 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + int osflags; + + if (0 == flags) { + osflags = 0; + } else { + PR_ASSERT(PR_MSG_PEEK == flags); + osflags = MSG_PEEK; + } + while ((rv = recv( osfd, buf, amount, osflags)) == -1) + { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) + { + rv = socket_io_wait(osfd, READ_FD, timeout); + if ( rv < 0 ) + { + return -1; + } + } + else + { + _PR_MD_MAP_RECV_ERROR(err); + break; + } + } /* end while() */ + return(rv); +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRInt32 bytesSent = 0; + + while(bytesSent < amount ) + { + while ((rv = send( osfd, buf, amount, 0 )) == -1) + { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) + { + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) + { + return -1; + } + } + else + { + _PR_MD_MAP_SEND_ERROR(err); + return -1; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) + { + break; + } + if (bytesSent < amount) + { + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) + { + return -1; + } + } + } + return bytesSent; +} + +PRInt32 +_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRInt32 bytesSent = 0; + + while(bytesSent < amount) + { + while ((rv = sendto( osfd, buf, amount, 0, (struct sockaddr *) addr, + addrlen)) == -1) + { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) + { + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) + { + return -1; + } + } + else + { + _PR_MD_MAP_SENDTO_ERROR(err); + return -1; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) + { + break; + } + if (bytesSent < amount) + { + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv < 0) + { + return -1; + } + } + } + return bytesSent; +} + +PRInt32 +_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + PROsfd osfd = fd->secret->md.osfd; + PRInt32 rv, err; + + while ((rv = recvfrom( osfd, buf, amount, 0, (struct sockaddr *) addr, + addrlen)) == -1) + { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) + { + rv = socket_io_wait(osfd, READ_FD, timeout); + if ( rv < 0) + { + return -1; + } + } + else + { + _PR_MD_MAP_RECVFROM_ERROR(err); + break; + } + } + return(rv); +} + +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +{ + int index; + int sent = 0; + int rv; + + for (index=0; index < iov_size; index++) + { + rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout); + if (rv > 0) + sent += rv; + if ( rv != iov[index].iov_len ) + { + if (rv < 0) + { + if (fd->secret->nonblocking + && (PR_GetError() == PR_WOULD_BLOCK_ERROR) + && (sent > 0)) + { + return sent; + } + else + { + return -1; + } + } + /* Only a nonblocking socket can have partial sends */ + PR_ASSERT(fd->secret->nonblocking); + return sent; + } + } + return sent; +} + +PRInt32 +_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; +} + +PRStatus +_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; + } +} + +PRStatus +_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; + } +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +{ + 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; + } +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +{ + 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; + } +} + +void +_MD_MakeNonblock(PRFileDesc *f) +{ + 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( + PROsfd osfd, + PRInt32 fd_type, + PRIntervalTime timeout) +{ + PRInt32 rv = -1; + struct timeval tv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime elapsed, remaining; + PRBool wait_for_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(0, &rd_wr, NULL, NULL, &tv); + break; + case WRITE_FD: + rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv); + break; + case CONNECT_FD: + rv = _MD_SELECT(0, 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. + */ + wait_for_remaining = PR_TRUE; + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + wait_for_remaining = PR_FALSE; + 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(0, &rd_wr, NULL, NULL, &tv); + break; + case WRITE_FD: + rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv); + break; + case CONNECT_FD: + rv = _MD_SELECT(0, 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 ) + { + if (wait_for_remaining) { + elapsed = remaining; + } else { + 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/nsprpub/pr/src/md/windows/w95thred.c b/nsprpub/pr/src/md/windows/w95thred.c new file mode 100644 index 00000000000..5d8045aa4b5 --- /dev/null +++ b/nsprpub/pr/src/md/windows/w95thred.c @@ -0,0 +1,306 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include /* for _beginthreadex() */ + +#if _MSC_VER <= 1200 +/* + * VC++ 6.0 doesn't have DWORD_PTR. + */ + +typedef DWORD DWORD_PTR; +#endif /* _MSC_VER <= 1200 */ + +/* --- globals ------------------------------------------------ */ +#ifdef _PR_USE_STATIC_TLS +__declspec(thread) struct PRThread *_pr_thread_last_run; +__declspec(thread) struct PRThread *_pr_currentThread; +__declspec(thread) struct _PRCPU *_pr_currentCPU; +#else +DWORD _pr_currentThreadIndex; +DWORD _pr_lastThreadIndex; +DWORD _pr_currentCPUIndex; +#endif +int _pr_intsOff = 0; +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; + +void +_PR_MD_EARLY_INIT() +{ +#ifndef _PR_USE_STATIC_TLS + _pr_currentThreadIndex = TlsAlloc(); + _pr_lastThreadIndex = TlsAlloc(); + _pr_currentCPUIndex = TlsAlloc(); +#endif +} + +void _PR_MD_CLEANUP_BEFORE_EXIT(void) +{ + _PR_NT_FreeSids(); + + _PR_MD_CleanupSockets(); + + WSACleanup(); + +#ifndef _PR_USE_STATIC_TLS + TlsFree(_pr_currentThreadIndex); + TlsFree(_pr_lastThreadIndex); + TlsFree(_pr_currentCPUIndex); +#endif +} + +PRStatus +_PR_MD_INIT_THREAD(PRThread *thread) +{ + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + /* + ** Warning: + ** -------- + ** NSPR requires a real handle to every thread. + ** GetCurrentThread() returns a pseudo-handle which + ** is not suitable for some thread operations (e.g., + ** suspending). Therefore, get a real handle from + ** the pseudo handle via DuplicateHandle(...) + */ + DuplicateHandle( + GetCurrentProcess(), /* Process of source handle */ + GetCurrentThread(), /* Pseudo Handle to dup */ + GetCurrentProcess(), /* Process of handle */ + &(thread->md.handle), /* resulting handle */ + 0L, /* access flags */ + FALSE, /* Inheritable */ + DUPLICATE_SAME_ACCESS); /* Options */ + } + + /* Create the blocking IO semaphore */ + thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL); + if (thread->md.blocked_sema == NULL) + return PR_FAILURE; + else + return PR_SUCCESS; +} + +static unsigned __stdcall +pr_root(void *arg) +{ + PRThread *thread = (PRThread *)arg; + thread->md.start(thread); + return 0; +} + +PRStatus +_PR_MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + + thread->md.start = start; + thread->md.handle = (HANDLE) _beginthreadex( + NULL, + thread->stack->stackSize, + pr_root, + (void *)thread, + CREATE_SUSPENDED, + &(thread->id)); + if(!thread->md.handle) { + return PR_FAILURE; + } + + thread->md.id = thread->id; + /* + * On windows, a thread is created with a thread priority of + * THREAD_PRIORITY_NORMAL. + */ + if (priority != PR_PRIORITY_NORMAL) { + _PR_MD_SET_PRIORITY(&(thread->md), priority); + } + + /* Activate the thread */ + if ( ResumeThread( thread->md.handle ) != -1) + return PR_SUCCESS; + + return PR_FAILURE; +} + +void +_PR_MD_YIELD(void) +{ + /* Can NT really yield at all? */ + Sleep(0); +} + +void +_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) +{ + int nativePri; + BOOL rv; + + if (newPri < PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } else if (newPri > PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } + switch (newPri) { + case PR_PRIORITY_LOW: + nativePri = THREAD_PRIORITY_BELOW_NORMAL; + break; + case PR_PRIORITY_NORMAL: + nativePri = THREAD_PRIORITY_NORMAL; + break; + case PR_PRIORITY_HIGH: + nativePri = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case PR_PRIORITY_URGENT: + nativePri = THREAD_PRIORITY_HIGHEST; + } + rv = SetThreadPriority(thread->handle, nativePri); + PR_ASSERT(rv); + if (!rv) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: can't set thread priority\n")); + } + return; +} + +void +_PR_MD_CLEAN_THREAD(PRThread *thread) +{ + BOOL rv; + + if (thread->md.blocked_sema) { + rv = CloseHandle(thread->md.blocked_sema); + PR_ASSERT(rv); + thread->md.blocked_sema = 0; + } + + if (thread->md.handle) { + rv = CloseHandle(thread->md.handle); + PR_ASSERT(rv); + thread->md.handle = 0; + } +} + +void +_PR_MD_EXIT_THREAD(PRThread *thread) +{ + _PR_MD_CLEAN_THREAD(thread); + _PR_MD_SET_CURRENT_THREAD(NULL); +} + + +void +_PR_MD_EXIT(PRIntn status) +{ + _exit(status); +} + +PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) +{ + DWORD_PTR rv; + + rv = SetThreadAffinityMask(thread->md.handle, mask); + + return rv?0:-1; +} + +PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) +{ + BOOL rv; + DWORD_PTR process_mask; + DWORD_PTR system_mask; + + rv = GetProcessAffinityMask(GetCurrentProcess(), + &process_mask, &system_mask); + if (rv) + *mask = (PRUint32)process_mask; + + return rv?0:-1; +} + +void +_PR_MD_SUSPEND_CPU(_PRCPU *cpu) +{ + _PR_MD_SUSPEND_THREAD(cpu->thread); +} + +void +_PR_MD_RESUME_CPU(_PRCPU *cpu) +{ + _PR_MD_RESUME_THREAD(cpu->thread); +} + +void +_PR_MD_SUSPEND_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + DWORD previousSuspendCount; + /* XXXMB - SuspendThread() is not a blocking call; how do we + * know when the thread is *REALLY* suspended? + */ + previousSuspendCount = SuspendThread(thread->md.handle); + PR_ASSERT(previousSuspendCount == 0); + } +} + +void +_PR_MD_RESUME_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + DWORD previousSuspendCount; + previousSuspendCount = ResumeThread(thread->md.handle); + PR_ASSERT(previousSuspendCount == 1); + } +} + +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/nsprpub/pr/src/md/windows/win32_errors.c b/nsprpub/pr/src/md/windows/win32_errors.c new file mode 100644 index 00000000000..ced1b7aa3dc --- /dev/null +++ b/nsprpub/pr/src/md/windows/win32_errors.c @@ -0,0 +1,565 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prerror.h" +#include "prlog.h" +#include +#include + +/* + * On Win32, we map three kinds of error codes: + * - GetLastError(): for Win32 functions + * - WSAGetLastError(): for Winsock functions + * - errno: for standard C library functions + * + * GetLastError() and WSAGetLastError() return error codes in + * non-overlapping ranges, so their error codes (ERROR_* and + * WSAE*) can be mapped by the same function. On the other hand, + * errno and GetLastError() have overlapping ranges, so we need + * to use a separate function to map errno. + * + * 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. + */ + +static void _MD_win32_map_default_errno(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case EACCES: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case ENOENT: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + default: + prError = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_default_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case ERROR_ACCESS_DENIED: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case ERROR_ALREADY_EXISTS: + prError = PR_FILE_EXISTS_ERROR; + break; + case ERROR_CALL_NOT_IMPLEMENTED: + prError = PR_NOT_IMPLEMENTED_ERROR; + break; + case ERROR_DISK_CORRUPT: + prError = PR_IO_ERROR; + break; + case ERROR_DISK_FULL: + prError = PR_NO_DEVICE_SPACE_ERROR; + break; + case ERROR_DISK_OPERATION_FAILED: + prError = PR_IO_ERROR; + break; + case ERROR_DRIVE_LOCKED: + prError = PR_FILE_IS_LOCKED_ERROR; + break; + case ERROR_FILENAME_EXCED_RANGE: + prError = PR_NAME_TOO_LONG_ERROR; + break; + case ERROR_FILE_CORRUPT: + prError = PR_IO_ERROR; + break; + case ERROR_FILE_EXISTS: + prError = PR_FILE_EXISTS_ERROR; + break; + case ERROR_FILE_INVALID: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + case ERROR_FILE_NOT_FOUND: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ERROR_HANDLE_DISK_FULL: + prError = PR_NO_DEVICE_SPACE_ERROR; + break; + case ERROR_INVALID_ADDRESS: + prError = PR_ACCESS_FAULT_ERROR; + break; + case ERROR_INVALID_HANDLE: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + case ERROR_INVALID_NAME: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case ERROR_INVALID_PARAMETER: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case ERROR_INVALID_USER_BUFFER: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case ERROR_LOCKED: + prError = PR_FILE_IS_LOCKED_ERROR; + break; + case ERROR_NETNAME_DELETED: + prError = PR_CONNECT_RESET_ERROR; + break; + case ERROR_NOACCESS: + prError = PR_ACCESS_FAULT_ERROR; + break; + case ERROR_NOT_ENOUGH_MEMORY: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case ERROR_NOT_ENOUGH_QUOTA: + prError = PR_OUT_OF_MEMORY_ERROR; + break; + case ERROR_NOT_READY: + prError = PR_IO_ERROR; + break; + case ERROR_NO_MORE_FILES: + prError = PR_NO_MORE_FILES_ERROR; + break; + case ERROR_OPEN_FAILED: + prError = PR_IO_ERROR; + break; + case ERROR_OPEN_FILES: + prError = PR_IO_ERROR; + break; + case ERROR_OPERATION_ABORTED: + prError = PR_OPERATION_ABORTED_ERROR; + break; + case ERROR_OUTOFMEMORY: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case ERROR_PATH_BUSY: + prError = PR_IO_ERROR; + break; + case ERROR_PATH_NOT_FOUND: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ERROR_SEEK_ON_DEVICE: + prError = PR_IO_ERROR; + break; + case ERROR_SHARING_VIOLATION: + prError = PR_FILE_IS_BUSY_ERROR; + break; + case ERROR_STACK_OVERFLOW: + prError = PR_ACCESS_FAULT_ERROR; + break; + case ERROR_TOO_MANY_OPEN_FILES: + prError = PR_SYS_DESC_TABLE_FULL_ERROR; + break; + case ERROR_WRITE_PROTECT: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case WSAEACCES: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case WSAEADDRINUSE: + prError = PR_ADDRESS_IN_USE_ERROR; + break; + case WSAEADDRNOTAVAIL: + prError = PR_ADDRESS_NOT_AVAILABLE_ERROR; + break; + case WSAEAFNOSUPPORT: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case WSAEALREADY: + prError = PR_ALREADY_INITIATED_ERROR; + break; + case WSAEBADF: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + case WSAECONNABORTED: + prError = PR_CONNECT_ABORTED_ERROR; + break; + case WSAECONNREFUSED: + prError = PR_CONNECT_REFUSED_ERROR; + break; + case WSAECONNRESET: + prError = PR_CONNECT_RESET_ERROR; + break; + case WSAEDESTADDRREQ: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAEFAULT: + prError = PR_ACCESS_FAULT_ERROR; + break; + case WSAEHOSTUNREACH: + prError = PR_HOST_UNREACHABLE_ERROR; + break; + case WSAEINVAL: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAEISCONN: + prError = PR_IS_CONNECTED_ERROR; + break; + case WSAEMFILE: + prError = PR_PROC_DESC_TABLE_FULL_ERROR; + break; + case WSAEMSGSIZE: + prError = PR_BUFFER_OVERFLOW_ERROR; + break; + case WSAENETDOWN: + prError = PR_NETWORK_DOWN_ERROR; + break; + case WSAENETRESET: + prError = PR_CONNECT_ABORTED_ERROR; + break; + case WSAENETUNREACH: + prError = PR_NETWORK_UNREACHABLE_ERROR; + break; + case WSAENOBUFS: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case WSAENOPROTOOPT: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAENOTCONN: + prError = PR_NOT_CONNECTED_ERROR; + break; + case WSAENOTSOCK: + prError = PR_NOT_SOCKET_ERROR; + break; + case WSAEOPNOTSUPP: + prError = PR_OPERATION_NOT_SUPPORTED_ERROR; + break; + case WSAEPROTONOSUPPORT: + prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR; + break; + case WSAEPROTOTYPE: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAESHUTDOWN: + prError = PR_SOCKET_SHUTDOWN_ERROR; + break; + case WSAESOCKTNOSUPPORT: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAETIMEDOUT: + prError = PR_CONNECT_ABORTED_ERROR; + break; + case WSAEWOULDBLOCK: + prError = PR_WOULD_BLOCK_ERROR; + break; + default: + prError = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_opendir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_closedir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_unix_readdir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_delete_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +/* The error code for stat() is in errno. */ +void _MD_win32_map_stat_error(PRInt32 err) +{ + _MD_win32_map_default_errno(err); +} + +void _MD_win32_map_fstat_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_rename_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +/* The error code for access() is in errno. */ +void _MD_win32_map_access_error(PRInt32 err) +{ + _MD_win32_map_default_errno(err); +} + +void _MD_win32_map_mkdir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_rmdir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_read_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_transmitfile_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_write_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_lseek_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_fsync_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +/* + * For both CloseHandle() and closesocket(). + */ +void _MD_win32_map_close_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_socket_error(PRInt32 err) +{ + PR_ASSERT(err != WSANOTINITIALISED); + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_recv_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_recvfrom_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_send_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEMSGSIZE: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_sendto_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEMSGSIZE: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_accept_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEOPNOTSUPP: + prError = PR_NOT_TCP_SOCKET_ERROR; + break; + case WSAEINVAL: + prError = PR_INVALID_STATE_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_acceptex_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_connect_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEWOULDBLOCK: + prError = PR_IN_PROGRESS_ERROR; + break; + case WSAEINVAL: + prError = PR_ALREADY_INITIATED_ERROR; + break; + case WSAETIMEDOUT: + prError = PR_IO_TIMEOUT_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_bind_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEINVAL: + prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_listen_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEOPNOTSUPP: + prError = PR_NOT_TCP_SOCKET_ERROR; + break; + case WSAEINVAL: + prError = PR_INVALID_STATE_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_shutdown_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_getsockname_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEINVAL: + prError = PR_INVALID_STATE_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_getpeername_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_getsockopt_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_setsockopt_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_open_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_gethostname_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +/* Win32 select() only works on sockets. So in this +** context, WSAENOTSOCK is equivalent to EBADF on Unix. +*/ +void _MD_win32_map_select_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAENOTSOCK: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_lockf_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} diff --git a/nsprpub/pr/src/memory/.cvsignore b/nsprpub/pr/src/memory/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/memory/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/memory/Makefile.in b/nsprpub/pr/src/memory/Makefile.in new file mode 100644 index 00000000000..6ba0ba78092 --- /dev/null +++ b/nsprpub/pr/src/memory/Makefile.in @@ -0,0 +1,69 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +CSRCS = prseg.c prshm.c prshma.c + +ifdef GC_LEAK_DETECTOR +CSRCS += prgcleak.c +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +ifdef GC_LEAK_DETECTOR +INCLUDES += -I$(dist_includedir)/.. -I$(dist_includedir)/../boehm +endif + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + + diff --git a/nsprpub/pr/src/memory/prgcleak.c b/nsprpub/pr/src/memory/prgcleak.c new file mode 100644 index 00000000000..414b3851d32 --- /dev/null +++ b/nsprpub/pr/src/memory/prgcleak.c @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick Beard + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * prgcleak.c + */ + +#ifdef GC_LEAK_DETECTOR + +/* for FILE */ +#include + +/* NSPR stuff */ +#include "generic_threads.h" +#include "primpl.h" + +extern FILE *GC_stdout, *GC_stderr; + +extern void GC_gcollect(void); +extern void GC_clear_roots(void); + +static PRStatus PR_CALLBACK scanner(PRThread* t, void** baseAddr, + PRUword count, void* closure) +{ + if (count) { + char* begin = (char*)baseAddr; + char* end = (char*)(baseAddr + count); + GC_mark_range_proc marker = (GC_mark_range_proc) closure; + marker(begin, end); + } + return PR_SUCCESS; +} + +static void mark_all_stacks(GC_mark_range_proc marker) +{ + PR_ScanStackPointers(&scanner, (void *)marker); +} + +#if defined(_PR_PTHREADS) +#define _PR_MD_CURRENT_CPU() 1 +#endif + +static void locker(void* mutex) +{ + if (_PR_MD_CURRENT_CPU()) + PR_EnterMonitor(mutex); +} + +static void unlocker(void* mutex) +{ + if (_PR_MD_CURRENT_CPU()) + PR_ExitMonitor(mutex); +} + +static void stopper(void* unused) +{ + if (_PR_MD_CURRENT_CPU()) + PR_SuspendAll(); +} + +static void starter(void* unused) +{ + if (_PR_MD_CURRENT_CPU()) + PR_ResumeAll(); +} + +void _PR_InitGarbageCollector() +{ + void* mutex; + + /* redirect GC's stderr to catch startup leaks. */ + GC_stderr = fopen("StartupLeaks", "w"); + + mutex = PR_NewMonitor(); + PR_ASSERT(mutex != NULL); + + GC_generic_init_threads(&mark_all_stacks, mutex, + &locker, &unlocker, + &stopper, &starter); +} + +void _PR_ShutdownGarbageCollector() +{ + /* do anything you need to shut down the collector. */ +} + +#endif /* GC_LEAK_DETECTOR */ diff --git a/nsprpub/pr/src/memory/prseg.c b/nsprpub/pr/src/memory/prseg.c new file mode 100644 index 00000000000..14de6668fcb --- /dev/null +++ b/nsprpub/pr/src/memory/prseg.c @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#if defined(_PR_PTHREADS) + +/* +** The pthreads version doesn't use these functions. +*/ +void _PR_InitSegs(void) +{ +} + +#else /* _PR_PTHREADS */ + +void _PR_InitSegs(void) +{ + _PR_MD_INIT_SEGS(); +} + +/* +** 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. +*/ +PRSegment* _PR_NewSegment(PRUint32 size, void *vaddr) +{ + PRSegment *seg; + + /* calloc the data structure for the segment */ + seg = PR_NEWZAP(PRSegment); + + if (seg) { + size = ((size + _pr_pageSize - 1) >> _pr_pageShift) << _pr_pageShift; + /* + ** Now, allocate the actual segment memory (or map under some OS) + ** The OS specific code decides from where or how to allocate memory. + */ + if (_PR_MD_ALLOC_SEGMENT(seg, size, vaddr) != PR_SUCCESS) { + PR_DELETE(seg); + return NULL; + } + } + + return seg; +} + +/* +** Free a memory segment. +*/ +void _PR_DestroySegment(PRSegment *seg) +{ + _PR_MD_FREE_SEGMENT(seg); + PR_DELETE(seg); +} + +#endif /* _PR_PTHREADS */ diff --git a/nsprpub/pr/src/memory/prshm.c b/nsprpub/pr/src/memory/prshm.c new file mode 100644 index 00000000000..ac6339523dd --- /dev/null +++ b/nsprpub/pr/src/memory/prshm.c @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** prshm.c -- NSPR Named Shared Memory +** +** lth. Jul-1999. +*/ +#include +#include "primpl.h" + +extern PRLogModuleInfo *_pr_shm_lm; + + +#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY +/* SysV implementation is in pr/src/md/unix/uxshm.c */ +#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY +/* Posix implementation is in pr/src/md/unix/uxshm.c */ +#elif defined PR_HAVE_WIN32_NAMED_SHARED_MEMORY +/* Win32 implementation is in pr/src/md/windows/w32shm.c */ +#else +/* +** there is no named_shared_memory +*/ +extern PRSharedMemory* _MD_OpenSharedMemory( const char *name, PRSize size, PRIntn flags, PRIntn mode ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +extern PRStatus _MD_DeleteSharedMemory( const char *name ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} +#endif /* HAVE_SYSV_NAMED_SHARED_MEMORY */ + +/* +** FUNCTION: PR_OpenSharedMemory() +** +*/ +PR_IMPLEMENT( PRSharedMemory * ) + PR_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return( _PR_MD_OPEN_SHARED_MEMORY( name, size, flags, mode )); +} /* end PR_OpenSharedMemory() */ + +/* +** FUNCTION: PR_AttachSharedMemory() +** +*/ +PR_IMPLEMENT( void * ) + PR_AttachSharedMemory( + PRSharedMemory *shm, + PRIntn flags +) +{ + return( _PR_MD_ATTACH_SHARED_MEMORY( shm, flags )); +} /* end PR_AttachSharedMemory() */ + +/* +** FUNCTION: PR_DetachSharedMemory() +** +*/ +PR_IMPLEMENT( PRStatus ) + PR_DetachSharedMemory( + PRSharedMemory *shm, + void *addr +) +{ + return( _PR_MD_DETACH_SHARED_MEMORY( shm, addr )); +} /* end PR_DetachSharedMemory() */ + +/* +** FUNCTION: PR_CloseSharedMemory() +** +*/ +PR_IMPLEMENT( PRStatus ) + PR_CloseSharedMemory( + PRSharedMemory *shm +) +{ + return( _PR_MD_CLOSE_SHARED_MEMORY( shm )); +} /* end PR_CloseSharedMemory() */ + +/* +** FUNCTION: PR_DeleteSharedMemory() +** +*/ +PR_EXTERN( PRStatus ) + PR_DeleteSharedMemory( + const char *name +) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return(_PR_MD_DELETE_SHARED_MEMORY( name )); +} /* end PR_DestroySharedMemory() */ +/* end prshm.c */ diff --git a/nsprpub/pr/src/memory/prshma.c b/nsprpub/pr/src/memory/prshma.c new file mode 100644 index 00000000000..fbc22578981 --- /dev/null +++ b/nsprpub/pr/src/memory/prshma.c @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** prshma.h -- NSPR Anonymous Shared Memory +** +** +*/ + +#include "primpl.h" + +extern PRLogModuleInfo *_pr_shma_lm; + +#if defined(XP_UNIX) +/* defined in pr/src/md/unix/uxshm.c */ +#elif defined(WIN32) +/* defined in pr/src/md/windows/w32shm.c */ +#else +extern PRFileMap * _PR_MD_OPEN_ANON_FILE_MAP( const char *dirName, PRSize size, PRFileMapProtect prot ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} +extern PRStatus _PR_MD_EXPORT_FILE_MAP_AS_STRING(PRFileMap *fm, PRSize bufSize, char *buf) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} +extern PRFileMap * _PR_MD_IMPORT_FILE_MAP_FROM_STRING(const char *fmstring) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} +#endif + +/* +** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory +** +*/ +PR_IMPLEMENT(PRFileMap*) +PR_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +) +{ + return(_PR_MD_OPEN_ANON_FILE_MAP( dirName, size, prot )); +} /* end PR_OpenAnonFileMap() */ + +/* +** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export +** to my children processes via PR_CreateProcess() +** +** +*/ +PR_IMPLEMENT( PRStatus) +PR_ProcessAttrSetInheritableFileMap( + PRProcessAttr *attr, + PRFileMap *fm, + const char *shmname +) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return( PR_FAILURE); +} /* end PR_ProcessAttrSetInheritableFileMap() */ + +/* +** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported +** by my parent process via PR_CreateProcess() +** +*/ +PR_IMPLEMENT( PRFileMap *) +PR_GetInheritedFileMap( + const char *shmname +) +{ + PRFileMap *fm = NULL; + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return( fm ); +} /* end PR_GetInhteritedFileMap() */ + +/* +** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap +** +*/ +PR_IMPLEMENT( PRStatus ) +PR_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufSize, + char *buf +) +{ + return( _PR_MD_EXPORT_FILE_MAP_AS_STRING( fm, bufSize, buf )); +} /* end PR_ExportFileMapAsString() */ + +/* +** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string +** +** +*/ +PR_IMPLEMENT( PRFileMap * ) +PR_ImportFileMapFromString( + const char *fmstring +) +{ + return( _PR_MD_IMPORT_FILE_MAP_FROM_STRING(fmstring)); +} /* end PR_ImportFileMapFromString() */ +/* end prshma.c */ diff --git a/nsprpub/pr/src/misc/.cvsignore b/nsprpub/pr/src/misc/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/misc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/misc/Makefile.in b/nsprpub/pr/src/misc/Makefile.in new file mode 100644 index 00000000000..55791215637 --- /dev/null +++ b/nsprpub/pr/src/misc/Makefile.in @@ -0,0 +1,111 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +CSRCS = \ + pralarm.c \ + pratom.c \ + prcountr.c \ + prdtoa.c \ + prenv.c \ + prerr.c \ + prerror.c \ + prerrortable.c \ + prinit.c \ + prinrval.c \ + pripc.c \ + prlog2.c \ + prlong.c \ + prnetdb.c \ + prolock.c \ + prrng.c \ + prsystem.c \ + prtime.c \ + prthinfo.c \ + prtpool.c \ + prtrace.c \ + $(NULL) + +ifndef USE_PTHREADS +CSRCS += \ + pripcsem.c \ + $(NULL) +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +RELEASE_BINS = $(srcdir)/compile-et.pl $(srcdir)/prerr.properties + +include $(topsrcdir)/config/rules.mk + +# Prevent floating point errors caused by MSVC 6.0 Processor Pack +# optimizations (bug 207421). This disables optimizations that +# could change the precision of floating-point calculations for +# this single compilation unit. +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) +$(OBJDIR)/prdtoa.$(OBJ_SUFFIX): prdtoa.c + @$(MAKE_OBJDIR) +ifeq (,$(filter-out 1100 1200 1300 1310,$(MSC_VER))) + $(CC) -Fo$@ -c $(CFLAGS) -Op $(call abspath,$<) +else + $(CC) -Fo$@ -c $(CFLAGS) -fp:precise $(call abspath,$<) +endif +endif + +# +# Generate prerr.h, prerr.c, and prerr.properties from prerr.et. +# +build_prerr: + cd $(srcdir); $(PERL) compile-et.pl prerr.et + +export:: $(TARGETS) + + diff --git a/nsprpub/pr/src/misc/compile-et.pl b/nsprpub/pr/src/misc/compile-et.pl new file mode 100644 index 00000000000..9f0d90bc108 --- /dev/null +++ b/nsprpub/pr/src/misc/compile-et.pl @@ -0,0 +1,140 @@ +#!/usr/bin/perl + +# usage: compile-et input.et + +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +sub header +{ + local($filename, $comment) = @_; + +< 0x7fffff); + $base*256; +} + +sub code { + local($macro, $text) = @_; + $code = $table_base + $table_item_count; + + print H "\n"; + print H "/* ", $text, " */\n"; + printf H "#define %-40s (%dL)\n", $macro, $code; + + print C "\t{\"", $macro, "\", \"", $text, "\"},\n"; + + print PROPERTIES $macro, "=", $text, "\n"; + + $table_item_count++; +} + + +$filename = $ARGV[0]; +open(INPUT, "< $filename") || die "Can't read $filename: $!\n"; + +$base = "$filename"; +$base =~ s/\.et$//; +$base =~ s#.*/##; + +open(H, "> ${base}.h") || die "Can't write ${base}.h\n"; +open(C, "> ${base}.c") || die "Can't write ${base}.c\n"; +open(PROPERTIES, "> ${base}.properties") || die "Can't write ${base}.properties\n"; + +print H "/*\n", &header("${base}.h", " *"), " */\n"; +print C "/*\n", &header("${base}.c", " *"), " */\n"; +print PROPERTIES &header("${base}.properties", "#"); + +$skipone = 0; + +while ($_ = ) { + next if /^#/; + + if (/^[ \t]*(error_table|et)[ \t]+([a-zA-Z][a-zA-Z0-9_]+) *(-?[0-9]*)/) { + $table_name = $2; + if ($3) { + $table_base = $3; + } + else { + $table_base = &table_base($table_name); + } + $table_item_count = 0; + + print C "#include \"prerror.h\"\n"; + print C "static const struct PRErrorMessage text[] = {\n"; + } + elsif (/^[ \t]*(error_code|ec)[ \t]+([A-Z_0-9]+),[ \t]*$/) { + $skipone = 1; + $macro = $2; + } + elsif (/^[ \t]*(error_code|ec)[ \t]+([A-Z_0-9]+),[ \t]*"(.*)"[ \t]*$/) { + &code($2, $3); + } + elsif ($skipone && /^[ \t]*"(.*)"[ \t]*$/) { + &code($macro, $1); + } +} + +print H "\n"; +print H "extern void ", $table_name, "_InitializePRErrorTable","(void);\n"; +printf H "#define ERROR_TABLE_BASE_%s (%dL)\n", $table_name, $table_base; + +print C "\t{0, 0}\n"; +print C "};\n\n"; +printf C "static const struct PRErrorTable et = { text, \"%s\", %dL, %d };\n", + $base, $table_base, $table_item_count; +print C "\n"; +print C "void ", $table_name, "_InitializePRErrorTable", "(void) {\n"; +print C " PR_ErrorInstallTable(&et);\n"; +print C "}\n"; + +0; diff --git a/nsprpub/pr/src/misc/pralarm.c b/nsprpub/pr/src/misc/pralarm.c new file mode 100644 index 00000000000..9323bab6774 --- /dev/null +++ b/nsprpub/pr/src/misc/pralarm.c @@ -0,0 +1,282 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/**********************************************************************/ +/******************************* PRALARM ******************************/ +/**********************************************************************/ + +#ifdef XP_MAC +#include "pralarm.h" +#else +#include "obsolete/pralarm.h" +#endif + +struct PRAlarmID { /* typedef'd in pralarm.h */ + PRCList list; /* circular list linkage */ + PRAlarm *alarm; /* back pointer to owning alarm */ + PRPeriodicAlarmFn function; /* function to call for notify */ + void *clientData; /* opaque client context */ + PRIntervalTime period; /* the client defined period */ + PRUint32 rate; /* rate of notification */ + + PRUint32 accumulator; /* keeps track of # notifies */ + PRIntervalTime epoch; /* when timer was started */ + PRIntervalTime nextNotify; /* when we'll next do our thing */ + PRIntervalTime lastNotify; /* when we last did our thing */ +}; + +typedef enum {alarm_active, alarm_inactive} _AlarmState; + +struct PRAlarm { /* typedef'd in pralarm.h */ + PRCList timers; /* base of alarm ids list */ + PRLock *lock; /* lock used to protect data */ + PRCondVar *cond; /* condition that used to wait */ + PRThread *notifier; /* thread to deliver notifies */ + PRAlarmID *current; /* current alarm being served */ + _AlarmState state; /* used to delete the alarm */ +}; + +static PRAlarmID *pr_getNextAlarm(PRAlarm *alarm, PRAlarmID *id) +{ +/* + * Puts 'id' back into the sorted list iff it's not NULL. + * Removes the first element from the list and returns it (or NULL). + * List is "assumed" to be short. + * + * NB: Caller is providing locking + */ + PRCList *timer; + PRAlarmID *result = id; + PRIntervalTime now = PR_IntervalNow(); + + if (!PR_CLIST_IS_EMPTY(&alarm->timers)) + { + if (id != NULL) /* have to put this id back in */ + { + PRIntervalTime idDelta = now - id->nextNotify; + timer = alarm->timers.next; + do + { + result = (PRAlarmID*)timer; + if ((PRIntervalTime)(now - result->nextNotify) > idDelta) + { + PR_INSERT_BEFORE(&id->list, &alarm->timers); + break; + } + timer = timer->next; + } while (timer != &alarm->timers); + } + result = (PRAlarmID*)(timer = PR_LIST_HEAD(&alarm->timers)); + PR_REMOVE_LINK(timer); /* remove it from the list */ + } + + return result; +} /* pr_getNextAlarm */ + +static PRIntervalTime pr_PredictNextNotifyTime(PRAlarmID *id) +{ + PRIntervalTime delta; + PRFloat64 baseRate = (PRFloat64)id->period / (PRFloat64)id->rate; + PRFloat64 offsetFromEpoch = (PRFloat64)id->accumulator * baseRate; + + id->accumulator += 1; /* every call advances to next period */ + id->lastNotify = id->nextNotify; /* just keeping track of things */ + id->nextNotify = (PRIntervalTime)(offsetFromEpoch + 0.5); + + delta = id->nextNotify - id->lastNotify; + return delta; +} /* pr_PredictNextNotifyTime */ + +static void PR_CALLBACK pr_alarmNotifier(void *arg) +{ + /* + * This is the root of the notifier thread. There is one such thread + * for each PRAlarm. It may service an arbitrary (though assumed to be + * small) number of alarms using the same thread and structure. It + * continues to run until the alarm is destroyed. + */ + PRAlarmID *id = NULL; + PRAlarm *alarm = (PRAlarm*)arg; + enum {notify, abort, scan} why = scan; + + while (why != abort) + { + PRIntervalTime pause; + + PR_Lock(alarm->lock); + while (why == scan) + { + alarm->current = NULL; /* reset current id */ + if (alarm->state == alarm_inactive) why = abort; /* we're toast */ + else if (why == scan) /* the dominant case */ + { + id = pr_getNextAlarm(alarm, id); /* even if it's the same */ + if (id == NULL) /* there are no alarms set */ + (void)PR_WaitCondVar(alarm->cond, PR_INTERVAL_NO_TIMEOUT); + else + { + pause = id->nextNotify - (PR_IntervalNow() - id->epoch); + if ((PRInt32)pause <= 0) /* is this one's time up? */ + { + why = notify; /* set up to do our thing */ + alarm->current = id; /* id we're about to schedule */ + } + else + (void)PR_WaitCondVar(alarm->cond, pause); /* dally */ + } + } + } + PR_Unlock(alarm->lock); + + if (why == notify) + { + (void)pr_PredictNextNotifyTime(id); + if (!id->function(id, id->clientData, ~pause)) + { + /* + * Notified function decided not to continue. Free + * the alarm id to make sure it doesn't get back on + * the list. + */ + PR_DELETE(id); /* free notifier object */ + id = NULL; /* so it doesn't get back into the list */ + } + why = scan; /* so we can cycle through the loop again */ + } + } + +} /* pr_alarm_notifier */ + +PR_IMPLEMENT(PRAlarm*) PR_CreateAlarm(void) +{ + PRAlarm *alarm = PR_NEWZAP(PRAlarm); + if (alarm != NULL) + { + if ((alarm->lock = PR_NewLock()) == NULL) goto done; + if ((alarm->cond = PR_NewCondVar(alarm->lock)) == NULL) goto done; + alarm->state = alarm_active; + PR_INIT_CLIST(&alarm->timers); + alarm->notifier = PR_CreateThread( + PR_USER_THREAD, pr_alarmNotifier, alarm, + PR_GetThreadPriority(PR_GetCurrentThread()), + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + if (alarm->notifier == NULL) goto done; + } + return alarm; + +done: + if (alarm->cond != NULL) PR_DestroyCondVar(alarm->cond); + if (alarm->lock != NULL) PR_DestroyLock(alarm->lock); + PR_DELETE(alarm); + return NULL; +} /* CreateAlarm */ + +PR_IMPLEMENT(PRStatus) PR_DestroyAlarm(PRAlarm *alarm) +{ + PRStatus rv; + + PR_Lock(alarm->lock); + alarm->state = alarm_inactive; + rv = PR_NotifyCondVar(alarm->cond); + PR_Unlock(alarm->lock); + + if (rv == PR_SUCCESS) + rv = PR_JoinThread(alarm->notifier); + if (rv == PR_SUCCESS) + { + PR_DestroyCondVar(alarm->cond); + PR_DestroyLock(alarm->lock); + PR_DELETE(alarm); + } + return rv; +} /* PR_DestroyAlarm */ + +PR_IMPLEMENT(PRAlarmID*) PR_SetAlarm( + PRAlarm *alarm, PRIntervalTime period, PRUint32 rate, + PRPeriodicAlarmFn function, void *clientData) +{ + /* + * Create a new periodic alarm an existing current structure. + * Set up the context and compute the first notify time (immediate). + * Link the new ID into the head of the list (since it's notifying + * immediately). + */ + + PRAlarmID *id = PR_NEWZAP(PRAlarmID); + + if (!id) + return NULL; + + id->alarm = alarm; + PR_INIT_CLIST(&id->list); + id->function = function; + id->clientData = clientData; + id->period = period; + id->rate = rate; + id->epoch = id->nextNotify = PR_IntervalNow(); + (void)pr_PredictNextNotifyTime(id); + + PR_Lock(alarm->lock); + PR_INSERT_BEFORE(&id->list, &alarm->timers); + PR_NotifyCondVar(alarm->cond); + PR_Unlock(alarm->lock); + + return id; +} /* PR_SetAlarm */ + +PR_IMPLEMENT(PRStatus) PR_ResetAlarm( + PRAlarmID *id, PRIntervalTime period, PRUint32 rate) +{ + /* + * Can only be called from within the notify routine. Doesn't + * need locking because it can only be called from within the + * notify routine. + */ + if (id != id->alarm->current) + return PR_FAILURE; + id->period = period; + id->rate = rate; + id->accumulator = 1; + id->epoch = PR_IntervalNow(); + (void)pr_PredictNextNotifyTime(id); + return PR_SUCCESS; +} /* PR_ResetAlarm */ + + + diff --git a/nsprpub/pr/src/misc/pratom.c b/nsprpub/pr/src/misc/pratom.c new file mode 100644 index 00000000000..35b86c0dbcd --- /dev/null +++ b/nsprpub/pr/src/misc/pratom.c @@ -0,0 +1,411 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** PR Atomic operations +*/ + + +#include "pratom.h" +#include "primpl.h" + +#include + +/* + * The following is a fallback implementation that emulates + * atomic operations for platforms without atomic operations. + * If a platform has atomic operations, it should define the + * macro _PR_HAVE_ATOMIC_OPS, and the following will not be + * compiled in. + */ + +#if !defined(_PR_HAVE_ATOMIC_OPS) + +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +/* + * PR_AtomicDecrement() is used in NSPR's thread-specific data + * destructor. Because thread-specific data destructors may be + * invoked after a PR_Cleanup() call, we need an implementation + * of the atomic routines that doesn't need NSPR to be initialized. + */ + +/* + * We use a set of locks for all the emulated atomic operations. + * By hashing on the address of the integer to be locked the + * contention between multiple threads should be lessened. + * + * The number of atomic locks can be set by the environment variable + * NSPR_ATOMIC_HASH_LOCKS + */ + +/* + * lock counts should be a power of 2 + */ +#define DEFAULT_ATOMIC_LOCKS 16 /* should be in sync with the number of initializers + below */ +#define MAX_ATOMIC_LOCKS (4 * 1024) + +static pthread_mutex_t static_atomic_locks[DEFAULT_ATOMIC_LOCKS] = { + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }; + +#ifdef DEBUG +static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS]; +static PRInt32 *hash_lock_counts = static_hash_lock_counts; +#endif + +static PRUint32 num_atomic_locks = DEFAULT_ATOMIC_LOCKS; +static pthread_mutex_t *atomic_locks = static_atomic_locks; +static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1; + +#define _PR_HASH_FOR_LOCK(ptr) \ + ((PRUint32) (((PRUptrdiff) (ptr) >> 2) ^ \ + ((PRUptrdiff) (ptr) >> 8)) & \ + atomic_hash_mask) + +void _PR_MD_INIT_ATOMIC() +{ +char *eval; +int index; + + + PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) == + PR_CeilingLog2(MAX_ATOMIC_LOCKS)); + + PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) == + PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS)); + + if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL) && + ((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) { + + if (num_atomic_locks > MAX_ATOMIC_LOCKS) + num_atomic_locks = MAX_ATOMIC_LOCKS; + else if (num_atomic_locks < 1) + num_atomic_locks = 1; + else { + num_atomic_locks = PR_FloorLog2(num_atomic_locks); + num_atomic_locks = 1L << num_atomic_locks; + } + atomic_locks = (pthread_mutex_t *) PR_Malloc(sizeof(pthread_mutex_t) * + num_atomic_locks); + if (atomic_locks) { + for (index = 0; index < num_atomic_locks; index++) { + if (pthread_mutex_init(&atomic_locks[index], NULL)) { + PR_DELETE(atomic_locks); + atomic_locks = NULL; + break; + } + } + } +#ifdef DEBUG + if (atomic_locks) { + hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32)); + if (hash_lock_counts == NULL) { + PR_DELETE(atomic_locks); + atomic_locks = NULL; + } + } +#endif + if (atomic_locks == NULL) { + /* + * Use statically allocated locks + */ + atomic_locks = static_atomic_locks; + num_atomic_locks = DEFAULT_ATOMIC_LOCKS; + #ifdef DEBUG + hash_lock_counts = static_hash_lock_counts; + #endif + } + atomic_hash_mask = num_atomic_locks - 1; + } + PR_ASSERT(PR_FloorLog2(num_atomic_locks) == + PR_CeilingLog2(num_atomic_locks)); +} + +PRInt32 +_PR_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + PRInt32 rv; + PRInt32 idx = _PR_HASH_FOR_LOCK(val); + + pthread_mutex_lock(&atomic_locks[idx]); + rv = ++(*val); +#ifdef DEBUG + hash_lock_counts[idx]++; +#endif + pthread_mutex_unlock(&atomic_locks[idx]); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + PRInt32 rv; + PRInt32 idx = _PR_HASH_FOR_LOCK(ptr); + + pthread_mutex_lock(&atomic_locks[idx]); + rv = ((*ptr) += val); +#ifdef DEBUG + hash_lock_counts[idx]++; +#endif + pthread_mutex_unlock(&atomic_locks[idx]); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + PRInt32 rv; + PRInt32 idx = _PR_HASH_FOR_LOCK(val); + + pthread_mutex_lock(&atomic_locks[idx]); + rv = --(*val); +#ifdef DEBUG + hash_lock_counts[idx]++; +#endif + pthread_mutex_unlock(&atomic_locks[idx]); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + PRInt32 rv; + PRInt32 idx = _PR_HASH_FOR_LOCK(val); + + pthread_mutex_lock(&atomic_locks[idx]); + rv = *val; + *val = newval; +#ifdef DEBUG + hash_lock_counts[idx]++; +#endif + pthread_mutex_unlock(&atomic_locks[idx]); + return rv; +} +#else /* _PR_PTHREADS && !_PR_DCETHREADS */ +/* + * We use a single lock for all the emulated atomic operations. + * The lock contention should be acceptable. + */ +static PRLock *atomic_lock = NULL; +void _PR_MD_INIT_ATOMIC(void) +{ + if (atomic_lock == NULL) { + atomic_lock = PR_NewLock(); + } +} + +PRInt32 +_PR_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(atomic_lock); + rv = ++(*val); + PR_Unlock(atomic_lock); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(atomic_lock); + rv = ((*ptr) += val); + PR_Unlock(atomic_lock); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(atomic_lock); + rv = --(*val); + PR_Unlock(atomic_lock); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(atomic_lock); + rv = *val; + *val = newval; + PR_Unlock(atomic_lock); + return rv; +} +#endif /* _PR_PTHREADS && !_PR_DCETHREADS */ + +#endif /* !_PR_HAVE_ATOMIC_OPS */ + +void _PR_InitAtomic(void) +{ + _PR_MD_INIT_ATOMIC(); +} + +PR_IMPLEMENT(PRInt32) +PR_AtomicIncrement(PRInt32 *val) +{ + return _PR_MD_ATOMIC_INCREMENT(val); +} + +PR_IMPLEMENT(PRInt32) +PR_AtomicDecrement(PRInt32 *val) +{ + return _PR_MD_ATOMIC_DECREMENT(val); +} + +PR_IMPLEMENT(PRInt32) +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/nsprpub/pr/src/misc/prcountr.c b/nsprpub/pr/src/misc/prcountr.c new file mode 100644 index 00000000000..a4e4f6cc790 --- /dev/null +++ b/nsprpub/pr/src/misc/prcountr.c @@ -0,0 +1,506 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** 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. +** +*/ + +#include "prcountr.h" +#include "prclist.h" +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" +#include + +/* +** +*/ +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 = NULL; + 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() */ diff --git a/nsprpub/pr/src/misc/prdtoa.c b/nsprpub/pr/src/misc/prdtoa.c new file mode 100644 index 00000000000..dd3134fa40d --- /dev/null +++ b/nsprpub/pr/src/misc/prdtoa.c @@ -0,0 +1,3516 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#define MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) PR_Lock(dtoa_lock[n]) +#define FREE_DTOA_LOCK(n) PR_Unlock(dtoa_lock[n]) + +static PRLock *dtoa_lock[2]; + +void _PR_InitDtoa(void) +{ + dtoa_lock[0] = PR_NewLock(); + dtoa_lock[1] = PR_NewLock(); +} + +void _PR_CleanupDtoa(void) +{ + PR_DestroyLock(dtoa_lock[0]); + dtoa_lock[0] = NULL; + PR_DestroyLock(dtoa_lock[1]); + dtoa_lock[1] = NULL; + + /* FIXME: deal with freelist and p5s. */ +} + +#if !defined(__ARM_EABI__) \ + && (defined(__arm) || defined(__arm__) || defined(__arm26__) \ + || defined(__arm32__)) +#define IEEE_ARM +#elif defined(IS_LITTLE_ENDIAN) +#define IEEE_8087 +#else +#define IEEE_MC68k +#endif + +#define Long PRInt32 +#define ULong PRUint32 +#define NO_LONG_LONG + +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_8087 for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_MC68k for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define IEEE_ARM for IEEE-arithmetic machines where the two words + * in a double are stored in big endian order but the two shorts + * in a word are still stored in little endian order. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. + * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making + * memory allocations from a private pool of memory when possible. + * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions in single-threaded executions with 8-byte + * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte + * pointers, PRIVATE_MEM >= 7112 appears adequate. + * #define INFNAN_CHECK on IEEE systems to cause strtod to check for + * Infinity and NaN (case insensitively). On some systems (e.g., + * some HP systems), it may be necessary to #define NAN_WORD0 + * appropriately -- to the most significant word of a quiet NaN. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod also accepts (case insensitively) strings of the form + * NaN(x), where x is a string of hexadecimal digits and spaces; + * if there is only one string of hexadecimal digits, it is taken + * for the 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define YES_ALIAS to permit aliasing certain double values with + * arrays of ULongs. This leads to slightly better code with + * some compilers and was always used prior to 19990916, but it + * is not strictly legal and can cause trouble with aggressively + * optimizing compilers (e.g., gcc 2.95.1 under -O2). + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + */ + +#ifndef Long +#define Long long +#endif +#ifndef ULong +typedef unsigned Long ULong; +#endif + +#ifdef DEBUG +#include "stdio.h" +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#include "stdlib.h" +#include "string.h" + +#ifdef USE_LOCALE +#include "locale.h" +#endif + +#ifdef MALLOC +#ifdef KR_headers +extern char *MALLOC(); +#else +extern void *MALLOC(size_t); +#endif +#else +#define MALLOC malloc +#endif + +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_MC68k +#define IEEE_Arith +#endif +#ifdef IEEE_8087 +#define IEEE_Arith +#endif +#ifdef IEEE_ARM +#define IEEE_Arith +#endif + +#include "errno.h" + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include "float.h" +/* + * MacOS 10.2 defines the macro FLT_ROUNDS to an internal function + * which does not exist on 10.1. We can safely #define it to 1 here + * to allow 10.2 builds to run on 10.1, since we can't use fesetround() + * (which does not exist on 10.1 either). + */ +#if defined(XP_MACOSX) && (!defined(MAC_OS_X_VERSION_10_2) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2) +#undef FLT_ROUNDS +#define FLT_ROUNDS 1 +#endif /* DT < 10.2 */ +#endif /* Bad_float_h */ + +#ifndef __MATH_H__ +#include "math.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONST +#ifdef KR_headers +#define CONST /* blank */ +#else +#define CONST const +#endif +#endif + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_8087, IEEE_MC68k, IEEE_ARM, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#ifdef YES_ALIAS +#define dval(x) x +#ifdef IEEE_8087 +#define word0(x) ((ULong *)&x)[1] +#define word1(x) ((ULong *)&x)[0] +#else +#define word0(x) ((ULong *)&x)[0] +#define word1(x) ((ULong *)&x)[1] +#endif +#else +#ifdef IEEE_8087 +#define word0(x) ((U*)&x)->L[1] +#define word1(x) ((U*)&x)->L[0] +#else +#define word0(x) ((U*)&x)->L[0] +#define word1(x) ((U*)&x)->L[1] +#endif +#define dval(x) ((U*)&x)->d +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_8087) + defined(IEEE_ARM) + defined(VAX) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +((unsigned short *)a)[0] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Bias 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#define Rounding rounding +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +#ifdef KR_headers +extern double rnd_prod(), rnd_quot(); +#else +extern double rnd_prod(double, double), rnd_quot(double, double); +#endif +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +#ifdef KR_headers +#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) +#else +#define FFFFFFFF 0xffffffffUL +#endif + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#endif + +#define Kmax 15 + + struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; + }; + + typedef struct Bigint Bigint; + + static Bigint *freelist[Kmax+1]; + + static Bigint * +Balloc +#ifdef KR_headers + (k) int k; +#else + (int k) +#endif +{ + int x; + Bigint *rv; +#ifndef Omit_Private_Memory + unsigned int len; +#endif + + ACQUIRE_DTOA_LOCK(0); + if (rv = freelist[k]) { + freelist[k] = rv->next; + } + else { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (pmem_next - private_mem + len <= PRIVATE_mem) { + rv = (Bigint*)pmem_next; + pmem_next += len; + } + else + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); + rv->sign = rv->wds = 0; + return rv; + } + + static void +Bfree +#ifdef KR_headers + (v) Bigint *v; +#else + (Bigint *v) +#endif +{ + if (v) { + ACQUIRE_DTOA_LOCK(0); + v->next = freelist[v->k]; + freelist[v->k] = v; + FREE_DTOA_LOCK(0); + } + } + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(Long) + 2*sizeof(int)) + + static Bigint * +multadd +#ifdef KR_headers + (b, m, a) Bigint *b; int m, a; +#else + (Bigint *b, int m, int a) /* multiply by m and add a */ +#endif +{ + int i, wds; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } + while(++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = carry; + b->wds = wds; + } + return b; + } + + static Bigint * +s2b +#ifdef KR_headers + (s, nd0, nd, y9) CONST char *s; int nd0, nd; ULong y9; +#else + (CONST char *s, int nd0, int nd, ULong y9) +#endif +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); + s++; + } + else + s += 10; + for(; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; + } + + static int +hi0bits +#ifdef KR_headers + (x) register ULong x; +#else + (register ULong x) +#endif +{ + register int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; + } + + static int +lo0bits +#ifdef KR_headers + (y) ULong *y; +#else + (ULong *y) +#endif +{ + register int k; + register ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; + } + + static Bigint * +i2b +#ifdef KR_headers + (i) int i; +#else + (int i) +#endif +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; + } + + static Bigint * +mult +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = z & FFFFFFFF; + } + while(x < xae); + *xc = carry; + } + } +#else +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; + } + + static Bigint *p5s; + + static Bigint * +pow5mult +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + if (i = k & 3) + b = multadd(b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + if (!(p5 = p5s)) { + /* first time */ +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p5 = p5s)) { + p5 = p5s = i2b(625); + p5->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p5 = p5s = i2b(625); + p5->next = 0; +#endif + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p51 = p5->next = mult(p5,p5); + p51->next = 0; +#endif + } + p5 = p51; + } + return b; + } + + static Bigint * +lshift +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; + } + + static int +cmp +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; + } + + static Bigint * +diff +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; + } + + static double +ulp +#ifdef KR_headers + (x) double x; +#else + (double x) +#endif +{ + register Long L; + double a; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(a) = L; + word1(a) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(a) = 0x80000 >> L; + word1(a) = 0; + } + else { + word0(a) = 0; + L -= Exp_shift; + word1(a) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(a); + } + + static double +b2d +#ifdef KR_headers + (a, e) Bigint *a; int *e; +#else + (Bigint *a, int *e) +#endif +{ + ULong *xa, *xa0, w, y, z; + int k; + double d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> Ebits - k; + w = xa > xa0 ? *--xa : 0; + d1 = y << (32-Ebits) + k | w >> Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> 32 - k; + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> 32 - k; + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif + ret_d: +#ifdef VAX + word0(d) = d0 >> 16 | d0 << 16; + word1(d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(d); + } + + static Bigint * +d2b +#ifdef KR_headers + (d, e, bits) double d; int *e, *bits; +#else + (double d, int *e, int *bits) +#endif +{ + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if (de = (int)(d0 >> Exp_shift)) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if (y = d1) { + if (k = lo0bits(&y)) { + x[0] = y | z << 32 - k; + z >>= k; + } + else + x[0] = y; +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; + } +#undef d0 +#undef d1 + + static double +ratio +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + double da, db; + int k, ka, kb; + + dval(da) = b2d(a, &ka); + dval(db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(da) *= 1 << k; + } + else { + k = -k; + word0(db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(db) *= 1 << k; + } +#else + if (k > 0) + word0(da) += k*Exp_msk1; + else { + k = -k; + word0(db) += k*Exp_msk1; + } +#endif + return dval(da) / dval(db); + } + + static CONST double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif + }; + + static CONST double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-53 */ +#else + 1e-256 +#endif + }; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +#ifndef IEEE_Arith +#undef INFNAN_CHECK +#endif + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + + static int +match +#ifdef KR_headers + (sp, t) char **sp, *t; +#else + (CONST char **sp, char *t) +#endif +{ + int c, d; + CONST char *s = *sp; + + while(d = *t++) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; + } + +#ifndef No_Hex_NaN + static void +hexnan +#ifdef KR_headers + (rvp, sp) double *rvp; CONST char **sp; +#else + (double *rvp, CONST char **sp) +#endif +{ + ULong c, x[2]; + CONST char *s; + int havedig, udx0, xshift; + + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + while(c = *(CONST unsigned char*)++s) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c += 10 - 'a'; + else if (c >= 'A' && c <= 'F') + c += 10 - 'A'; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(*rvp) = Exp_mask | x[0]; + word1(*rvp) = x[1]; + } + } +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + + PR_IMPLEMENT(double) +PR_strtod +#ifdef KR_headers + (s00, se) CONST char *s00; char **se; +#else + (CONST char *s00, char **se) +#endif +{ +#ifdef Avoid_Underflow + int scale; +#endif + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + CONST char *s, *s0, *s1; + double aadj, aadj1, adj, rv, rv0; + Long L; + ULong y, z; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef USE_LOCALE + CONST char *s2; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + sign = nz0 = nz = 0; + dval(rv) = 0.; + for(s = s00;;s++) switch(*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } + break2: + if (*s == '0') { + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for(;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + c = *++s; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + switch(c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(rv) = 0x7ff00000; + word1(rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(rv) = NAN_WORD0; + word1(rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ + ret0: + s = s00; + sign = 0; + } + goto ret; + } + e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + dval(rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(rv) = tens[k - 9] * dval(rv) + z; + } + bd0 = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + e -= i; + dval(rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + word0(rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(rv), tens[e]); + if ((word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(rv), tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if (i = e1 & 15) + dval(rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: +#ifndef NO_ERRNO + PR_SetError(PR_RANGE_ERROR, 0); +#endif + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(rv) = Big0; + word1(rv) = Big1; + break; + default: + word0(rv) = Exp_mask; + word1(rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(rv) = Exp_mask; + word1(rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(rv0) = 1e300; + dval(rv0) *= dval(rv0); +#endif +#else /*IEEE_Arith*/ + word0(rv) = Big0; + word1(rv) = Big1; +#endif /*IEEE_Arith*/ + if (bd0) + goto retfree; + goto ret; + } + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(rv) -= P*Exp_msk1; + dval(rv) *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if (i = e1 & 15) + dval(rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; zap j low bits */ + if (j >= 32) { + word1(rv) = 0; + if (j >= 53) + word0(rv) = (P+2)*Exp_msk1; + else + word0(rv) &= 0xffffffff << j-32; + } + else + word1(rv) &= 0xffffffff << j; + } +#else + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(rv0) = dval(rv); + dval(rv) *= tinytens[j]; + if (!dval(rv)) { + dval(rv) = 2.*dval(rv0); + dval(rv) *= tinytens[j]; +#endif + if (!dval(rv)) { + undfl: + dval(rv) = 0.; +#ifndef NO_ERRNO + PR_SetError(PR_RANGE_ERROR, 0); +#endif + if (bd0) + goto retfree; + goto ret; + } +#ifndef Avoid_Underflow + word0(rv) = Tiny0; + word1(rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bd0 = s2b(s0, nd0, nd, y); + + for(;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + j = bbe - scale; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (rounding) { + if (dsign) { + adj = 1.; + goto apply_adj; + } + } + else if (!dsign) { + adj = -1.; + if (!word1(rv) + && !(word0(rv) & Frac_mask)) { + y = word0(rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (cmp(delta, bs) <= 0) + adj = -0.5; + } + } + apply_adj: +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= + P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + dval(rv) += adj*ulp(dval(rv)); + word0(rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + dval(rv) += adj*ulp(dval(rv)); + } + break; + } + adj = ratio(delta, bs); + if (adj < 1.) + adj = 1.; + if (adj <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj; + if (y != adj) { + if (!((rounding>>1) ^ dsign)) + y++; + adj = y; + } + } +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + word0(rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + goto cont; + } +#endif /*Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask +#ifdef IEEE_Arith +#ifdef Avoid_Underflow + || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(rv) & Exp_mask) <= Exp_msk1 +#endif +#endif + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((word0(rv) & Bndry_mask1) == Bndry_mask1 + && word1(rv) == ( +#ifdef Avoid_Underflow + (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + word0(rv) = (word0(rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(rv) = 0; +#ifdef Avoid_Underflow + dsign = 0; +#endif + break; + } + } + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + goto undfl; + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (scale) { + L = word0(rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(rv) = L | Bndry_mask1; + word1(rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(word1(rv) & LSB)) + break; +#endif + if (dsign) + dval(rv) += ulp(dval(rv)); +#ifndef ROUND_BIASED + else { + dval(rv) -= ulp(dval(rv)); +#ifndef Sudden_Underflow + if (!dval(rv)) + goto undfl; +#endif + } +#ifdef Avoid_Underflow + dsign = 1 - dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = aadj1 = 1.; + else if (word1(rv) || word0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(rv) == Tiny1 && !word0(rv)) + goto undfl; +#endif + aadj = 1.; + aadj1 = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(Rounding) { + case 2: /* towards +infinity */ + aadj1 -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + aadj1 += 0.5; + } +#else + if (Flt_Rounds == 0) + aadj1 += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(rv0) = dval(rv); + word0(rv) -= P*Exp_msk1; + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; + if ((word0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(rv0) == Big0 && word1(rv0) == Big1) + goto ovfl; + word0(rv) = Big0; + word1(rv) = Big1; + goto cont; + } + else + word0(rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = aadj) <= 0) + z = 1; + aadj = z; + aadj1 = dsign ? aadj : -aadj; + } + word0(aadj1) += (2*P+1)*Exp_msk1 - y; + } + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + dval(rv0) = dval(rv); + word0(rv) += P*Exp_msk1; + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; +#ifdef IBM + if ((word0(rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(rv0) == Tiny0 + && word1(rv0) == Tiny1) + goto undfl; + word0(rv) = Tiny0; + word1(rv) = Tiny1; + goto cont; + } + else + word0(rv) -= P*Exp_msk1; + } + else { + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + aadj1 = (double)(int)(aadj + 0.5); + if (!dsign) + aadj1 = -aadj1; + } + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(rv) & Exp_mask; +#ifndef SET_INEXACT +#ifdef Avoid_Underflow + if (!scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } +#endif + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(rv0) = Exp_1 + (70 << Exp_shift); + word1(rv0) = 0; + dval(rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (scale) { + word0(rv0) = Exp_1 - 2*P*Exp_msk1; + word1(rv0) = 0; + dval(rv) *= dval(rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ + if (word0(rv) == 0 && word1(rv) == 0) + PR_SetError(PR_RANGE_ERROR, 0); +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (inexact && !(word0(rv) & Exp_mask)) { + /* set underflow bit */ + dval(rv0) = 1e-300; + dval(rv0) *= dval(rv0); + } +#endif + retfree: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + ret: + if (se) + *se = (char *)s; + return sign ? -dval(rv) : dval(rv); + } + + static int +quorem +#ifdef KR_headers + (b, S) Bigint *b, *S; +#else + (Bigint *b, Bigint *S) +#endif +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; + } + +#ifndef MULTIPLE_THREADS + static char *dtoa_result; +#endif + + static char * +#ifdef KR_headers +rv_alloc(i) int i; +#else +rv_alloc(int i) +#endif +{ + int j, k, *r; + + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; + j <<= 1) + k++; + r = (int*)Balloc(k); + *r = k; + return +#ifndef MULTIPLE_THREADS + dtoa_result = +#endif + (char *)(r+1); + } + + static char * +#ifdef KR_headers +nrv_alloc(s, rve, n) char *s, **rve; int n; +#else +nrv_alloc(char *s, char **rve, int n) +#endif +{ + char *rv, *t; + + t = rv = rv_alloc(n); + while(*t = *s++) t++; + if (rve) + *rve = t; + return rv; + } + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + + void +#ifdef KR_headers +freedtoa(s) char *s; +#else +freedtoa(char *s) +#endif +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(b); +#ifndef MULTIPLE_THREADS + if (s == dtoa_result) + dtoa_result = 0; +#endif + } + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + + static char * +dtoa +#ifdef KR_headers + (d, mode, ndigits, decpt, sign, rve) + double d; int mode, ndigits, *decpt, *sign; char **rve; +#else + (double d, int mode, int ndigits, int *decpt, int *sign, char **rve) +#endif +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo, *mhi, *S; + double d2, ds, eps; + char *s, *s0; +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif + + if (word0(d) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(d) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(d) & Exp_mask) == Exp_mask) +#else + if (word0(d) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(d) && !(word0(d) & 0xfffff)) + return nrv_alloc("Infinity", rve, 8); +#endif + return nrv_alloc("NaN", rve, 3); + } +#endif +#ifdef IBM + dval(d) += 0; /* normalize */ +#endif + if (!dval(d)) { + *decpt = 1; + return nrv_alloc("0", rve, 1); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (*sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif + + b = d2b(dval(d), &be, &bbits); +#ifdef Sudden_Underflow + i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) { +#endif + dval(d2) = dval(d); + word0(d2) &= Frac_mask1; + word0(d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(d2) & Frac_mask)) + dval(d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32 + : word1(d) << 32 - i; + dval(d2) = x; + word0(d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(d) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + switch(mode) { + case 0: + case 1: + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(i); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(d2) = dval(d); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(d) /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(d) /= ds; + } + else if (j1 = -k) { + dval(d) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(d) *= bigtens[i]; + } + } + if (k_check && dval(d) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(d) *= 10.; + ieps++; + } + dval(eps) = ieps*dval(d) + 7.; + word0(eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(d) -= 5.; + if (dval(d) > dval(eps)) + goto one_digit; + if (dval(d) < -dval(eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(eps) = 0.5/tens[ilim-1] - dval(eps); + for(i = 0;;) { + L = dval(d); + dval(d) -= L; + *s++ = '0' + (int)L; + if (dval(d) < dval(eps)) + goto ret1; + if (1. - dval(d) < dval(eps)) + goto bump_up; + if (++i >= ilim) + break; + dval(eps) *= 10.; + dval(d) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d)); + if (!(dval(d) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(d) > 0.5 + dval(eps)) + goto bump_up; + else if (dval(d) < 0.5 - dval(eps)) { + while(*--s == '0'); + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + dval(d) = dval(d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(d) <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1; i <= k+1; i++, dval(d) *= 10.) { + L = (Long)(dval(d) / ds); + dval(d) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(d) < 0) { + L--; + dval(d) += ds; + } +#endif + *s++ = '0' + (int)L; + if (!dval(d)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(d) += dval(d); + if (dval(d) > ds || dval(d) == ds && L & 1) { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + if (j = b5 - m5) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && rounding == 1 +#endif + ) { + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) + i = 32 - i; +#else + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) + i = 16 - i; +#endif + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ + no_digits: + k = -1 - ndigits; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(d) & 1) +#ifdef Honor_FLT_ROUNDS + && rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + ) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); + if ((j1 > 0 || j1 == 0 && dig & 1) + && dig++ == '9') + goto round_9_up; + } + accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS + keep_dig: +#endif + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(b, 1); + j = cmp(b, S); + if (j > 0 || j == 0 && dig & 1) { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { + trimzeros: + while(*--s == '0'); + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(d) = Exp_1 + (70 << Exp_shift); + word1(d) = 0; + dval(d) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + } +#ifdef __cplusplus +} +#endif + +PR_IMPLEMENT(PRStatus) +PR_dtoa(PRFloat64 d, PRIntn mode, PRIntn ndigits, + PRIntn *decpt, PRIntn *sign, char **rve, char *buf, PRSize bufsize) +{ + char *result; + PRSize resultlen; + PRStatus rv = PR_FAILURE; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (mode < 0 || mode > 3) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return rv; + } + result = dtoa(d, mode, ndigits, decpt, sign, rve); + if (!result) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return rv; + } + resultlen = strlen(result)+1; + if (bufsize < resultlen) { + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); + } else { + memcpy(buf, result, resultlen); + if (rve) { + *rve = buf + (*rve - result); + } + rv = PR_SUCCESS; + } + freedtoa(result); + return rv; +} + +/* +** conversion routines for floating point +** prcsn - number of digits of precision to generate floating +** point value. +** This should be reparameterized so that you can send in a +** prcn for the positive and negative ranges. For now, +** conform to the ECMA JavaScript spec which says numbers +** less than 1e-6 are in scientific notation. +** Also, the ECMA spec says that there should always be a +** '+' or '-' after the 'e' in scientific notation +*/ +PR_IMPLEMENT(void) +PR_cnvtf(char *buf,int bufsz, int prcsn,double fval) +{ + PRIntn decpt, sign, numdigits; + char *num, *nump; + char *bufp = buf; + char *endnum; + + /* If anything fails, we store an empty string in 'buf' */ + num = (char*)PR_MALLOC(bufsz); + if (num == NULL) { + buf[0] = '\0'; + return; + } + /* XXX Why use mode 1? */ + if (PR_dtoa(dval(fval),1,prcsn,&decpt,&sign,&endnum,num,bufsz) + == PR_FAILURE) { + buf[0] = '\0'; + goto done; + } + numdigits = endnum - num; + nump = num; + + if (sign && + !(word0(fval) == Sign_bit && word1(fval) == 0) && + !((word0(fval) & Exp_mask) == Exp_mask && + (word1(fval) || (word0(fval) & 0xfffff)))) { + *bufp++ = '-'; + } + + if (decpt == 9999) { + while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */ + goto done; + } + + if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) { + *bufp++ = *nump++; + if (numdigits != 1) { + *bufp++ = '.'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = 'e'; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1); + } else if (decpt >= 0) { + if (decpt == 0) { + *bufp++ = '0'; + } else { + while (decpt--) { + if (*nump != '\0') { + *bufp++ = *nump++; + } else { + *bufp++ = '0'; + } + } + } + if (*nump != '\0') { + *bufp++ = '.'; + while (*nump != '\0') { + *bufp++ = *nump++; + } + } + *bufp++ = '\0'; + } else if (decpt < 0) { + *bufp++ = '0'; + *bufp++ = '.'; + while (decpt++) { + *bufp++ = '0'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = '\0'; + } +done: + PR_DELETE(num); +} diff --git a/nsprpub/pr/src/misc/prenv.c b/nsprpub/pr/src/misc/prenv.c new file mode 100644 index 00000000000..5f16ce1890d --- /dev/null +++ b/nsprpub/pr/src/misc/prenv.c @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include "primpl.h" + +/* Lock used to lock the environment */ +#if defined(_PR_NO_PREEMPT) +#define _PR_NEW_LOCK_ENV() +#define _PR_DELETE_LOCK_ENV() +#define _PR_LOCK_ENV() +#define _PR_UNLOCK_ENV() +#elif defined(_PR_LOCAL_THREADS_ONLY) +extern _PRCPU * _pr_primordialCPU; +static PRIntn _is; +#define _PR_NEW_LOCK_ENV() +#define _PR_DELETE_LOCK_ENV() +#define _PR_LOCK_ENV() if (_pr_primordialCPU) _PR_INTSOFF(_is); +#define _PR_UNLOCK_ENV() if (_pr_primordialCPU) _PR_INTSON(_is); +#else +static PRLock *_pr_envLock = NULL; +#define _PR_NEW_LOCK_ENV() {_pr_envLock = PR_NewLock();} +#define _PR_DELETE_LOCK_ENV() \ + { if (_pr_envLock) { PR_DestroyLock(_pr_envLock); _pr_envLock = NULL; } } +#define _PR_LOCK_ENV() { if (_pr_envLock) PR_Lock(_pr_envLock); } +#define _PR_UNLOCK_ENV() { if (_pr_envLock) PR_Unlock(_pr_envLock); } +#endif + +/************************************************************************/ + +void _PR_InitEnv(void) +{ + _PR_NEW_LOCK_ENV(); +} + +void _PR_CleanupEnv(void) +{ + _PR_DELETE_LOCK_ENV(); +} + +PR_IMPLEMENT(char*) PR_GetEnv(const char *var) +{ + char *ev; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _PR_LOCK_ENV(); + ev = _PR_MD_GET_ENV(var); + _PR_UNLOCK_ENV(); + return ev; +} + +PR_IMPLEMENT(PRStatus) PR_SetEnv(const char *string) +{ + PRIntn result; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if ( !strchr(string, '=')) return(PR_FAILURE); + + _PR_LOCK_ENV(); + result = _PR_MD_PUT_ENV(string); + _PR_UNLOCK_ENV(); + return (result)? PR_FAILURE : PR_SUCCESS; +} + +/* +** DEPRECATED. Use PR_SetEnv() instead. +*/ +#ifdef XP_MAC +PR_IMPLEMENT(PRIntn) PR_PutEnv(const char *string) +{ + return (PR_SetEnv(string) == PR_SUCCESS) ? PR_TRUE : PR_FALSE; +} +#endif diff --git a/nsprpub/pr/src/misc/prerr.c b/nsprpub/pr/src/misc/prerr.c new file mode 100644 index 00000000000..4db31132dd7 --- /dev/null +++ b/nsprpub/pr/src/misc/prerr.c @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * + * prerr.c + * This file is automatically generated; please do not edit it. + */ +#include "prerror.h" +static const struct PRErrorMessage text[] = { + {"PR_OUT_OF_MEMORY_ERROR", "Memory allocation attempt failed"}, + {"PR_BAD_DESCRIPTOR_ERROR", "Invalid file descriptor"}, + {"PR_WOULD_BLOCK_ERROR", "The operation would have blocked"}, + {"PR_ACCESS_FAULT_ERROR", "Invalid memory address argument"}, + {"PR_INVALID_METHOD_ERROR", "Invalid function for file type"}, + {"PR_ILLEGAL_ACCESS_ERROR", "Invalid memory address argument"}, + {"PR_UNKNOWN_ERROR", "Some unknown error has occurred"}, + {"PR_PENDING_INTERRUPT_ERROR", "Operation interrupted by another thread"}, + {"PR_NOT_IMPLEMENTED_ERROR", "function not implemented"}, + {"PR_IO_ERROR", "I/O function error"}, + {"PR_IO_TIMEOUT_ERROR", "I/O operation timed out"}, + {"PR_IO_PENDING_ERROR", "I/O operation on busy file descriptor"}, + {"PR_DIRECTORY_OPEN_ERROR", "The directory could not be opened"}, + {"PR_INVALID_ARGUMENT_ERROR", "Invalid function argument"}, + {"PR_ADDRESS_NOT_AVAILABLE_ERROR", "Network address not available (in use?)"}, + {"PR_ADDRESS_NOT_SUPPORTED_ERROR", "Network address type not supported"}, + {"PR_IS_CONNECTED_ERROR", "Already connected"}, + {"PR_BAD_ADDRESS_ERROR", "Network address is invalid"}, + {"PR_ADDRESS_IN_USE_ERROR", "Local Network address is in use"}, + {"PR_CONNECT_REFUSED_ERROR", "Connection refused by peer"}, + {"PR_NETWORK_UNREACHABLE_ERROR", "Network address is presently unreachable"}, + {"PR_CONNECT_TIMEOUT_ERROR", "Connection attempt timed out"}, + {"PR_NOT_CONNECTED_ERROR", "Network file descriptor is not connected"}, + {"PR_LOAD_LIBRARY_ERROR", "Failure to load dynamic library"}, + {"PR_UNLOAD_LIBRARY_ERROR", "Failure to unload dynamic library"}, + {"PR_FIND_SYMBOL_ERROR", "Symbol not found in any of the loaded dynamic libraries"}, + {"PR_INSUFFICIENT_RESOURCES_ERROR", "Insufficient system resources"}, + {"PR_DIRECTORY_LOOKUP_ERROR", "A directory lookup on a network address has failed"}, + {"PR_TPD_RANGE_ERROR", "Attempt to access a TPD key that is out of range"}, + {"PR_PROC_DESC_TABLE_FULL_ERROR", "Process open FD table is full"}, + {"PR_SYS_DESC_TABLE_FULL_ERROR", "System open FD table is full"}, + {"PR_NOT_SOCKET_ERROR", "Network operation attempted on non-network file descriptor"}, + {"PR_NOT_TCP_SOCKET_ERROR", "TCP-specific function attempted on a non-TCP file descriptor"}, + {"PR_SOCKET_ADDRESS_IS_BOUND_ERROR", "TCP file descriptor is already bound"}, + {"PR_NO_ACCESS_RIGHTS_ERROR", "Access Denied"}, + {"PR_OPERATION_NOT_SUPPORTED_ERROR", "The requested operation is not supported by the platform"}, + {"PR_PROTOCOL_NOT_SUPPORTED_ERROR", "The host operating system does not support the protocol requested"}, + {"PR_REMOTE_FILE_ERROR", "Access to the remote file has been severed"}, + {"PR_BUFFER_OVERFLOW_ERROR", "The value requested is too large to be stored in the data buffer provided"}, + {"PR_CONNECT_RESET_ERROR", "TCP connection reset by peer"}, + {"PR_RANGE_ERROR", "Unused"}, + {"PR_DEADLOCK_ERROR", "The operation would have deadlocked"}, + {"PR_FILE_IS_LOCKED_ERROR", "The file is already locked"}, + {"PR_FILE_TOO_BIG_ERROR", "Write would result in file larger than the system allows"}, + {"PR_NO_DEVICE_SPACE_ERROR", "The device for storing the file is full"}, + {"PR_PIPE_ERROR", "Unused"}, + {"PR_NO_SEEK_DEVICE_ERROR", "Unused"}, + {"PR_IS_DIRECTORY_ERROR", "Cannot perform a normal file operation on a directory"}, + {"PR_LOOP_ERROR", "Symbolic link loop"}, + {"PR_NAME_TOO_LONG_ERROR", "File name is too long"}, + {"PR_FILE_NOT_FOUND_ERROR", "File not found"}, + {"PR_NOT_DIRECTORY_ERROR", "Cannot perform directory operation on a normal file"}, + {"PR_READ_ONLY_FILESYSTEM_ERROR", "Cannot write to a read-only file system"}, + {"PR_DIRECTORY_NOT_EMPTY_ERROR", "Cannot delete a directory that is not empty"}, + {"PR_FILESYSTEM_MOUNTED_ERROR", "Cannot delete or rename a file object while the file system is busy"}, + {"PR_NOT_SAME_DEVICE_ERROR", "Cannot rename a file to a file system on another device"}, + {"PR_DIRECTORY_CORRUPTED_ERROR", "The directory object in the file system is corrupted"}, + {"PR_FILE_EXISTS_ERROR", "Cannot create or rename a filename that already exists"}, + {"PR_MAX_DIRECTORY_ENTRIES_ERROR", "Directory is full. No additional filenames may be added"}, + {"PR_INVALID_DEVICE_STATE_ERROR", "The required device was in an invalid state"}, + {"PR_DEVICE_IS_LOCKED_ERROR", "The device is locked"}, + {"PR_NO_MORE_FILES_ERROR", "No more entries in the directory"}, + {"PR_END_OF_FILE_ERROR", "Encountered end of file"}, + {"PR_FILE_SEEK_ERROR", "Seek error"}, + {"PR_FILE_IS_BUSY_ERROR", "The file is busy"}, + {"PR_OPERATION_ABORTED_ERROR", "The I/O operation was aborted"}, + {"PR_IN_PROGRESS_ERROR", "Operation is still in progress (probably a non-blocking connect)"}, + {"PR_ALREADY_INITIATED_ERROR", "Operation has already been initiated (probably a non-blocking connect)"}, + {"PR_GROUP_EMPTY_ERROR", "The wait group is empty"}, + {"PR_INVALID_STATE_ERROR", "Object state improper for request"}, + {"PR_NETWORK_DOWN_ERROR", "Network is down"}, + {"PR_SOCKET_SHUTDOWN_ERROR", "Socket shutdown"}, + {"PR_CONNECT_ABORTED_ERROR", "Connection aborted"}, + {"PR_HOST_UNREACHABLE_ERROR", "Host is unreachable"}, + {"PR_LIBRARY_NOT_LOADED_ERROR", "The library is not loaded"}, + {"PR_CALL_ONCE_ERROR", "The one-time function was previously called and failed. Its error code is no longer available"}, + {"PR_MAX_ERROR", "Placeholder for the end of the list"}, + {0, 0} +}; + +static const struct PRErrorTable et = { text, "prerr", -6000L, 77 }; + +void nspr_InitializePRErrorTable(void) { + PR_ErrorInstallTable(&et); +} diff --git a/nsprpub/pr/src/misc/prerr.et b/nsprpub/pr/src/misc/prerr.et new file mode 100644 index 00000000000..8578f95fe21 --- /dev/null +++ b/nsprpub/pr/src/misc/prerr.et @@ -0,0 +1,140 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +et nspr -6000 + +ec PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed" +ec PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor" +ec PR_WOULD_BLOCK_ERROR, "The operation would have blocked" +ec PR_ACCESS_FAULT_ERROR, "Invalid memory address argument" +ec PR_INVALID_METHOD_ERROR, "Invalid function for file type" +ec PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument" +ec PR_UNKNOWN_ERROR, "Some unknown error has occurred" +ec PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread" +ec PR_NOT_IMPLEMENTED_ERROR, "function not implemented" +ec PR_IO_ERROR, "I/O function error" +ec PR_IO_TIMEOUT_ERROR, "I/O operation timed out" +ec PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor" +ec PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened" +ec PR_INVALID_ARGUMENT_ERROR, "Invalid function argument" +ec PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)" +ec PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported" +ec PR_IS_CONNECTED_ERROR, "Already connected" +ec PR_BAD_ADDRESS_ERROR, "Network address is invalid" +ec PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use" +ec PR_CONNECT_REFUSED_ERROR, "Connection refused by peer" +ec PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable" +ec PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out" +ec PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected" +ec PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library" +ec PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library" +ec PR_FIND_SYMBOL_ERROR, +"Symbol not found in any of the loaded dynamic libraries" +ec PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources" +ec PR_DIRECTORY_LOOKUP_ERROR, +"A directory lookup on a network address has failed" +ec PR_TPD_RANGE_ERROR, +"Attempt to access a TPD key that is out of range" +ec PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full" +ec PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full" +ec PR_NOT_SOCKET_ERROR, +"Network operation attempted on non-network file descriptor" +ec PR_NOT_TCP_SOCKET_ERROR, +"TCP-specific function attempted on a non-TCP file descriptor" +ec PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound" +ec PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied" +ec PR_OPERATION_NOT_SUPPORTED_ERROR, +"The requested operation is not supported by the platform" +ec PR_PROTOCOL_NOT_SUPPORTED_ERROR, +"The host operating system does not support the protocol requested" +ec PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed" +ec PR_BUFFER_OVERFLOW_ERROR, +"The value requested is too large to be stored in the data buffer provided" +ec PR_CONNECT_RESET_ERROR, "TCP connection reset by peer" +ec PR_RANGE_ERROR, "Unused" +ec PR_DEADLOCK_ERROR, "The operation would have deadlocked" +ec PR_FILE_IS_LOCKED_ERROR, "The file is already locked" +ec PR_FILE_TOO_BIG_ERROR, +"Write would result in file larger than the system allows" +ec PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full" +ec PR_PIPE_ERROR, "Unused" +ec PR_NO_SEEK_DEVICE_ERROR, "Unused" +ec PR_IS_DIRECTORY_ERROR, +"Cannot perform a normal file operation on a directory" +ec PR_LOOP_ERROR, "Symbolic link loop" +ec PR_NAME_TOO_LONG_ERROR, "File name is too long" +ec PR_FILE_NOT_FOUND_ERROR, "File not found" +ec PR_NOT_DIRECTORY_ERROR, +"Cannot perform directory operation on a normal file" +ec PR_READ_ONLY_FILESYSTEM_ERROR, +"Cannot write to a read-only file system" +ec PR_DIRECTORY_NOT_EMPTY_ERROR, +"Cannot delete a directory that is not empty" +ec PR_FILESYSTEM_MOUNTED_ERROR, +"Cannot delete or rename a file object while the file system is busy" +ec PR_NOT_SAME_DEVICE_ERROR, +"Cannot rename a file to a file system on another device" +ec PR_DIRECTORY_CORRUPTED_ERROR, +"The directory object in the file system is corrupted" +ec PR_FILE_EXISTS_ERROR, +"Cannot create or rename a filename that already exists" +ec PR_MAX_DIRECTORY_ENTRIES_ERROR, +"Directory is full. No additional filenames may be added" +ec PR_INVALID_DEVICE_STATE_ERROR, +"The required device was in an invalid state" +ec PR_DEVICE_IS_LOCKED_ERROR, "The device is locked" +ec PR_NO_MORE_FILES_ERROR, "No more entries in the directory" +ec PR_END_OF_FILE_ERROR, "Encountered end of file" +ec PR_FILE_SEEK_ERROR, "Seek error" +ec PR_FILE_IS_BUSY_ERROR, "The file is busy" +ec PR_OPERATION_ABORTED_ERROR, "The I/O operation was aborted" +ec PR_IN_PROGRESS_ERROR, +"Operation is still in progress (probably a non-blocking connect)" +ec PR_ALREADY_INITIATED_ERROR, +"Operation has already been initiated (probably a non-blocking connect)" +ec PR_GROUP_EMPTY_ERROR, "The wait group is empty" +ec PR_INVALID_STATE_ERROR, "Object state improper for request" +ec PR_NETWORK_DOWN_ERROR, "Network is down" +ec PR_SOCKET_SHUTDOWN_ERROR, "Socket shutdown" +ec PR_CONNECT_ABORTED_ERROR, "Connection aborted" +ec PR_HOST_UNREACHABLE_ERROR, "Host is unreachable" +ec PR_LIBRARY_NOT_LOADED_ERROR, "The library is not loaded" +ec PR_CALL_ONCE_ERROR, "The one-time function was previously called and failed. Its error code is no longer available" + +ec PR_MAX_ERROR, "Placeholder for the end of the list" + +end diff --git a/nsprpub/pr/src/misc/prerr.properties b/nsprpub/pr/src/misc/prerr.properties new file mode 100644 index 00000000000..58a02859d23 --- /dev/null +++ b/nsprpub/pr/src/misc/prerr.properties @@ -0,0 +1,117 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# prerr.properties +# This file is automatically generated; please do not edit it. +PR_OUT_OF_MEMORY_ERROR=Memory allocation attempt failed +PR_BAD_DESCRIPTOR_ERROR=Invalid file descriptor +PR_WOULD_BLOCK_ERROR=The operation would have blocked +PR_ACCESS_FAULT_ERROR=Invalid memory address argument +PR_INVALID_METHOD_ERROR=Invalid function for file type +PR_ILLEGAL_ACCESS_ERROR=Invalid memory address argument +PR_UNKNOWN_ERROR=Some unknown error has occurred +PR_PENDING_INTERRUPT_ERROR=Operation interrupted by another thread +PR_NOT_IMPLEMENTED_ERROR=function not implemented +PR_IO_ERROR=I/O function error +PR_IO_TIMEOUT_ERROR=I/O operation timed out +PR_IO_PENDING_ERROR=I/O operation on busy file descriptor +PR_DIRECTORY_OPEN_ERROR=The directory could not be opened +PR_INVALID_ARGUMENT_ERROR=Invalid function argument +PR_ADDRESS_NOT_AVAILABLE_ERROR=Network address not available (in use?) +PR_ADDRESS_NOT_SUPPORTED_ERROR=Network address type not supported +PR_IS_CONNECTED_ERROR=Already connected +PR_BAD_ADDRESS_ERROR=Network address is invalid +PR_ADDRESS_IN_USE_ERROR=Local Network address is in use +PR_CONNECT_REFUSED_ERROR=Connection refused by peer +PR_NETWORK_UNREACHABLE_ERROR=Network address is presently unreachable +PR_CONNECT_TIMEOUT_ERROR=Connection attempt timed out +PR_NOT_CONNECTED_ERROR=Network file descriptor is not connected +PR_LOAD_LIBRARY_ERROR=Failure to load dynamic library +PR_UNLOAD_LIBRARY_ERROR=Failure to unload dynamic library +PR_FIND_SYMBOL_ERROR=Symbol not found in any of the loaded dynamic libraries +PR_INSUFFICIENT_RESOURCES_ERROR=Insufficient system resources +PR_DIRECTORY_LOOKUP_ERROR=A directory lookup on a network address has failed +PR_TPD_RANGE_ERROR=Attempt to access a TPD key that is out of range +PR_PROC_DESC_TABLE_FULL_ERROR=Process open FD table is full +PR_SYS_DESC_TABLE_FULL_ERROR=System open FD table is full +PR_NOT_SOCKET_ERROR=Network operation attempted on non-network file descriptor +PR_NOT_TCP_SOCKET_ERROR=TCP-specific function attempted on a non-TCP file descriptor +PR_SOCKET_ADDRESS_IS_BOUND_ERROR=TCP file descriptor is already bound +PR_NO_ACCESS_RIGHTS_ERROR=Access Denied +PR_OPERATION_NOT_SUPPORTED_ERROR=The requested operation is not supported by the platform +PR_PROTOCOL_NOT_SUPPORTED_ERROR=The host operating system does not support the protocol requested +PR_REMOTE_FILE_ERROR=Access to the remote file has been severed +PR_BUFFER_OVERFLOW_ERROR=The value requested is too large to be stored in the data buffer provided +PR_CONNECT_RESET_ERROR=TCP connection reset by peer +PR_RANGE_ERROR=Unused +PR_DEADLOCK_ERROR=The operation would have deadlocked +PR_FILE_IS_LOCKED_ERROR=The file is already locked +PR_FILE_TOO_BIG_ERROR=Write would result in file larger than the system allows +PR_NO_DEVICE_SPACE_ERROR=The device for storing the file is full +PR_PIPE_ERROR=Unused +PR_NO_SEEK_DEVICE_ERROR=Unused +PR_IS_DIRECTORY_ERROR=Cannot perform a normal file operation on a directory +PR_LOOP_ERROR=Symbolic link loop +PR_NAME_TOO_LONG_ERROR=File name is too long +PR_FILE_NOT_FOUND_ERROR=File not found +PR_NOT_DIRECTORY_ERROR=Cannot perform directory operation on a normal file +PR_READ_ONLY_FILESYSTEM_ERROR=Cannot write to a read-only file system +PR_DIRECTORY_NOT_EMPTY_ERROR=Cannot delete a directory that is not empty +PR_FILESYSTEM_MOUNTED_ERROR=Cannot delete or rename a file object while the file system is busy +PR_NOT_SAME_DEVICE_ERROR=Cannot rename a file to a file system on another device +PR_DIRECTORY_CORRUPTED_ERROR=The directory object in the file system is corrupted +PR_FILE_EXISTS_ERROR=Cannot create or rename a filename that already exists +PR_MAX_DIRECTORY_ENTRIES_ERROR=Directory is full. No additional filenames may be added +PR_INVALID_DEVICE_STATE_ERROR=The required device was in an invalid state +PR_DEVICE_IS_LOCKED_ERROR=The device is locked +PR_NO_MORE_FILES_ERROR=No more entries in the directory +PR_END_OF_FILE_ERROR=Encountered end of file +PR_FILE_SEEK_ERROR=Seek error +PR_FILE_IS_BUSY_ERROR=The file is busy +PR_OPERATION_ABORTED_ERROR=The I/O operation was aborted +PR_IN_PROGRESS_ERROR=Operation is still in progress (probably a non-blocking connect) +PR_ALREADY_INITIATED_ERROR=Operation has already been initiated (probably a non-blocking connect) +PR_GROUP_EMPTY_ERROR=The wait group is empty +PR_INVALID_STATE_ERROR=Object state improper for request +PR_NETWORK_DOWN_ERROR=Network is down +PR_SOCKET_SHUTDOWN_ERROR=Socket shutdown +PR_CONNECT_ABORTED_ERROR=Connection aborted +PR_HOST_UNREACHABLE_ERROR=Host is unreachable +PR_LIBRARY_NOT_LOADED_ERROR=The library is not loaded +PR_CALL_ONCE_ERROR=The one-time function was previously called and failed. Its error code is no longer available +PR_MAX_ERROR=Placeholder for the end of the list diff --git a/nsprpub/pr/src/misc/prerror.c b/nsprpub/pr/src/misc/prerror.c new file mode 100644 index 00000000000..f578f2d24a3 --- /dev/null +++ b/nsprpub/pr/src/misc/prerror.c @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include + +PR_IMPLEMENT(PRErrorCode) PR_GetError(void) +{ + PRThread *thread = PR_GetCurrentThread(); + return thread->errorCode; +} + +PR_IMPLEMENT(PRInt32) PR_GetOSError(void) +{ + PRThread *thread = PR_GetCurrentThread(); + return thread->osErrorCode; +} + +PR_IMPLEMENT(void) PR_SetError(PRErrorCode code, PRInt32 osErr) +{ + PRThread *thread = PR_GetCurrentThread(); + thread->errorCode = code; + thread->osErrorCode = osErr; + thread->errorStringLength = 0; +} + +PR_IMPLEMENT(void) PR_SetErrorText(PRIntn textLength, const char *text) +{ + PRThread *thread = PR_GetCurrentThread(); + + if (0 == textLength) + { + if (NULL != thread->errorString) + PR_DELETE(thread->errorString); + thread->errorStringSize = 0; + } + else + { + PRIntn size = textLength + 31; /* actual length to allocate. Plus a little extra */ + if (thread->errorStringSize < textLength+1) /* do we have room? */ + { + if (NULL != thread->errorString) + PR_DELETE(thread->errorString); + thread->errorString = (char*)PR_MALLOC(size); + if ( NULL == thread->errorString ) { + thread->errorStringSize = 0; + thread->errorStringLength = 0; + return; + } + thread->errorStringSize = size; + } + memcpy(thread->errorString, text, textLength+1 ); + } + thread->errorStringLength = textLength; +} + +PR_IMPLEMENT(PRInt32) PR_GetErrorTextLength(void) +{ + PRThread *thread = PR_GetCurrentThread(); + return thread->errorStringLength; +} /* PR_GetErrorTextLength */ + +PR_IMPLEMENT(PRInt32) PR_GetErrorText(char *text) +{ + PRThread *thread = PR_GetCurrentThread(); + if (0 != thread->errorStringLength) + memcpy(text, thread->errorString, thread->errorStringLength+1); + return thread->errorStringLength; +} /* PR_GetErrorText */ + + diff --git a/nsprpub/pr/src/misc/prerrortable.c b/nsprpub/pr/src/misc/prerrortable.c new file mode 100644 index 00000000000..a51b4e8fcf3 --- /dev/null +++ b/nsprpub/pr/src/misc/prerrortable.c @@ -0,0 +1,240 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + + + +/* + +Copyright 1987, 1988 by the Student Information Processing Board + of the Massachusetts Institute of Technology + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is +hereby granted, provided that the above copyright notice +appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, +and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. +M.I.T. and the M.I.T. S.I.P.B. make no representations about +the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. + +*/ + +#include +#ifdef SUNOS4 +#include "md/sunos4.h" /* for strerror */ +#endif +#include +#include +#include "prmem.h" +#include "prerror.h" + +#define ERRCODE_RANGE 8 /* # of bits to shift table number */ +#define BITS_PER_CHAR 6 /* # bits to shift per character in name */ + +#ifdef NEED_SYS_ERRLIST +extern char const * const sys_errlist[]; +extern const int sys_nerr; +#endif + +/* List of error tables */ +struct PRErrorTableList { + struct PRErrorTableList *next; + const struct PRErrorTable *table; + struct PRErrorCallbackTablePrivate *table_private; +}; +static struct PRErrorTableList * Table_List = (struct PRErrorTableList *) NULL; + +/* Supported languages */ +static const char * default_languages[] = { "i-default", "en", 0 }; +static const char * const * callback_languages = default_languages; + +/* Callback info */ +static struct PRErrorCallbackPrivate *callback_private = 0; +static PRErrorCallbackLookupFn *callback_lookup = 0; +static PRErrorCallbackNewTableFn *callback_newtable = 0; + + +static const char char_set[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; + +static const char * +error_table_name (PRErrorCode num) +{ + static char buf[6]; /* only used if internal code problems exist */ + + long ch; + int i; + char *p; + + /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */ + p = buf; + num >>= ERRCODE_RANGE; + /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */ + num &= 077777777; + /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */ + for (i = 4; i >= 0; i--) { + ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1); + if (ch != 0) + *p++ = char_set[ch-1]; + } + *p = '\0'; + return(buf); +} + +PR_IMPLEMENT(const char *) +PR_ErrorToString(PRErrorCode code, PRLanguageCode language) +{ + /* static buffer only used if code is using inconsistent error message + * numbers, so just ignore the possible thread contention + */ + static char buffer[25]; + + const char *msg; + int offset; + PRErrorCode table_num; + struct PRErrorTableList *et; + int started = 0; + char *cp; + + for (et = Table_List; et; et = et->next) { + if (et->table->base <= code && + et->table->base + et->table->n_msgs > code) { + /* This is the right table */ + if (callback_lookup) { + msg = callback_lookup(code, language, et->table, + callback_private, et->table_private); + if (msg) return msg; + } + + return(et->table->msgs[code - et->table->base].en_text); + } + } + + if (code >= 0 && code < 256) { + return strerror(code); + } + + offset = (int) (code & ((1<= 100) { + *cp++ = (char)('0' + offset / 100); + offset %= 100; + started++; + } + if (started || offset >= 10) { + *cp++ = (char)('0' + offset / 10); + offset %= 10; + } + *cp++ = (char)('0' + offset); + *cp = '\0'; + return(buffer); +} + +PR_IMPLEMENT(const char *) +PR_ErrorToName(PRErrorCode code) +{ + struct PRErrorTableList *et; + + for (et = Table_List; et; et = et->next) { + if (et->table->base <= code && + et->table->base + et->table->n_msgs > code) { + /* This is the right table */ + return(et->table->msgs[code - et->table->base].name); + } + } + + return 0; +} + +PR_IMPLEMENT(const char * const *) +PR_ErrorLanguages(void) +{ + return callback_languages; +} + +PR_IMPLEMENT(PRErrorCode) +PR_ErrorInstallTable(const struct PRErrorTable *table) +{ + struct PRErrorTableList * new_et; + + new_et = (struct PRErrorTableList *) + PR_Malloc(sizeof(struct PRErrorTableList)); + if (!new_et) + return errno; /* oops */ + new_et->table = table; + if (callback_newtable) { + new_et->table_private = callback_newtable(table, callback_private); + } else { + new_et->table_private = 0; + } + new_et->next = Table_List; + Table_List = new_et; + return 0; +} + +PR_IMPLEMENT(void) +PR_ErrorInstallCallback(const char * const * languages, + PRErrorCallbackLookupFn *lookup, + PRErrorCallbackNewTableFn *newtable, + struct PRErrorCallbackPrivate *cb_private) +{ + struct PRErrorTableList *et; + + assert(strcmp(languages[0], "i-default") == 0); + assert(strcmp(languages[1], "en") == 0); + + callback_languages = languages; + callback_lookup = lookup; + callback_newtable = newtable; + callback_private = cb_private; + + if (callback_newtable) { + for (et = Table_List; et; et = et->next) { + et->table_private = callback_newtable(et->table, callback_private); + } + } +} diff --git a/nsprpub/pr/src/misc/prinit.c b/nsprpub/pr/src/misc/prinit.c new file mode 100644 index 00000000000..dc4ca98c20e --- /dev/null +++ b/nsprpub/pr/src/misc/prinit.c @@ -0,0 +1,873 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include +#include + +PRLogModuleInfo *_pr_clock_lm; +PRLogModuleInfo *_pr_cmon_lm; +PRLogModuleInfo *_pr_io_lm; +PRLogModuleInfo *_pr_cvar_lm; +PRLogModuleInfo *_pr_mon_lm; +PRLogModuleInfo *_pr_linker_lm; +PRLogModuleInfo *_pr_sched_lm; +PRLogModuleInfo *_pr_thread_lm; +PRLogModuleInfo *_pr_gc_lm; +PRLogModuleInfo *_pr_shm_lm; +PRLogModuleInfo *_pr_shma_lm; + +PRFileDesc *_pr_stdin; +PRFileDesc *_pr_stdout; +PRFileDesc *_pr_stderr; + +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + +PRCList _pr_active_local_threadQ = + PR_INIT_STATIC_CLIST(&_pr_active_local_threadQ); +PRCList _pr_active_global_threadQ = + PR_INIT_STATIC_CLIST(&_pr_active_global_threadQ); + +_MDLock _pr_cpuLock; /* lock for the CPU Q */ +PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ); + +PRUint32 _pr_utid; + +PRInt32 _pr_userActive; +PRInt32 _pr_systemActive; +PRUintn _pr_maxPTDs; + +#ifdef _PR_LOCAL_THREADS_ONLY + +struct _PRCPU *_pr_currentCPU; +PRThread *_pr_currentThread; +PRThread *_pr_lastThread; +PRInt32 _pr_intsOff; + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +/* Lock protecting all "termination" condition variables of all threads */ +PRLock *_pr_terminationCVLock; + +#endif /* !defined(_PR_PTHREADS) */ + +PRLock *_pr_sleeplock; /* used in PR_Sleep(), classic and pthreads */ + +static void _PR_InitCallOnce(void); + +PRBool _pr_initialized = PR_FALSE; + + +PR_IMPLEMENT(PRBool) PR_VersionCheck(const char *importedVersion) +{ + /* + ** This is the secret handshake algorithm. + ** + ** This release has a simple version compatibility + ** check algorithm. This release is not backward + ** compatible with previous major releases. It is + ** not compatible with future major, minor, or + ** patch releases. + */ + int vmajor = 0, vminor = 0, vpatch = 0; + const char *ptr = importedVersion; + + while (isdigit(*ptr)) { + vmajor = 10 * vmajor + *ptr - '0'; + ptr++; + } + if (*ptr == '.') { + ptr++; + while (isdigit(*ptr)) { + vminor = 10 * vminor + *ptr - '0'; + ptr++; + } + if (*ptr == '.') { + ptr++; + while (isdigit(*ptr)) { + vpatch = 10 * vpatch + *ptr - '0'; + ptr++; + } + } + } + + if (vmajor != PR_VMAJOR) { + return PR_FALSE; + } + if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) { + return PR_FALSE; + } + if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) { + return PR_FALSE; + } + return PR_TRUE; +} /* PR_VersionCheck */ + + +PR_IMPLEMENT(PRBool) PR_Initialized(void) +{ + return _pr_initialized; +} + +PRInt32 _native_threads_only = 0; + +#ifdef WINNT +static void _pr_SetNativeThreadsOnlyMode(void) +{ + HMODULE mainExe; + PRBool *globalp; + char *envp; + + mainExe = GetModuleHandle(NULL); + PR_ASSERT(NULL != mainExe); + globalp = (PRBool *) GetProcAddress(mainExe, "nspr_native_threads_only"); + if (globalp) { + _native_threads_only = (*globalp != PR_FALSE); + } else if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) { + _native_threads_only = (atoi(envp) == 1); + } +} +#endif + +static void _PR_InitStuff(void) +{ + + if (_pr_initialized) return; + _pr_initialized = PR_TRUE; +#ifdef _PR_ZONE_ALLOCATOR + _PR_InitZones(); +#endif +#ifdef WINNT + _pr_SetNativeThreadsOnlyMode(); +#endif + + + (void) PR_GetPageSize(); + + _pr_clock_lm = PR_NewLogModule("clock"); + _pr_cmon_lm = PR_NewLogModule("cmon"); + _pr_io_lm = PR_NewLogModule("io"); + _pr_mon_lm = PR_NewLogModule("mon"); + _pr_linker_lm = PR_NewLogModule("linker"); + _pr_cvar_lm = PR_NewLogModule("cvar"); + _pr_sched_lm = PR_NewLogModule("sched"); + _pr_thread_lm = PR_NewLogModule("thread"); + _pr_gc_lm = PR_NewLogModule("gc"); + _pr_shm_lm = PR_NewLogModule("shm"); + _pr_shma_lm = PR_NewLogModule("shma"); + + /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ + _PR_MD_EARLY_INIT(); + + _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); + +#ifdef GC_LEAK_DETECTOR + _PR_InitGarbageCollector(); +#endif + + _PR_InitThreads(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + +#ifdef WIN16 + { + PRInt32 top; /* artificial top of stack, win16 */ + _pr_top_of_task_stack = (char *) ⊤ + } +#endif + +#ifndef _PR_GLOBAL_THREADS_ONLY + _PR_InitCPUs(); +#endif + +/* + * XXX: call _PR_InitMem only on those platforms for which nspr implements + * malloc, for now. + */ +#ifdef _PR_OVERRIDE_MALLOC + _PR_InitMem(); +#endif + + _PR_InitCMon(); + _PR_InitIO(); + _PR_InitNet(); + _PR_InitLog(); + _PR_InitLinker(); + _PR_InitCallOnce(); + _PR_InitDtoa(); + _PR_InitTime(); + _PR_InitMW(); + _PR_InitRWLocks(); + + nspr_InitializePRErrorTable(); + + _PR_MD_FINAL_INIT(); +} + +void _PR_ImplicitInitialization(void) +{ + _PR_InitStuff(); + + /* Enable interrupts */ +#if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY) + _PR_MD_START_INTERRUPTS(); +#endif + +} + +PR_IMPLEMENT(void) PR_DisableClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + if (!_pr_initialized) { + _PR_InitStuff(); + } else { + _PR_MD_DISABLE_CLOCK_INTERRUPTS(); + } +#endif +} + +PR_IMPLEMENT(void) PR_EnableClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + if (!_pr_initialized) { + _PR_InitStuff(); + } + _PR_MD_ENABLE_CLOCK_INTERRUPTS(); +#endif +} + +PR_IMPLEMENT(void) PR_BlockClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + _PR_MD_BLOCK_CLOCK_INTERRUPTS(); +#endif +} + +PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(); +#endif +} + +PR_IMPLEMENT(void) PR_Init( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) +{ +#if defined(XP_MAC) +#pragma unused (type, priority, maxPTDs) +#endif + + _PR_ImplicitInitialization(); +} + +PR_IMPLEMENT(PRIntn) PR_Initialize( + PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs) +{ +#if defined(XP_MAC) +#pragma unused (maxPTDs) +#endif + + PRIntn rv; + _PR_ImplicitInitialization(); + rv = prmain(argc, argv); + PR_Cleanup(); + return rv; +} /* PR_Initialize */ + +/* + *----------------------------------------------------------------------- + * + * _PR_CleanupBeforeExit -- + * + * Perform the cleanup work before exiting the process. + * We first do the cleanup generic to all platforms. Then + * we call _PR_MD_CLEANUP_BEFORE_EXIT(), where platform-dependent + * cleanup is done. This function is used by PR_Cleanup(). + * + * See also: PR_Cleanup(). + * + *----------------------------------------------------------------------- + */ +#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) + /* see ptthread.c */ +#else +static void +_PR_CleanupBeforeExit(void) +{ +/* +Do not make any calls here other than to destroy resources. For example, +do not make any calls that eventually may end up in PR_Lock. Because the +thread is destroyed, can not access current thread any more. +*/ + _PR_CleanupTPD(); + if (_pr_terminationCVLock) + /* + * In light of the comment above, this looks real suspicious. + * I'd go so far as to say it's just a problem waiting to happen. + */ + PR_DestroyLock(_pr_terminationCVLock); + + _PR_MD_CLEANUP_BEFORE_EXIT(); +} +#endif /* defined(_PR_PTHREADS) */ + +/* + *---------------------------------------------------------------------- + * + * PR_Cleanup -- + * + * Perform a graceful shutdown of the NSPR runtime. PR_Cleanup() may + * only be called from the primordial thread, typically at the + * end of the main() function. It returns when it has completed + * its platform-dependent duty and the process must not make any other + * NSPR library calls prior to exiting from main(). + * + * PR_Cleanup() first blocks the primordial thread until all the + * other user (non-system) threads, if any, have terminated. + * Then it performs cleanup in preparation for exiting the process. + * PR_Cleanup() does not exit the primordial thread (which would + * in turn exit the process). + * + * PR_Cleanup() only responds when it is called by the primordial + * thread. Calls by any other thread are silently ignored. + * + * See also: PR_ExitProcess() + * + *---------------------------------------------------------------------- + */ +#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) + /* see ptthread.c */ +#else + +PR_IMPLEMENT(PRStatus) PR_Cleanup() +{ + PRThread *me = PR_GetCurrentThread(); + 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")); + + /* + * No more recycling of threads + */ + _pr_recycleThreads = 0; + + /* + * Wait for all other user (non-system/daemon) threads + * to terminate. + */ + PR_Lock(_pr_activeLock); + while (_pr_userActive > _pr_primordialExitCount) { + PR_WaitCondVar(_pr_primordialExitCVar, PR_INTERVAL_NO_TIMEOUT); + } + 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 + + _PR_CleanupMW(); + _PR_CleanupTime(); + _PR_CleanupDtoa(); + _PR_CleanupCallOnce(); + _PR_ShutdownLinker(); + _PR_CleanupNet(); + _PR_CleanupIO(); + /* Release the primordial thread's private data, etc. */ + _PR_CleanupThread(me); + + _PR_MD_STOP_INTERRUPTS(); + + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_Cleanup: clean up before destroying thread")); + _PR_LogCleanup(); + + /* + * This part should look like the end of _PR_NativeRunThread + * and _PR_UserRunThread. + */ + if (_PR_IS_NATIVE_THREAD(me)) { + _PR_MD_EXIT_THREAD(me); + _PR_NativeDestroyThread(me); + } else { + _PR_UserDestroyThread(me); + PR_DELETE(me->stack); + PR_DELETE(me); + } + + /* + * XXX: We are freeing the heap memory here so that Purify won't + * complain, but we should also free other kinds of resources + * that are allocated by the _PR_InitXXX() functions. + * Ideally, for each _PR_InitXXX(), there should be a corresponding + * _PR_XXXCleanup() that we can call here. + */ +#ifdef WINNT + _PR_CleanupCPUs(); +#endif + _PR_CleanupThreads(); + _PR_CleanupCMon(); + PR_DestroyLock(_pr_sleeplock); + _pr_sleeplock = NULL; + _PR_CleanupLayerCache(); + _PR_CleanupEnv(); + _PR_CleanupStacks(); + _PR_CleanupBeforeExit(); + _pr_initialized = PR_FALSE; + return PR_SUCCESS; + } + return PR_FAILURE; +} +#endif /* defined(_PR_PTHREADS) */ + +/* + *------------------------------------------------------------------------ + * PR_ProcessExit -- + * + * Cause an immediate, nongraceful, forced termination of the process. + * It takes a PRIntn argument, which is the exit status code of the + * process. + * + * See also: PR_Cleanup() + * + *------------------------------------------------------------------------ + */ + +#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) + /* see ptthread.c */ +#else +PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status) +{ + _PR_MD_EXIT(status); +} + +#endif /* defined(_PR_PTHREADS) */ + +PR_IMPLEMENT(PRProcessAttr *) +PR_NewProcessAttr(void) +{ + PRProcessAttr *attr; + + attr = PR_NEWZAP(PRProcessAttr); + if (!attr) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return attr; +} + +PR_IMPLEMENT(void) +PR_ResetProcessAttr(PRProcessAttr *attr) +{ + PR_FREEIF(attr->currentDirectory); + PR_FREEIF(attr->fdInheritBuffer); + memset(attr, 0, sizeof(*attr)); +} + +PR_IMPLEMENT(void) +PR_DestroyProcessAttr(PRProcessAttr *attr) +{ + PR_FREEIF(attr->currentDirectory); + PR_FREEIF(attr->fdInheritBuffer); + PR_DELETE(attr); +} + +PR_IMPLEMENT(void) +PR_ProcessAttrSetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd) +{ + switch (stdioFd) { + case PR_StandardInput: + attr->stdinFd = redirectFd; + break; + case PR_StandardOutput: + attr->stdoutFd = redirectFd; + break; + case PR_StandardError: + attr->stderrFd = redirectFd; + break; + default: + PR_ASSERT(0); + } +} + +/* + * OBSOLETE + */ +PR_IMPLEMENT(void) +PR_SetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd) +{ +#if defined(DEBUG) + static PRBool warn = PR_TRUE; + if (warn) { + warn = _PR_Obsolete("PR_SetStdioRedirect()", + "PR_ProcessAttrSetStdioRedirect()"); + } +#endif + PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd); +} + +PR_IMPLEMENT(PRStatus) +PR_ProcessAttrSetCurrentDirectory( + PRProcessAttr *attr, + const char *dir) +{ + PR_FREEIF(attr->currentDirectory); + attr->currentDirectory = (char *) PR_MALLOC(strlen(dir) + 1); + if (!attr->currentDirectory) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_FAILURE; + } + strcpy(attr->currentDirectory, dir); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) +PR_ProcessAttrSetInheritableFD( + PRProcessAttr *attr, + PRFileDesc *fd, + const char *name) +{ + /* We malloc the fd inherit buffer in multiples of this number. */ +#define FD_INHERIT_BUFFER_INCR 128 + /* The length of "NSPR_INHERIT_FDS=" */ +#define NSPR_INHERIT_FDS_STRLEN 17 + /* The length of osfd (PROsfd) printed in hexadecimal with 0x prefix */ +#ifdef _WIN64 +#define OSFD_STRLEN 18 +#else +#define OSFD_STRLEN 10 +#endif + /* The length of fd type (PRDescType) printed in decimal */ +#define FD_TYPE_STRLEN 1 + PRSize newSize; + int remainder; + char *newBuffer; + int nwritten; + char *cur; + int freeSize; + + if (fd->identity != PR_NSPR_IO_LAYER) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + if (fd->secret->inheritable == _PR_TRI_UNKNOWN) { + _PR_MD_QUERY_FD_INHERITABLE(fd); + } + if (fd->secret->inheritable != _PR_TRI_TRUE) { + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); + return PR_FAILURE; + } + + /* + * We also need to account for the : separators and the + * terminating null byte. + */ + if (NULL == attr->fdInheritBuffer) { + /* The first time, we print "NSPR_INHERIT_FDS=::" */ + newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name) + + FD_TYPE_STRLEN + OSFD_STRLEN + 2 + 1; + } else { + /* At other times, we print ":::" */ + newSize = attr->fdInheritBufferUsed + strlen(name) + + FD_TYPE_STRLEN + OSFD_STRLEN + 3 + 1; + } + if (newSize > attr->fdInheritBufferSize) { + /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */ + remainder = newSize % FD_INHERIT_BUFFER_INCR; + if (remainder != 0) { + newSize += (FD_INHERIT_BUFFER_INCR - remainder); + } + if (NULL == attr->fdInheritBuffer) { + newBuffer = (char *) PR_MALLOC(newSize); + } else { + newBuffer = (char *) PR_REALLOC(attr->fdInheritBuffer, newSize); + } + if (NULL == newBuffer) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_FAILURE; + } + attr->fdInheritBuffer = newBuffer; + attr->fdInheritBufferSize = newSize; + } + cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed; + freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed; + if (0 == attr->fdInheritBufferUsed) { + nwritten = PR_snprintf(cur, freeSize, + "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD, + name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); + } else { + nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%" PR_PRIxOSFD, + name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); + } + attr->fdInheritBufferUsed += nwritten; + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRFileDesc *) PR_GetInheritedFD( + const char *name) +{ + PRFileDesc *fd; + const char *envVar; + const char *ptr; + int len = strlen(name); + PROsfd osfd; + int nColons; + PRIntn fileType; + + envVar = PR_GetEnv("NSPR_INHERIT_FDS"); + if (NULL == envVar || '\0' == envVar[0]) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return NULL; + } + + ptr = envVar; + while (1) { + if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) { + ptr += len + 1; + PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd); + switch ((PRDescType)fileType) { + case PR_DESC_FILE: + fd = PR_ImportFile(osfd); + break; + case PR_DESC_PIPE: + fd = PR_ImportPipe(osfd); + break; + case PR_DESC_SOCKET_TCP: + fd = PR_ImportTCPSocket(osfd); + break; + case PR_DESC_SOCKET_UDP: + fd = PR_ImportUDPSocket(osfd); + break; + default: + PR_ASSERT(0); + PR_SetError(PR_UNKNOWN_ERROR, 0); + fd = NULL; + break; + } + if (fd) { + /* + * An inherited FD is inheritable by default. + * The child process needs to call PR_SetFDInheritable + * to make it non-inheritable if so desired. + */ + fd->secret->inheritable = _PR_TRI_TRUE; + } + return fd; + } + /* Skip three colons */ + nColons = 0; + while (*ptr) { + if (*ptr == ':') { + if (++nColons == 3) { + break; + } + } + ptr++; + } + if (*ptr == '\0') { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return NULL; + } + ptr++; + } +} + +PR_IMPLEMENT(PRProcess*) PR_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + return _PR_MD_CREATE_PROCESS(path, argv, envp, attr); +} /* PR_CreateProcess */ + +PR_IMPLEMENT(PRStatus) PR_CreateProcessDetached( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + PRProcess *process; + PRStatus rv; + + process = PR_CreateProcess(path, argv, envp, attr); + if (NULL == process) { + return PR_FAILURE; + } + rv = PR_DetachProcess(process); + PR_ASSERT(PR_SUCCESS == rv); + if (rv == PR_FAILURE) { + PR_DELETE(process); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess *process) +{ + return _PR_MD_DETACH_PROCESS(process); +} + +PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode) +{ + return _PR_MD_WAIT_PROCESS(process, exitCode); +} /* PR_WaitProcess */ + +PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess *process) +{ + return _PR_MD_KILL_PROCESS(process); +} + +/* + ******************************************************************** + * + * Module initialization + * + ******************************************************************** + */ + +static struct { + PRLock *ml; + PRCondVar *cv; +} mod_init; + +static void _PR_InitCallOnce(void) { + mod_init.ml = PR_NewLock(); + PR_ASSERT(NULL != mod_init.ml); + mod_init.cv = PR_NewCondVar(mod_init.ml); + PR_ASSERT(NULL != mod_init.cv); +} + +void _PR_CleanupCallOnce() +{ + PR_DestroyLock(mod_init.ml); + mod_init.ml = NULL; + PR_DestroyCondVar(mod_init.cv); + mod_init.cv = NULL; +} + +PR_IMPLEMENT(PRStatus) PR_CallOnce( + PRCallOnceType *once, + PRCallOnceFN func) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (!once->initialized) { + if (PR_AtomicSet(&once->inProgress, 1) == 0) { + once->status = (*func)(); + PR_Lock(mod_init.ml); + once->initialized = 1; + PR_NotifyAllCondVar(mod_init.cv); + PR_Unlock(mod_init.ml); + } else { + PR_Lock(mod_init.ml); + while (!once->initialized) { + PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(mod_init.ml); + } + } else { + if (PR_SUCCESS != once->status) { + PR_SetError(PR_CALL_ONCE_ERROR, 0); + } + } + return once->status; +} + +PR_IMPLEMENT(PRStatus) PR_CallOnceWithArg( + PRCallOnceType *once, + PRCallOnceWithArgFN func, + void *arg) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (!once->initialized) { + if (PR_AtomicSet(&once->inProgress, 1) == 0) { + once->status = (*func)(arg); + PR_Lock(mod_init.ml); + once->initialized = 1; + PR_NotifyAllCondVar(mod_init.cv); + PR_Unlock(mod_init.ml); + } else { + PR_Lock(mod_init.ml); + while (!once->initialized) { + PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(mod_init.ml); + } + } else { + if (PR_SUCCESS != once->status) { + PR_SetError(PR_CALL_ONCE_ERROR, 0); + } + } + return once->status; +} + +PRBool _PR_Obsolete(const char *obsolete, const char *preferred) +{ +#if defined(DEBUG) +#ifndef XP_MAC + PR_fprintf( + PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n", + obsolete, (NULL == preferred) ? "something else" : preferred); +#else +#pragma unused (obsolete, preferred) +#endif +#endif + return PR_FALSE; +} /* _PR_Obsolete */ + +/* prinit.c */ + + diff --git a/nsprpub/pr/src/misc/prinrval.c b/nsprpub/pr/src/misc/prinrval.c new file mode 100644 index 00000000000..17229e80fa9 --- /dev/null +++ b/nsprpub/pr/src/misc/prinrval.c @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * file: prinrval.c + * description: implementation for the kernel interval timing functions + */ + +#include "primpl.h" + +/* + *----------------------------------------------------------------------- + * + * _PR_InitClock -- + * + * + *----------------------------------------------------------------------- + */ + +void _PR_InitClock(void) +{ + _PR_MD_INTERVAL_INIT(); +#ifdef DEBUG + { + PRIntervalTime ticksPerSec = PR_TicksPerSecond(); + + PR_ASSERT(ticksPerSec >= PR_INTERVAL_MIN); + PR_ASSERT(ticksPerSec <= PR_INTERVAL_MAX); + } +#endif /* DEBUG */ +} + +/* + * This version of interval times is based on the time of day + * capability offered by system. This isn't valid for two reasons: + * 1) The time of day is neither linear nor montonically increasing + * 2) The units here are milliseconds. That's not appropriate for our use. + */ + +PR_IMPLEMENT(PRIntervalTime) PR_IntervalNow(void) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return _PR_MD_GET_INTERVAL(); +} /* PR_IntervalNow */ + +PR_EXTERN(PRUint32) PR_TicksPerSecond(void) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return _PR_MD_INTERVAL_PER_SEC(); +} /* PR_TicksPerSecond */ + +PR_IMPLEMENT(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds) +{ + return seconds * PR_TicksPerSecond(); +} /* PR_SecondsToInterval */ + +PR_IMPLEMENT(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli) +{ + PRIntervalTime ticks; + PRUint64 tock, tps, msecPerSec, rounding; + LL_UI2L(tock, milli); + LL_I2L(msecPerSec, PR_MSEC_PER_SEC); + LL_I2L(rounding, (PR_MSEC_PER_SEC >> 1)); + LL_I2L(tps, PR_TicksPerSecond()); + LL_MUL(tock, tock, tps); + LL_ADD(tock, tock, rounding); + LL_DIV(tock, tock, msecPerSec); + LL_L2UI(ticks, tock); + return ticks; +} /* PR_MillisecondsToInterval */ + +PR_IMPLEMENT(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro) +{ + PRIntervalTime ticks; + PRUint64 tock, tps, usecPerSec, rounding; + LL_UI2L(tock, micro); + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_I2L(rounding, (PR_USEC_PER_SEC >> 1)); + LL_I2L(tps, PR_TicksPerSecond()); + LL_MUL(tock, tock, tps); + LL_ADD(tock, tock, rounding); + LL_DIV(tock, tock, usecPerSec); + LL_L2UI(ticks, tock); + return ticks; +} /* PR_MicrosecondsToInterval */ + +PR_IMPLEMENT(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks) +{ + return ticks / PR_TicksPerSecond(); +} /* PR_IntervalToSeconds */ + +PR_IMPLEMENT(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks) +{ + PRUint32 milli; + PRUint64 tock, tps, msecPerSec, rounding; + LL_UI2L(tock, ticks); + LL_I2L(msecPerSec, PR_MSEC_PER_SEC); + LL_I2L(tps, PR_TicksPerSecond()); + LL_USHR(rounding, tps, 1); + LL_MUL(tock, tock, msecPerSec); + LL_ADD(tock, tock, rounding); + LL_DIV(tock, tock, tps); + LL_L2UI(milli, tock); + return milli; +} /* PR_IntervalToMilliseconds */ + +PR_IMPLEMENT(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks) +{ + PRUint32 micro; + PRUint64 tock, tps, usecPerSec, rounding; + LL_UI2L(tock, ticks); + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_I2L(tps, PR_TicksPerSecond()); + LL_USHR(rounding, tps, 1); + LL_MUL(tock, tock, usecPerSec); + LL_ADD(tock, tock, rounding); + LL_DIV(tock, tock, tps); + LL_L2UI(micro, tock); + return micro; +} /* PR_IntervalToMicroseconds */ + +/* prinrval.c */ + diff --git a/nsprpub/pr/src/misc/pripc.c b/nsprpub/pr/src/misc/pripc.c new file mode 100644 index 00000000000..cb16aad9164 --- /dev/null +++ b/nsprpub/pr/src/misc/pripc.c @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: pripc.c + * + * Description: functions for IPC support + */ + +#include "primpl.h" + +#include + +/* + * A POSIX IPC name must begin with a '/'. + * A POSIX IPC name on Solaris cannot contain any '/' except + * the required leading '/'. + * A POSIX IPC name on HP-UX and OSF1 must be a valid pathname + * in the file system. + * + * The ftok() function for System V IPC requires a valid pathname + * in the file system. + * + * A Win32 IPC name cannot contain '\'. + */ + +static void _pr_ConvertSemName(char *result) +{ +#ifdef _PR_HAVE_POSIX_SEMAPHORES +#if defined(SOLARIS) + char *p; + + /* Convert '/' to '_' except for the leading '/' */ + for (p = result+1; *p; p++) { + if (*p == '/') { + *p = '_'; + } + } + return; +#else + return; +#endif +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) + return; +#elif defined(WIN32) + return; +#endif +} + +static void _pr_ConvertShmName(char *result) +{ +#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY) +#if defined(SOLARIS) + char *p; + + /* Convert '/' to '_' except for the leading '/' */ + for (p = result+1; *p; p++) { + if (*p == '/') { + *p = '_'; + } + } + return; +#else + return; +#endif +#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY) + return; +#elif defined(WIN32) + return; +#else + return; +#endif +} + +PRStatus _PR_MakeNativeIPCName( + const char *name, + char *result, + PRIntn size, + _PRIPCType type) +{ + if (strlen(name) >= (PRSize)size) { + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); + return PR_FAILURE; + } + strcpy(result, name); + switch (type) { + case _PRIPCSem: + _pr_ConvertSemName(result); + break; + case _PRIPCShm: + _pr_ConvertShmName(result); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + return PR_SUCCESS; +} diff --git a/nsprpub/pr/src/misc/pripcsem.c b/nsprpub/pr/src/misc/pripcsem.c new file mode 100644 index 00000000000..c6c59ec9f36 --- /dev/null +++ b/nsprpub/pr/src/misc/pripcsem.c @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: pripcsem.c + * + * Description: implements the named semaphores API in prsemipc.h + * for classic NSPR. If _PR_HAVE_NAMED_SEMAPHORES is not defined, + * the named semaphore functions all fail with the error code + * PR_NOT_IMPLEMENTED_ERROR. + */ + +#include "primpl.h" + +#ifdef _PR_PTHREADS + +#error "This file should not be compiled for the pthreads version" + +#else + +#ifndef _PR_HAVE_NAMED_SEMAPHORES + +PRSem * _PR_MD_OPEN_SEMAPHORE( + const char *osname, PRIntn flags, PRIntn mode, PRUintn value) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +#endif /* !_PR_HAVE_NAMED_SEMAPHORES */ + +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( + const char *name, PRIntn flags, PRIntn mode, PRUintn value) +{ + char osname[PR_IPC_NAME_SIZE]; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) { + return NULL; + } + return _PR_MD_OPEN_SEMAPHORE(osname, flags, mode, value); +} + +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) +{ + return _PR_MD_WAIT_SEMAPHORE(sem); +} + +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) +{ + return _PR_MD_POST_SEMAPHORE(sem); +} + +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) +{ + return _PR_MD_CLOSE_SEMAPHORE(sem); +} + +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) +{ + char osname[PR_IPC_NAME_SIZE]; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) { + return PR_FAILURE; + } + return _PR_MD_DELETE_SEMAPHORE(osname); +} + +#endif /* _PR_PTHREADS */ diff --git a/nsprpub/pr/src/misc/prlog2.c b/nsprpub/pr/src/misc/prlog2.c new file mode 100644 index 00000000000..d1a688ad70c --- /dev/null +++ b/nsprpub/pr/src/misc/prlog2.c @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prbit.h" + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +PR_IMPLEMENT(PRIntn) PR_CeilingLog2(PRUint32 n) +{ + PRIntn log2 = 0; + + if (n & (n-1)) + log2++; + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; +} + +/* +** Compute the log of the greatest power of 2 less than or equal to n. +** This really just finds the highest set bit in the word. +*/ +PR_IMPLEMENT(PRIntn) PR_FloorLog2(PRUint32 n) +{ + PRIntn log2 = 0; + + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; +} diff --git a/nsprpub/pr/src/misc/prlong.c b/nsprpub/pr/src/misc/prlong.c new file mode 100644 index 00000000000..ad1c2a0daed --- /dev/null +++ b/nsprpub/pr/src/misc/prlong.c @@ -0,0 +1,282 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +static PRInt64 ll_zero = LL_INIT( 0x00000000,0x00000000 ); +static PRInt64 ll_maxint = LL_INIT( 0x7fffffff, 0xffffffff ); +static PRInt64 ll_minint = LL_INIT( 0x80000000, 0x00000000 ); +static PRUint64 ll_maxuint = LL_INIT( 0xffffffff, 0xffffffff ); + +#if defined(HAVE_WATCOM_BUG_2) +PRInt64 __pascal __loadds __export + LL_Zero(void) { return ll_zero; } +PRInt64 __pascal __loadds __export + LL_MaxInt(void) { return ll_maxint; } +PRInt64 __pascal __loadds __export + LL_MinInt(void) { return ll_minint; } +PRUint64 __pascal __loadds __export + LL_MaxUint(void) { return ll_maxuint; } +#else +PR_IMPLEMENT(PRInt64) LL_Zero(void) { return ll_zero; } +PR_IMPLEMENT(PRInt64) LL_MaxInt(void) { return ll_maxint; } +PR_IMPLEMENT(PRInt64) LL_MinInt(void) { return ll_minint; } +PR_IMPLEMENT(PRUint64) LL_MaxUint(void) { return ll_maxuint; } +#endif + +#ifndef HAVE_LONG_LONG +/* +** Divide 64-bit a by 32-bit b, which must be normalized so its high bit is 1. +*/ +static void norm_udivmod32(PRUint32 *qp, PRUint32 *rp, PRUint64 a, PRUint32 b) +{ + PRUint32 d1, d0, q1, q0; + PRUint32 r1, r0, m; + + d1 = _hi16(b); + d0 = _lo16(b); + r1 = a.hi % d1; + q1 = a.hi / d1; + m = q1 * d0; + r1 = (r1 << 16) | _hi16(a.lo); + if (r1 < m) { + q1--, r1 += b; + if (r1 >= b /* i.e., we didn't get a carry when adding to r1 */ + && r1 < m) { + q1--, r1 += b; + } + } + r1 -= m; + r0 = r1 % d1; + q0 = r1 / d1; + m = q0 * d0; + r0 = (r0 << 16) | _lo16(a.lo); + if (r0 < m) { + q0--, r0 += b; + if (r0 >= b + && r0 < m) { + q0--, r0 += b; + } + } + *qp = (q1 << 16) | q0; + *rp = r0 - m; +} + +static PRUint32 CountLeadingZeros(PRUint32 a) +{ + PRUint32 t; + PRUint32 r = 32; + + if ((t = a >> 16) != 0) + r -= 16, a = t; + if ((t = a >> 8) != 0) + r -= 8, a = t; + if ((t = a >> 4) != 0) + r -= 4, a = t; + if ((t = a >> 2) != 0) + r -= 2, a = t; + if ((t = a >> 1) != 0) + r -= 1, a = t; + if (a & 1) + r--; + return r; +} + +PR_IMPLEMENT(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b) +{ + PRUint32 n0, n1, n2; + PRUint32 q0, q1; + PRUint32 rsh, lsh; + + n0 = a.lo; + n1 = a.hi; + + if (b.hi == 0) { + if (b.lo > n1) { + /* (0 q0) = (n1 n0) / (0 D0) */ + + lsh = CountLeadingZeros(b.lo); + + if (lsh) { + /* + * Normalize, i.e. make the most significant bit of the + * denominator be set. + */ + b.lo = b.lo << lsh; + n1 = (n1 << lsh) | (n0 >> (32 - lsh)); + n0 = n0 << lsh; + } + + a.lo = n0, a.hi = n1; + norm_udivmod32(&q0, &n0, a, b.lo); + q1 = 0; + + /* remainder is in n0 >> lsh */ + } else { + /* (q1 q0) = (n1 n0) / (0 d0) */ + + if (b.lo == 0) /* user wants to divide by zero! */ + b.lo = 1 / b.lo; /* so go ahead and crash */ + + lsh = CountLeadingZeros(b.lo); + + if (lsh == 0) { + /* + * From (n1 >= b.lo) + * && (the most significant bit of b.lo is set), + * conclude that + * (the most significant bit of n1 is set) + * && (the leading quotient digit q1 = 1). + * + * This special case is necessary, not an optimization + * (Shifts counts of 32 are undefined). + */ + n1 -= b.lo; + q1 = 1; + } else { + /* + * Normalize. + */ + rsh = 32 - lsh; + + b.lo = b.lo << lsh; + n2 = n1 >> rsh; + n1 = (n1 << lsh) | (n0 >> rsh); + n0 = n0 << lsh; + + a.lo = n1, a.hi = n2; + norm_udivmod32(&q1, &n1, a, b.lo); + } + + /* n1 != b.lo... */ + + a.lo = n0, a.hi = n1; + norm_udivmod32(&q0, &n0, a, b.lo); + + /* remainder in n0 >> lsh */ + } + + if (rp) { + rp->lo = n0 >> lsh; + rp->hi = 0; + } + } else { + if (b.hi > n1) { + /* (0 0) = (n1 n0) / (D1 d0) */ + + q0 = 0; + q1 = 0; + + /* remainder in (n1 n0) */ + if (rp) { + rp->lo = n0; + rp->hi = n1; + } + } else { + /* (0 q0) = (n1 n0) / (d1 d0) */ + + lsh = CountLeadingZeros(b.hi); + if (lsh == 0) { + /* + * From (n1 >= b.hi) + * && (the most significant bit of b.hi is set), + * conclude that + * (the most significant bit of n1 is set) + * && (the quotient digit q0 = 0 or 1). + * + * This special case is necessary, not an optimization. + */ + + /* + * The condition on the next line takes advantage of that + * n1 >= b.hi (true due to control flow). + */ + if (n1 > b.hi || n0 >= b.lo) { + q0 = 1; + a.lo = n0, a.hi = n1; + LL_SUB(a, a, b); + } else { + q0 = 0; + } + q1 = 0; + + if (rp) { + rp->lo = n0; + rp->hi = n1; + } + } else { + PRInt64 m; + + /* + * Normalize. + */ + rsh = 32 - lsh; + + b.hi = (b.hi << lsh) | (b.lo >> rsh); + b.lo = b.lo << lsh; + n2 = n1 >> rsh; + n1 = (n1 << lsh) | (n0 >> rsh); + n0 = n0 << lsh; + + a.lo = n1, a.hi = n2; + norm_udivmod32(&q0, &n1, a, b.hi); + LL_MUL32(m, q0, b.lo); + + if ((m.hi > n1) || ((m.hi == n1) && (m.lo > n0))) { + q0--; + LL_SUB(m, m, b); + } + + q1 = 0; + + /* Remainder is ((n1 n0) - (m1 m0)) >> lsh */ + if (rp) { + a.lo = n0, a.hi = n1; + LL_SUB(a, a, m); + rp->lo = (a.hi << rsh) | (a.lo >> lsh); + rp->hi = a.hi >> lsh; + } + } + } + } + + if (qp) { + qp->lo = q0; + qp->hi = q1; + } +} +#endif /* !HAVE_LONG_LONG */ diff --git a/nsprpub/pr/src/misc/prnetdb.c b/nsprpub/pr/src/misc/prnetdb.c new file mode 100644 index 00000000000..f7588411323 --- /dev/null +++ b/nsprpub/pr/src/misc/prnetdb.c @@ -0,0 +1,2364 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +/* + * On Unix, the error code for gethostbyname() and gethostbyaddr() + * is returned in the global variable h_errno, instead of the usual + * errno. + */ +#if defined(XP_UNIX) +#if defined(_PR_NEED_H_ERRNO) +extern int h_errno; +#endif +#define _MD_GETHOST_ERRNO() h_errno +#else +#define _MD_GETHOST_ERRNO() _MD_ERRNO() +#endif + +/* + * The meaning of the macros related to gethostbyname, gethostbyaddr, + * and gethostbyname2 is defined below. + * - _PR_HAVE_THREADSAFE_GETHOST: the gethostbyXXX functions return + * the result in thread specific storage. For example, AIX, HP-UX, + * and OSF1. + * - _PR_HAVE_GETHOST_R: have the gethostbyXXX_r functions. See next + * two macros. + * - _PR_HAVE_GETHOST_R_INT: the gethostbyXXX_r functions return an + * int. For example, Linux glibc. + * - _PR_HAVE_GETHOST_R_POINTER: the gethostbyXXX_r functions return + * a struct hostent* pointer. For example, Solaris and IRIX. + */ +#if defined(_PR_NO_PREEMPT) || defined(_PR_HAVE_GETHOST_R) \ + || defined(_PR_HAVE_THREADSAFE_GETHOST) +#define _PR_NO_DNS_LOCK +#endif + +#if defined(_PR_NO_DNS_LOCK) +#define LOCK_DNS() +#define UNLOCK_DNS() +#else +PRLock *_pr_dnsLock = NULL; +#define LOCK_DNS() PR_Lock(_pr_dnsLock) +#define UNLOCK_DNS() PR_Unlock(_pr_dnsLock) +#endif /* defined(_PR_NO_DNS_LOCK) */ + +/* + * Some platforms have the reentrant getprotobyname_r() and + * getprotobynumber_r(). However, they come in three flavors. + * Some return a pointer to struct protoent, others return + * an int, and glibc's flavor takes five arguments. + */ +#if defined(XP_BEOS) && defined(BONE_VERSION) +#include /* pick up define for inet_addr */ +#include +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_POINTER +#endif + +#if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT)) \ + || (defined(LINUX) && defined(_REENTRANT) \ + && !(defined(__GLIBC__) && __GLIBC__ >= 2)) +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_POINTER +#endif + +#if defined(OSF1) \ + || defined(AIX4_3_PLUS) || (defined(AIX) && defined(_THREAD_SAFE)) \ + || (defined(HPUX10_10) && defined(_REENTRANT)) \ + || (defined(HPUX10_20) && defined(_REENTRANT)) \ + || defined(OPENBSD) +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_INT +#endif + +#if __FreeBSD_version >= 602000 +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_5_ARG_GETPROTO_R +#endif + +/* BeOS has glibc but not the glibc-style getprotobyxxx_r functions. */ +#if (defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(XP_BEOS)) +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_5_ARG_GETPROTO_R +#endif + +#if !defined(_PR_HAVE_GETPROTO_R) +PRLock* _getproto_lock = NULL; +#endif + +#if defined(_PR_INET6_PROBE) +extern PRBool _pr_ipv6_is_present(void); +#endif + +#define _PR_IN6_IS_ADDR_UNSPECIFIED(a) \ + (((a)->pr_s6_addr32[0] == 0) && \ + ((a)->pr_s6_addr32[1] == 0) && \ + ((a)->pr_s6_addr32[2] == 0) && \ + ((a)->pr_s6_addr32[3] == 0)) + +#define _PR_IN6_IS_ADDR_LOOPBACK(a) \ + (((a)->pr_s6_addr32[0] == 0) && \ + ((a)->pr_s6_addr32[1] == 0) && \ + ((a)->pr_s6_addr32[2] == 0) && \ + ((a)->pr_s6_addr[12] == 0) && \ + ((a)->pr_s6_addr[13] == 0) && \ + ((a)->pr_s6_addr[14] == 0) && \ + ((a)->pr_s6_addr[15] == 0x1U)) + +const PRIPv6Addr _pr_in6addr_any = {{{ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 }}}; + +const PRIPv6Addr _pr_in6addr_loopback = {{{ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0x1U }}}; +/* + * The values at bytes 10 and 11 are compared using pointers to + * 8-bit fields, and not 32-bit fields, to make the comparison work on + * both big-endian and little-endian systems + */ + +#define _PR_IN6_IS_ADDR_V4MAPPED(a) \ + (((a)->pr_s6_addr32[0] == 0) && \ + ((a)->pr_s6_addr32[1] == 0) && \ + ((a)->pr_s6_addr[8] == 0) && \ + ((a)->pr_s6_addr[9] == 0) && \ + ((a)->pr_s6_addr[10] == 0xff) && \ + ((a)->pr_s6_addr[11] == 0xff)) + +#define _PR_IN6_IS_ADDR_V4COMPAT(a) \ + (((a)->pr_s6_addr32[0] == 0) && \ + ((a)->pr_s6_addr32[1] == 0) && \ + ((a)->pr_s6_addr32[2] == 0)) + +#define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->pr_s6_addr32[3]) + +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + +/* + * The _pr_QueryNetIfs() function finds out if the system has + * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if + * and _pr_have_inet6_if accordingly. + * + * We have an implementation using SIOCGIFCONF ioctl and a + * default implementation that simply sets _pr_have_inet_if + * and _pr_have_inet6_if to true. A better implementation + * would be to use the routing sockets (see Chapter 17 of + * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.) + */ + +static PRLock *_pr_query_ifs_lock = NULL; +static PRBool _pr_have_inet_if = PR_FALSE; +static PRBool _pr_have_inet6_if = PR_FALSE; + +#undef DEBUG_QUERY_IFS + +#if defined(AIX) \ + || (defined(DARWIN) && (!defined(HAVE_GETIFADDRS) \ + || (defined(XP_MACOSX) && (!defined(MAC_OS_X_VERSION_10_2) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2)))) + +/* + * Use SIOCGIFCONF ioctl on platforms that don't have routing + * sockets. Warning: whether SIOCGIFCONF ioctl returns AF_INET6 + * network interfaces is not portable. + * + * The _pr_QueryNetIfs() function is derived from the code in + * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in + * Section 16.6 of W. Richard Stevens' Unix Network Programming, + * Vol. 1, 2nd. Ed. + */ + +#include +#include +#include +#include + +#ifdef DEBUG_QUERY_IFS +static void +_pr_PrintIfreq(struct ifreq *ifr) +{ + PRNetAddr addr; + struct sockaddr *sa; + const char* family; + char addrstr[64]; + + sa = &ifr->ifr_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + family = "inet"; + memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr)); + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + family = "inet6"; + memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); + } else { + return; /* skip if not AF_INET or AF_INET6 */ + } + addr.raw.family = sa->sa_family; + PR_NetAddrToString(&addr, addrstr, sizeof(addrstr)); + printf("%s: %s %s\n", ifr->ifr_name, family, addrstr); +} +#endif + +static void +_pr_QueryNetIfs(void) +{ + int sock; + int rv; + struct ifconf ifc; + struct ifreq *ifr; + struct ifreq *lifr; + PRUint32 len, lastlen; + char *buf; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + return; + } + + /* Issue SIOCGIFCONF request in a loop. */ + lastlen = 0; + len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ + for (;;) { + buf = (char *)PR_Malloc(len); + if (NULL == buf) { + close(sock); + return; + } + ifc.ifc_buf = buf; + ifc.ifc_len = len; + rv = ioctl(sock, SIOCGIFCONF, &ifc); + if (rv < 0) { + if (errno != EINVAL || lastlen != 0) { + close(sock); + PR_Free(buf); + return; + } + } else { + if (ifc.ifc_len == lastlen) + break; /* success, len has not changed */ + lastlen = ifc.ifc_len; + } + len += 10 * sizeof(struct ifreq); /* increment */ + PR_Free(buf); + } + close(sock); + + ifr = ifc.ifc_req; + lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; + + while (ifr < lifr) { + struct sockaddr *sa; + int sa_len; + +#ifdef DEBUG_QUERY_IFS + _pr_PrintIfreq(ifr); +#endif + sa = &ifr->ifr_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + _pr_have_inet_if = PR_TRUE; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + _pr_have_inet6_if = PR_TRUE; + } + } + +#ifdef _PR_HAVE_SOCKADDR_LEN + sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr)); +#else + switch (sa->sa_family) { +#ifdef AF_LINK + case AF_LINK: + sa_len = sizeof(struct sockaddr_dl); + break; +#endif + case AF_INET6: + sa_len = sizeof(struct sockaddr_in6); + break; + default: + sa_len = sizeof(struct sockaddr); + break; + } +#endif + ifr = (struct ifreq *)(((char *)sa) + sa_len); + } + PR_Free(buf); +} + +#elif (defined(DARWIN) && defined(HAVE_GETIFADDRS)) || defined(FREEBSD) \ + || defined(NETBSD) || defined(OPENBSD) + +/* + * Use the BSD getifaddrs function. + */ + +#include +#include +#include +#include + +#ifdef DEBUG_QUERY_IFS +static void +_pr_PrintIfaddrs(struct ifaddrs *ifa) +{ + struct sockaddr *sa; + const char* family; + void *addrp; + char addrstr[64]; + + sa = ifa->ifa_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + family = "inet"; + addrp = &sin->sin_addr; + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + family = "inet6"; + addrp = &sin6->sin6_addr; + } else { + return; /* skip if not AF_INET or AF_INET6 */ + } + inet_ntop(sa->sa_family, addrp, addrstr, sizeof(addrstr)); + printf("%s: %s %s\n", ifa->ifa_name, family, addrstr); +} +#endif + +static void +_pr_QueryNetIfs(void) +{ + struct ifaddrs *ifp; + struct ifaddrs *ifa; + + if (getifaddrs(&ifp) == -1) { + return; + } + for (ifa = ifp; ifa; ifa = ifa->ifa_next) { + struct sockaddr *sa; + +#ifdef DEBUG_QUERY_IFS + _pr_PrintIfaddrs(ifa); +#endif + sa = ifa->ifa_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + _pr_have_inet_if = 1; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + _pr_have_inet6_if = 1; + } + } + } + freeifaddrs(ifp); +} + +#else /* default */ + +/* + * Emulate the code in NSPR 4.2 or older. PR_GetIPNodeByName behaves + * as if the system had both IPv4 and IPv6 source addresses configured. + */ +static void +_pr_QueryNetIfs(void) +{ + _pr_have_inet_if = PR_TRUE; + _pr_have_inet6_if = PR_TRUE; +} + +#endif + +#endif /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */ + +void _PR_InitNet(void) +{ +#if defined(XP_UNIX) +#ifdef HAVE_NETCONFIG + /* + * This one-liner prevents the endless re-open's and re-read's of + * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc. + */ + (void)setnetconfig(); +#endif +#endif +#if !defined(_PR_NO_DNS_LOCK) + _pr_dnsLock = PR_NewLock(); +#endif +#if !defined(_PR_HAVE_GETPROTO_R) + _getproto_lock = PR_NewLock(); +#endif +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + _pr_query_ifs_lock = PR_NewLock(); +#endif +} + +void _PR_CleanupNet(void) +{ +#if !defined(_PR_NO_DNS_LOCK) + if (_pr_dnsLock) { + PR_DestroyLock(_pr_dnsLock); + _pr_dnsLock = NULL; + } +#endif +#if !defined(_PR_HAVE_GETPROTO_R) + if (_getproto_lock) { + PR_DestroyLock(_getproto_lock); + _getproto_lock = NULL; + } +#endif +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + if (_pr_query_ifs_lock) { + PR_DestroyLock(_pr_query_ifs_lock); + _pr_query_ifs_lock = NULL; + } +#endif +} + +/* +** Allocate space from the buffer, aligning it to "align" before doing +** the allocation. "align" must be a power of 2. +*/ +static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align) +{ + char *buf = *bufp; + PRIntn buflen = *buflenp; + + if (align && ((long)buf & (align - 1))) { + PRIntn skip = align - ((ptrdiff_t)buf & (align - 1)); + if (buflen < skip) { + return 0; + } + buf += skip; + buflen -= skip; + } + if (buflen < amount) { + return 0; + } + *bufp = buf + amount; + *buflenp = buflen - amount; + return buf; +} + +typedef enum _PRIPAddrConversion { + _PRIPAddrNoConversion, + _PRIPAddrIPv4Mapped, + _PRIPAddrIPv4Compat +} _PRIPAddrConversion; + +/* +** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6). +*/ +static void MakeIPv4MappedAddr(const char *v4, char *v6) +{ + memset(v6, 0, 10); + memset(v6 + 10, 0xff, 2); + memcpy(v6 + 12, v4, 4); +} + +/* +** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6). +*/ +static void MakeIPv4CompatAddr(const char *v4, char *v6) +{ + memset(v6, 0, 12); + memcpy(v6 + 12, v4, 4); +} + +/* +** Copy a hostent, and all of the memory that it refers to into +** (hopefully) stacked buffers. +*/ +static PRStatus CopyHostent( + struct hostent *from, + char **buf, + PRIntn *bufsize, + _PRIPAddrConversion conversion, + PRHostEnt *to) +{ + PRIntn len, na; + char **ap; + + if (conversion != _PRIPAddrNoConversion + && from->h_addrtype == AF_INET) { + PR_ASSERT(from->h_length == 4); + to->h_addrtype = PR_AF_INET6; + to->h_length = 16; + } else { +#if defined(_PR_INET6) || defined(_PR_INET6_PROBE) + if (AF_INET6 == from->h_addrtype) + to->h_addrtype = PR_AF_INET6; + else +#endif + to->h_addrtype = from->h_addrtype; + to->h_length = from->h_length; + } + + /* Copy the official name */ + if (!from->h_name) return PR_FAILURE; + len = strlen(from->h_name) + 1; + to->h_name = Alloc(len, buf, bufsize, 0); + if (!to->h_name) return PR_FAILURE; + memcpy(to->h_name, from->h_name, len); + + /* Count the aliases, then allocate storage for the pointers */ + if (!from->h_aliases) { + na = 1; + } else { + for (na = 1, ap = from->h_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */ + } + to->h_aliases = (char**)Alloc( + na * sizeof(char*), buf, bufsize, sizeof(char**)); + if (!to->h_aliases) return PR_FAILURE; + + /* Copy the aliases, one at a time */ + if (!from->h_aliases) { + to->h_aliases[0] = 0; + } else { + for (na = 0, ap = from->h_aliases; *ap != 0; na++, ap++) { + len = strlen(*ap) + 1; + to->h_aliases[na] = Alloc(len, buf, bufsize, 0); + if (!to->h_aliases[na]) return PR_FAILURE; + memcpy(to->h_aliases[na], *ap, len); + } + to->h_aliases[na] = 0; + } + + /* Count the addresses, then allocate storage for the pointers */ + for (na = 1, ap = from->h_addr_list; *ap != 0; na++, ap++){;} /* nothing to execute */ + to->h_addr_list = (char**)Alloc( + na * sizeof(char*), buf, bufsize, sizeof(char**)); + if (!to->h_addr_list) return PR_FAILURE; + + /* Copy the addresses, one at a time */ + for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) { + to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0); + if (!to->h_addr_list[na]) return PR_FAILURE; + if (conversion != _PRIPAddrNoConversion + && from->h_addrtype == AF_INET) { + if (conversion == _PRIPAddrIPv4Mapped) { + MakeIPv4MappedAddr(*ap, to->h_addr_list[na]); + } else { + PR_ASSERT(conversion == _PRIPAddrIPv4Compat); + MakeIPv4CompatAddr(*ap, to->h_addr_list[na]); + } + } else { + memcpy(to->h_addr_list[na], *ap, to->h_length); + } + } + to->h_addr_list[na] = 0; + return PR_SUCCESS; +} + +#if !defined(_PR_HAVE_GETPROTO_R) +/* +** Copy a protoent, and all of the memory that it refers to into +** (hopefully) stacked buffers. +*/ +static PRStatus CopyProtoent( + struct protoent *from, char *buf, PRIntn bufsize, PRProtoEnt *to) +{ + PRIntn len, na; + char **ap; + + /* Do the easy stuff */ + to->p_num = from->p_proto; + + /* Copy the official name */ + if (!from->p_name) return PR_FAILURE; + len = strlen(from->p_name) + 1; + to->p_name = Alloc(len, &buf, &bufsize, 0); + if (!to->p_name) return PR_FAILURE; + memcpy(to->p_name, from->p_name, len); + + /* Count the aliases, then allocate storage for the pointers */ + for (na = 1, ap = from->p_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */ + to->p_aliases = (char**)Alloc( + na * sizeof(char*), &buf, &bufsize, sizeof(char**)); + if (!to->p_aliases) return PR_FAILURE; + + /* Copy the aliases, one at a time */ + for (na = 0, ap = from->p_aliases; *ap != 0; na++, ap++) { + len = strlen(*ap) + 1; + to->p_aliases[na] = Alloc(len, &buf, &bufsize, 0); + if (!to->p_aliases[na]) return PR_FAILURE; + memcpy(to->p_aliases[na], *ap, len); + } + to->p_aliases[na] = 0; + + return PR_SUCCESS; +} +#endif /* !defined(_PR_HAVE_GETPROTO_R) */ + +/* + * ################################################################# + * NOTE: tmphe, tmpbuf, bufsize, h, and h_err are local variables + * or arguments of PR_GetHostByName, PR_GetIPNodeByName, and + * PR_GetHostByAddr. DO NOT CHANGE THE NAMES OF THESE LOCAL + * VARIABLES OR ARGUMENTS. + * ################################################################# + */ +#if defined(_PR_HAVE_GETHOST_R_INT) + +#define GETHOSTBYNAME(name) \ + (gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &h_err), h) +#define GETHOSTBYNAME2(name, af) \ + (gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h, &h_err), h) +#define GETHOSTBYADDR(addr, addrlen, af) \ + (gethostbyaddr_r(addr, addrlen, af, \ + &tmphe, tmpbuf, bufsize, &h, &h_err), h) + +#elif defined(_PR_HAVE_GETHOST_R_POINTER) + +#define GETHOSTBYNAME(name) \ + gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h_err) +#define GETHOSTBYNAME2(name, af) \ + gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h_err) +#define GETHOSTBYADDR(addr, addrlen, af) \ + gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize, &h_err) + +#else + +#define GETHOSTBYNAME(name) gethostbyname(name) +#define GETHOSTBYNAME2(name, af) gethostbyname2(name, af) +#define GETHOSTBYADDR(addr, addrlen, af) gethostbyaddr(addr, addrlen, af) + +#endif /* definition of GETHOSTBYXXX */ + +PR_IMPLEMENT(PRStatus) PR_GetHostByName( + const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp) +{ + struct hostent *h; + PRStatus rv = PR_FAILURE; +#if defined(_PR_HAVE_GETHOST_R) + char localbuf[PR_NETDB_BUF_SIZE]; + char *tmpbuf; + struct hostent tmphe; + int h_err; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if defined(_PR_HAVE_GETHOST_R) + tmpbuf = localbuf; + if (bufsize > sizeof(localbuf)) + { + tmpbuf = (char *)PR_Malloc(bufsize); + if (NULL == tmpbuf) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return rv; + } + } +#endif + + LOCK_DNS(); + +#ifdef XP_OS2_VACPP + h = GETHOSTBYNAME((char *)name); +#else + h = GETHOSTBYNAME(name); +#endif + + if (NULL == h) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); + } + else + { + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; + rv = CopyHostent(h, &buf, &bufsize, conversion, hp); + if (PR_SUCCESS != rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } + UNLOCK_DNS(); +#if defined(_PR_HAVE_GETHOST_R) + if (tmpbuf != localbuf) + PR_Free(tmpbuf); +#endif + return rv; +} + +#if !defined(_PR_INET6) && \ + defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) +typedef struct hostent * (*_pr_getipnodebyname_t)(const char *, int, + int, int *); +typedef struct hostent * (*_pr_getipnodebyaddr_t)(const void *, size_t, + int, int *); +typedef void (*_pr_freehostent_t)(struct hostent *); +static void * _pr_getipnodebyname_fp; +static void * _pr_getipnodebyaddr_fp; +static void * _pr_freehostent_fp; + +/* + * Look up the addresses of getipnodebyname, getipnodebyaddr, + * and freehostent. + */ +PRStatus +_pr_find_getipnodebyname(void) +{ + PRLibrary *lib; + PRStatus rv; +#if defined(VMS) +#define GETIPNODEBYNAME getenv("GETIPNODEBYNAME") +#define GETIPNODEBYADDR getenv("GETIPNODEBYADDR") +#define FREEHOSTENT getenv("FREEHOSTENT") +#else +#define GETIPNODEBYNAME "getipnodebyname" +#define GETIPNODEBYADDR "getipnodebyaddr" +#define FREEHOSTENT "freehostent" +#endif + _pr_getipnodebyname_fp = PR_FindSymbolAndLibrary(GETIPNODEBYNAME, &lib); + if (NULL != _pr_getipnodebyname_fp) { + _pr_freehostent_fp = PR_FindSymbol(lib, FREEHOSTENT); + if (NULL != _pr_freehostent_fp) { + _pr_getipnodebyaddr_fp = PR_FindSymbol(lib, GETIPNODEBYADDR); + if (NULL != _pr_getipnodebyaddr_fp) + rv = PR_SUCCESS; + else + rv = PR_FAILURE; + } else + rv = PR_FAILURE; + (void)PR_UnloadLibrary(lib); + } else + rv = PR_FAILURE; + return rv; +} +#endif + +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) +/* +** Append the V4 addresses to the end of the list +*/ +static PRStatus AppendV4AddrsToHostent( + struct hostent *from, + char **buf, + PRIntn *bufsize, + PRHostEnt *to) +{ + PRIntn na, na_old; + char **ap; + char **new_addr_list; + + /* Count the addresses, then grow storage for the pointers */ + for (na_old = 0, ap = to->h_addr_list; *ap != 0; na_old++, ap++) + {;} /* nothing to execute */ + for (na = na_old + 1, ap = from->h_addr_list; *ap != 0; na++, ap++) + {;} /* nothing to execute */ + new_addr_list = (char**)Alloc( + na * sizeof(char*), buf, bufsize, sizeof(char**)); + if (!new_addr_list) return PR_FAILURE; + + /* Copy the V6 addresses, one at a time */ + for (na = 0, ap = to->h_addr_list; *ap != 0; na++, ap++) { + new_addr_list[na] = to->h_addr_list[na]; + } + to->h_addr_list = new_addr_list; + + /* Copy the V4 addresses, one at a time */ + for (ap = from->h_addr_list; *ap != 0; na++, ap++) { + to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0); + if (!to->h_addr_list[na]) return PR_FAILURE; + MakeIPv4MappedAddr(*ap, to->h_addr_list[na]); + } + to->h_addr_list[na] = 0; + return PR_SUCCESS; +} +#endif + +PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName( + const char *name, PRUint16 af, PRIntn flags, + char *buf, PRIntn bufsize, PRHostEnt *hp) +{ + struct hostent *h = 0; + PRStatus rv = PR_FAILURE; +#if defined(_PR_HAVE_GETHOST_R) + char localbuf[PR_NETDB_BUF_SIZE]; + char *tmpbuf; + struct hostent tmphe; + int h_err; +#endif +#if defined(_PR_HAVE_GETIPNODEBYNAME) + PRUint16 md_af = af; + int error_num; + int tmp_flags = 0; +#endif +#if defined(_PR_HAVE_GETHOSTBYNAME2) + PRBool did_af_inet = PR_FALSE; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (af != PR_AF_INET && af != PR_AF_INET6) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + PR_Lock(_pr_query_ifs_lock); + /* + * Keep querying the presence of IPv4 and IPv6 interfaces until + * at least one is up. This allows us to detect the local + * machine going from offline to online. + */ + if (!_pr_have_inet_if && !_pr_have_inet6_if) { + _pr_QueryNetIfs(); +#ifdef DEBUG_QUERY_IFS + if (_pr_have_inet_if) + printf("Have IPv4 source address\n"); + if (_pr_have_inet6_if) + printf("Have IPv6 source address\n"); +#endif + } + PR_Unlock(_pr_query_ifs_lock); +#endif + +#if defined(_PR_HAVE_GETIPNODEBYNAME) + if (flags & PR_AI_V4MAPPED) + tmp_flags |= AI_V4MAPPED; + if (flags & PR_AI_ADDRCONFIG) + tmp_flags |= AI_ADDRCONFIG; + if (flags & PR_AI_ALL) + tmp_flags |= AI_ALL; + if (af == PR_AF_INET6) + md_af = AF_INET6; + else + md_af = af; +#endif + +#if defined(_PR_HAVE_GETHOST_R) + tmpbuf = localbuf; + if (bufsize > sizeof(localbuf)) + { + tmpbuf = (char *)PR_Malloc(bufsize); + if (NULL == tmpbuf) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return rv; + } + } +#endif + + /* Do not need to lock the DNS lock if getipnodebyname() is called */ +#ifdef _PR_INET6 +#ifdef _PR_HAVE_GETHOSTBYNAME2 + LOCK_DNS(); + if (af == PR_AF_INET6) + { + if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet6_if) + { +#ifdef _PR_INET6_PROBE + if (_pr_ipv6_is_present()) +#endif + h = GETHOSTBYNAME2(name, AF_INET6); + } + if ((NULL == h) && (flags & PR_AI_V4MAPPED) + && ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if)) + { + did_af_inet = PR_TRUE; + h = GETHOSTBYNAME2(name, AF_INET); + } + } + else + { + if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if) + { + did_af_inet = PR_TRUE; + h = GETHOSTBYNAME2(name, af); + } + } +#elif defined(_PR_HAVE_GETIPNODEBYNAME) + h = getipnodebyname(name, md_af, tmp_flags, &error_num); +#else +#error "Unknown name-to-address translation function" +#endif /* _PR_HAVE_GETHOSTBYNAME2 */ +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) + if (_pr_ipv6_is_present()) + { +#ifdef PR_GETIPNODE_NOT_THREADSAFE + LOCK_DNS(); +#endif + h = (*((_pr_getipnodebyname_t)_pr_getipnodebyname_fp))(name, md_af, tmp_flags, &error_num); + } + else + { + LOCK_DNS(); + h = GETHOSTBYNAME(name); + } +#else /* _PR_INET6 */ + LOCK_DNS(); +#ifdef XP_OS2_VACPP + h = GETHOSTBYNAME((char *)name); +#else + h = GETHOSTBYNAME(name); +#endif +#endif /* _PR_INET6 */ + + if (NULL == h) + { +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) + if (_pr_ipv6_is_present()) + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); + else + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); +#else + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); +#endif + } + else + { + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; + + if (af == PR_AF_INET6) conversion = _PRIPAddrIPv4Mapped; + rv = CopyHostent(h, &buf, &bufsize, conversion, hp); + if (PR_SUCCESS != rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) + freehostent(h); +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) + if (_pr_ipv6_is_present()) + (*((_pr_freehostent_t)_pr_freehostent_fp))(h); +#endif +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + if ((PR_SUCCESS == rv) && (flags & PR_AI_V4MAPPED) + && ((flags & PR_AI_ALL) + || ((flags & PR_AI_ADDRCONFIG) && _pr_have_inet_if)) + && !did_af_inet && (h = GETHOSTBYNAME2(name, AF_INET)) != 0) { + rv = AppendV4AddrsToHostent(h, &buf, &bufsize, hp); + if (PR_SUCCESS != rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } +#endif + } + + /* Must match the convoluted logic above for LOCK_DNS() */ +#ifdef _PR_INET6 +#ifdef _PR_HAVE_GETHOSTBYNAME2 + UNLOCK_DNS(); +#endif /* _PR_HAVE_GETHOSTBYNAME2 */ +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) +#ifdef PR_GETIPNODE_NOT_THREADSAFE + UNLOCK_DNS(); +#else + if (!_pr_ipv6_is_present()) + UNLOCK_DNS(); +#endif +#else /* _PR_INET6 */ + UNLOCK_DNS(); +#endif /* _PR_INET6 */ + +#if defined(_PR_HAVE_GETHOST_R) + if (tmpbuf != localbuf) + PR_Free(tmpbuf); +#endif + + return rv; +} + +PR_IMPLEMENT(PRStatus) PR_GetHostByAddr( + const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry) +{ + struct hostent *h; + PRStatus rv = PR_FAILURE; + const void *addr; + PRUint32 tmp_ip; + int addrlen; + PRInt32 af; +#if defined(_PR_HAVE_GETHOST_R) + char localbuf[PR_NETDB_BUF_SIZE]; + char *tmpbuf; + struct hostent tmphe; + int h_err; +#endif +#if defined(_PR_HAVE_GETIPNODEBYADDR) + int error_num; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (hostaddr->raw.family == PR_AF_INET6) + { +#if defined(_PR_INET6_PROBE) + af = _pr_ipv6_is_present() ? AF_INET6 : AF_INET; +#elif defined(_PR_INET6) + af = AF_INET6; +#else + af = AF_INET; +#endif +#if defined(_PR_GHBA_DISALLOW_V4MAPPED) + if (_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) + af = AF_INET; +#endif + } + else + { + PR_ASSERT(hostaddr->raw.family == AF_INET); + af = AF_INET; + } + if (hostaddr->raw.family == PR_AF_INET6) { +#if defined(_PR_INET6) || defined(_PR_INET6_PROBE) + if (af == AF_INET6) { + addr = &hostaddr->ipv6.ip; + addrlen = sizeof(hostaddr->ipv6.ip); + } + else +#endif + { + PR_ASSERT(af == AF_INET); + if (!_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return rv; + } + tmp_ip = _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *) + &hostaddr->ipv6.ip); + addr = &tmp_ip; + addrlen = sizeof(tmp_ip); + } + } else { + PR_ASSERT(hostaddr->raw.family == AF_INET); + PR_ASSERT(af == AF_INET); + addr = &hostaddr->inet.ip; + addrlen = sizeof(hostaddr->inet.ip); + } + +#if defined(_PR_HAVE_GETHOST_R) + tmpbuf = localbuf; + if (bufsize > sizeof(localbuf)) + { + tmpbuf = (char *)PR_Malloc(bufsize); + if (NULL == tmpbuf) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return rv; + } + } +#endif + + /* Do not need to lock the DNS lock if getipnodebyaddr() is called */ +#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6) + h = getipnodebyaddr(addr, addrlen, af, &error_num); +#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE) + if (_pr_ipv6_is_present()) + { +#ifdef PR_GETIPNODE_NOT_THREADSAFE + LOCK_DNS(); +#endif + h = (*((_pr_getipnodebyaddr_t)_pr_getipnodebyaddr_fp))(addr, addrlen, + af, &error_num); + } + else + { + LOCK_DNS(); + h = GETHOSTBYADDR(addr, addrlen, af); + } +#else /* _PR_HAVE_GETIPNODEBYADDR */ + LOCK_DNS(); +#ifdef XP_OS2_VACPP + h = GETHOSTBYADDR((char *)addr, addrlen, af); +#else + h = GETHOSTBYADDR(addr, addrlen, af); +#endif +#endif /* _PR_HAVE_GETIPNODEBYADDR */ + if (NULL == h) + { +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR) + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR) + if (_pr_ipv6_is_present()) + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); + else + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); +#else + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); +#endif + } + else + { + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; + if (hostaddr->raw.family == PR_AF_INET6) { + if (af == AF_INET) { + if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr*) + &hostaddr->ipv6.ip)) { + conversion = _PRIPAddrIPv4Mapped; + } else if (_PR_IN6_IS_ADDR_V4COMPAT((PRIPv6Addr *) + &hostaddr->ipv6.ip)) { + conversion = _PRIPAddrIPv4Compat; + } + } + } + rv = CopyHostent(h, &buf, &bufsize, conversion, hostentry); + if (PR_SUCCESS != rv) { + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR) + freehostent(h); +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR) + if (_pr_ipv6_is_present()) + (*((_pr_freehostent_t)_pr_freehostent_fp))(h); +#endif + } + + /* Must match the convoluted logic above for LOCK_DNS() */ +#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6) +#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE) +#ifdef PR_GETIPNODE_NOT_THREADSAFE + UNLOCK_DNS(); +#else + if (!_pr_ipv6_is_present()) + UNLOCK_DNS(); +#endif +#else /* _PR_HAVE_GETIPNODEBYADDR */ + UNLOCK_DNS(); +#endif /* _PR_HAVE_GETIPNODEBYADDR */ + +#if defined(_PR_HAVE_GETHOST_R) + if (tmpbuf != localbuf) + PR_Free(tmpbuf); +#endif + + return rv; +} + +/******************************************************************************/ +/* + * Some systems define a reentrant version of getprotobyname(). Too bad + * the signature isn't always the same. But hey, they tried. If there + * is such a definition, use it. Otherwise, grab a lock and do it here. + */ +/******************************************************************************/ + +#if !defined(_PR_HAVE_GETPROTO_R) +/* + * This may seem like a silly thing to do, but the compiler SHOULD + * complain if getprotobyname_r() is implemented on some system and + * we're not using it. For sure these signatures are different than + * any usable implementation. + */ + +static struct protoent *getprotobyname_r(const char* name) +{ +#ifdef XP_OS2_VACPP + return getprotobyname((char *)name); +#else + return getprotobyname(name); +#endif +} /* getprotobyname_r */ + +static struct protoent *getprotobynumber_r(PRInt32 number) +{ + return getprotobynumber(number); +} /* getprotobynumber_r */ + +#endif /* !defined(_PR_HAVE_GETPROTO_R) */ + +PR_IMPLEMENT(PRStatus) PR_GetProtoByName( + const char* name, char* buffer, PRInt32 buflen, PRProtoEnt* result) +{ + PRStatus rv = PR_SUCCESS; +#if defined(_PR_HAVE_GETPROTO_R) + struct protoent* res = (struct protoent*)result; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if defined(_PR_HAVE_GETPROTO_R_INT) + { + /* + ** The protoent_data has a pointer as the first field. + ** That implies the buffer better be aligned, and char* + ** doesn't promise much. + */ + PRUptrdiff aligned = (PRUptrdiff)buffer; + if (0 != (aligned & (sizeof(struct protoent_data*) - 1))) + { + aligned += sizeof(struct protoent_data*) - 1; + aligned &= ~(sizeof(struct protoent_data*) - 1); + buflen -= (aligned - (PRUptrdiff)buffer); + buffer = (char*)aligned; + } + } +#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */ + + if (PR_NETDB_BUF_SIZE > buflen) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + +#if defined(_PR_HAVE_GETPROTO_R_POINTER) + if (NULL == getprotobyname_r(name, res, buffer, buflen)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#elif defined(_PR_HAVE_GETPROTO_R_INT) + /* + ** The buffer needs to be zero'd, and it should be + ** at least the size of a struct protoent_data. + */ + memset(buffer, 0, buflen); + if (-1 == getprotobyname_r(name, res, (struct protoent_data*)buffer)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#elif defined(_PR_HAVE_5_ARG_GETPROTO_R) + /* The 5th argument for getprotobyname_r() cannot be NULL */ + if (-1 == getprotobyname_r(name, res, buffer, buflen, &res)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#else /* do it the hard way */ + { + struct protoent *staticBuf; + PR_Lock(_getproto_lock); + staticBuf = getprotobyname_r(name); + if (NULL == staticBuf) + { + rv = PR_FAILURE; + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + } + else + { + rv = CopyProtoent(staticBuf, buffer, buflen, result); + if (PR_FAILURE == rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } + PR_Unlock(_getproto_lock); + } +#endif /* all that */ + return rv; +} + +PR_IMPLEMENT(PRStatus) PR_GetProtoByNumber( + PRInt32 number, char* buffer, PRInt32 buflen, PRProtoEnt* result) +{ + PRStatus rv = PR_SUCCESS; +#if defined(_PR_HAVE_GETPROTO_R) + struct protoent* res = (struct protoent*)result; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if defined(_PR_HAVE_GETPROTO_R_INT) + { + /* + ** The protoent_data has a pointer as the first field. + ** That implies the buffer better be aligned, and char* + ** doesn't promise much. + */ + PRUptrdiff aligned = (PRUptrdiff)buffer; + if (0 != (aligned & (sizeof(struct protoent_data*) - 1))) + { + aligned += sizeof(struct protoent_data*) - 1; + aligned &= ~(sizeof(struct protoent_data*) - 1); + buflen -= (aligned - (PRUptrdiff)buffer); + buffer = (char*)aligned; + } + } +#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */ + + if (PR_NETDB_BUF_SIZE > buflen) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + +#if defined(_PR_HAVE_GETPROTO_R_POINTER) + if (NULL == getprotobynumber_r(number, res, buffer, buflen)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + +#elif defined(_PR_HAVE_GETPROTO_R_INT) + /* + ** The buffer needs to be zero'd for these OS's. + */ + memset(buffer, 0, buflen); + if (-1 == getprotobynumber_r(number, res, (struct protoent_data*)buffer)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#elif defined(_PR_HAVE_5_ARG_GETPROTO_R) + /* The 5th argument for getprotobynumber_r() cannot be NULL */ + if (-1 == getprotobynumber_r(number, res, buffer, buflen, &res)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#else /* do it the hard way */ + { + struct protoent *staticBuf; + PR_Lock(_getproto_lock); + staticBuf = getprotobynumber_r(number); + if (NULL == staticBuf) + { + rv = PR_FAILURE; + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + } + else + { + rv = CopyProtoent(staticBuf, buffer, buflen, result); + if (PR_FAILURE == rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } + PR_Unlock(_getproto_lock); + } +#endif /* all that crap */ + return rv; + +} + +PRUintn _PR_NetAddrSize(const PRNetAddr* addr) +{ + PRUintn addrsize; + + /* + * RFC 2553 added a new field (sin6_scope_id) to + * struct sockaddr_in6. PRNetAddr's ipv6 member has a + * scope_id field to match the new field. In order to + * work with older implementations supporting RFC 2133, + * we take the size of struct sockaddr_in6 instead of + * addr->ipv6. + */ + if (AF_INET == addr->raw.family) + addrsize = sizeof(addr->inet); + else if (PR_AF_INET6 == addr->raw.family) +#if defined(_PR_INET6) + addrsize = sizeof(struct sockaddr_in6); +#else + addrsize = sizeof(addr->ipv6); +#endif +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + else if (AF_UNIX == addr->raw.family) + addrsize = sizeof(addr->local); +#endif + else addrsize = 0; + + return addrsize; +} /* _PR_NetAddrSize */ + +PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt( + PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address) +{ + void *addr = hostEnt->h_addr_list[enumIndex++]; + memset(address, 0, sizeof(PRNetAddr)); + if (NULL == addr) enumIndex = 0; + else + { + address->raw.family = hostEnt->h_addrtype; + if (PR_AF_INET6 == hostEnt->h_addrtype) + { + address->ipv6.port = htons(port); + address->ipv6.flowinfo = 0; + address->ipv6.scope_id = 0; + memcpy(&address->ipv6.ip, addr, hostEnt->h_length); + } + else + { + PR_ASSERT(AF_INET == hostEnt->h_addrtype); + address->inet.port = htons(port); + memcpy(&address->inet.ip, addr, hostEnt->h_length); + } + } + return enumIndex; +} /* PR_EnumerateHostEnt */ + +PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr( + PRNetAddrValue val, PRUint16 port, PRNetAddr *addr) +{ + PRStatus rv = PR_SUCCESS; + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet)); + addr->inet.family = AF_INET; + addr->inet.port = htons(port); + switch (val) + { + case PR_IpAddrNull: + break; /* don't overwrite the address */ + case PR_IpAddrAny: + addr->inet.ip = htonl(INADDR_ANY); + break; + case PR_IpAddrLoopback: + addr->inet.ip = htonl(INADDR_LOOPBACK); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + return rv; +} /* PR_InitializeNetAddr */ + +PR_IMPLEMENT(PRStatus) PR_SetNetAddr( + PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr) +{ + PRStatus rv = PR_SUCCESS; + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (af == PR_AF_INET6) + { + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->ipv6)); + addr->ipv6.family = af; + addr->ipv6.port = htons(port); + addr->ipv6.flowinfo = 0; + addr->ipv6.scope_id = 0; + switch (val) + { + case PR_IpAddrNull: + break; /* don't overwrite the address */ + case PR_IpAddrAny: + addr->ipv6.ip = _pr_in6addr_any; + break; + case PR_IpAddrLoopback: + addr->ipv6.ip = _pr_in6addr_loopback; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + } + else + { + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet)); + addr->inet.family = af; + addr->inet.port = htons(port); + switch (val) + { + case PR_IpAddrNull: + break; /* don't overwrite the address */ + case PR_IpAddrAny: + addr->inet.ip = htonl(INADDR_ANY); + break; + case PR_IpAddrLoopback: + addr->inet.ip = htonl(INADDR_LOOPBACK); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + } + return rv; +} /* PR_SetNetAddr */ + +PR_IMPLEMENT(PRBool) +PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val) +{ + if (addr->raw.family == PR_AF_INET6) { + if (val == PR_IpAddrAny) { + if (_PR_IN6_IS_ADDR_UNSPECIFIED((PRIPv6Addr *)&addr->ipv6.ip)) { + return PR_TRUE; + } else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip) + && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip) + == htonl(INADDR_ANY)) { + return PR_TRUE; + } + } else if (val == PR_IpAddrLoopback) { + if (_PR_IN6_IS_ADDR_LOOPBACK((PRIPv6Addr *)&addr->ipv6.ip)) { + return PR_TRUE; + } else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip) + && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip) + == htonl(INADDR_LOOPBACK)) { + return PR_TRUE; + } + } else if (val == PR_IpAddrV4Mapped + && _PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)) { + return PR_TRUE; + } + } else { + if (addr->raw.family == AF_INET) { + if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY)) { + return PR_TRUE; + } else if (val == PR_IpAddrLoopback + && addr->inet.ip == htonl(INADDR_LOOPBACK)) { + return PR_TRUE; + } + } + } + return PR_FALSE; +} + +#ifndef _PR_HAVE_INET_NTOP +#define XX 127 +static const unsigned char index_hex[256] = { + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,XX,XX, XX,XX,XX,XX, + XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, +}; + +/* + * StringToV6Addr() returns 1 if the conversion succeeds, + * or 0 if the input is not a valid IPv6 address string. + * (Same as inet_pton(AF_INET6, string, addr).) + */ +static int StringToV6Addr(const char *string, PRIPv6Addr *addr) +{ + const unsigned char *s = (const unsigned char *)string; + int section = 0; /* index of the current section (a 16-bit + * piece of the address */ + int double_colon = -1; /* index of the section after the first + * 16-bit group of zeros represented by + * the double colon */ + unsigned int val; + int len; + + /* Handle initial (double) colon */ + if (*s == ':') { + if (s[1] != ':') return 0; + s += 2; + addr->pr_s6_addr16[0] = 0; + section = double_colon = 1; + } + + while (*s) { + if (section == 8) return 0; /* too long */ + if (*s == ':') { + if (double_colon != -1) return 0; /* two double colons */ + addr->pr_s6_addr16[section++] = 0; + double_colon = section; + s++; + continue; + } + for (len = val = 0; len < 4 && index_hex[*s] != XX; len++) { + val = (val << 4) + index_hex[*s++]; + } + if (*s == '.') { + if (len == 0) return 0; /* nothing between : and . */ + break; + } + if (*s == ':') { + s++; + if (!*s) return 0; /* cannot end with single colon */ + } else if (*s) { + return 0; /* bad character */ + } + addr->pr_s6_addr16[section++] = htons((unsigned short)val); + } + + if (*s == '.') { + /* Have a trailing v4 format address */ + if (section > 6) return 0; /* not enough room */ + + /* + * The number before the '.' is decimal, but we parsed it + * as hex. That means it is in BCD. Check it for validity + * and convert it to binary. + */ + if (val > 0x0255 || (val & 0xf0) > 0x90 || (val & 0xf) > 9) return 0; + val = (val >> 8) * 100 + ((val >> 4) & 0xf) * 10 + (val & 0xf); + addr->pr_s6_addr[2 * section] = val; + + s++; + val = index_hex[*s++]; + if (val > 9) return 0; + while (*s >= '0' && *s <= '9') { + val = val * 10 + *s++ - '0'; + if (val > 255) return 0; + } + if (*s != '.') return 0; /* must have exactly 4 decimal numbers */ + addr->pr_s6_addr[2 * section + 1] = val; + section++; + + s++; + val = index_hex[*s++]; + if (val > 9) return 0; + while (*s >= '0' && *s <= '9') { + val = val * 10 + *s++ - '0'; + if (val > 255) return 0; + } + if (*s != '.') return 0; /* must have exactly 4 decimal numbers */ + addr->pr_s6_addr[2 * section] = val; + + s++; + val = index_hex[*s++]; + if (val > 9) return 0; + while (*s >= '0' && *s <= '9') { + val = val * 10 + *s++ - '0'; + if (val > 255) return 0; + } + if (*s) return 0; /* must have exactly 4 decimal numbers */ + addr->pr_s6_addr[2 * section + 1] = val; + section++; + } + + if (double_colon != -1) { + /* Stretch the double colon */ + int tosection; + int ncopy = section - double_colon; + for (tosection = 7; ncopy--; tosection--) { + addr->pr_s6_addr16[tosection] = + addr->pr_s6_addr16[double_colon + ncopy]; + } + while (tosection >= double_colon) { + addr->pr_s6_addr16[tosection--] = 0; + } + } else if (section != 8) { + return 0; /* too short */ + } + return 1; +} +#undef XX + +static const char *basis_hex = "0123456789abcdef"; + +/* + * V6AddrToString() returns a pointer to the buffer containing + * the text string if the conversion succeeds, and NULL otherwise. + * (Same as inet_ntop(AF_INET6, addr, buf, size), except that errno + * is not set on failure.) + */ +static const char *V6AddrToString( + const PRIPv6Addr *addr, char *buf, PRUint32 size) +{ +#define STUFF(c) do { \ + if (!size--) return NULL; \ + *buf++ = (c); \ +} while (0) + + int double_colon = -1; /* index of the first 16-bit + * group of zeros represented + * by the double colon */ + int double_colon_length = 1; /* use double colon only if + * there are two or more 16-bit + * groups of zeros */ + int zero_length; + int section; + unsigned int val; + const char *bufcopy = buf; + + /* Scan to find the placement of the double colon */ + for (section = 0; section < 8; section++) { + if (addr->pr_s6_addr16[section] == 0) { + zero_length = 1; + section++; + while (section < 8 && addr->pr_s6_addr16[section] == 0) { + zero_length++; + section++; + } + /* Select the longest sequence of zeros */ + if (zero_length > double_colon_length) { + double_colon = section - zero_length; + double_colon_length = zero_length; + } + } + } + + /* Now start converting to a string */ + section = 0; + + if (double_colon == 0) { + if (double_colon_length == 6 || + (double_colon_length == 5 && addr->pr_s6_addr16[5] == 0xffff)) { + /* ipv4 format address */ + STUFF(':'); + STUFF(':'); + if (double_colon_length == 5) { + STUFF('f'); + STUFF('f'); + STUFF('f'); + STUFF('f'); + STUFF(':'); + } + if (addr->pr_s6_addr[12] > 99) STUFF(addr->pr_s6_addr[12]/100 + '0'); + if (addr->pr_s6_addr[12] > 9) STUFF((addr->pr_s6_addr[12]%100)/10 + '0'); + STUFF(addr->pr_s6_addr[12]%10 + '0'); + STUFF('.'); + if (addr->pr_s6_addr[13] > 99) STUFF(addr->pr_s6_addr[13]/100 + '0'); + if (addr->pr_s6_addr[13] > 9) STUFF((addr->pr_s6_addr[13]%100)/10 + '0'); + STUFF(addr->pr_s6_addr[13]%10 + '0'); + STUFF('.'); + if (addr->pr_s6_addr[14] > 99) STUFF(addr->pr_s6_addr[14]/100 + '0'); + if (addr->pr_s6_addr[14] > 9) STUFF((addr->pr_s6_addr[14]%100)/10 + '0'); + STUFF(addr->pr_s6_addr[14]%10 + '0'); + STUFF('.'); + if (addr->pr_s6_addr[15] > 99) STUFF(addr->pr_s6_addr[15]/100 + '0'); + if (addr->pr_s6_addr[15] > 9) STUFF((addr->pr_s6_addr[15]%100)/10 + '0'); + STUFF(addr->pr_s6_addr[15]%10 + '0'); + STUFF('\0'); + return bufcopy; + } + } + + while (section < 8) { + if (section == double_colon) { + STUFF(':'); + STUFF(':'); + section += double_colon_length; + continue; + } + val = ntohs(addr->pr_s6_addr16[section]); + if (val > 0xfff) { + STUFF(basis_hex[val >> 12]); + } + if (val > 0xff) { + STUFF(basis_hex[(val >> 8) & 0xf]); + } + if (val > 0xf) { + STUFF(basis_hex[(val >> 4) & 0xf]); + } + STUFF(basis_hex[val & 0xf]); + section++; + if (section < 8 && section != double_colon) STUFF(':'); + } + STUFF('\0'); + return bufcopy; +#undef STUFF +} + +#endif /* !_PR_HAVE_INET_NTOP */ + +/* + * Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr + */ +PR_IMPLEMENT(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr) +{ + PRUint8 *dstp; + dstp = v6addr->pr_s6_addr; + memset(dstp, 0, 10); + memset(dstp + 10, 0xff, 2); + memcpy(dstp + 12,(char *) &v4addr, 4); +} + +PR_IMPLEMENT(PRUint16) PR_ntohs(PRUint16 n) { return ntohs(n); } +PR_IMPLEMENT(PRUint32) PR_ntohl(PRUint32 n) { return ntohl(n); } +PR_IMPLEMENT(PRUint16) PR_htons(PRUint16 n) { return htons(n); } +PR_IMPLEMENT(PRUint32) PR_htonl(PRUint32 n) { return htonl(n); } +PR_IMPLEMENT(PRUint64) PR_ntohll(PRUint64 n) +{ +#ifdef IS_BIG_ENDIAN + return n; +#else + PRUint64 tmp; + PRUint32 hi, lo; + LL_L2UI(lo, n); + LL_SHR(tmp, n, 32); + LL_L2UI(hi, tmp); + hi = PR_ntohl(hi); + lo = PR_ntohl(lo); + LL_UI2L(n, lo); + LL_SHL(n, n, 32); + LL_UI2L(tmp, hi); + LL_ADD(n, n, tmp); + return n; +#endif +} /* ntohll */ + +PR_IMPLEMENT(PRUint64) PR_htonll(PRUint64 n) +{ +#ifdef IS_BIG_ENDIAN + return n; +#else + PRUint64 tmp; + PRUint32 hi, lo; + LL_L2UI(lo, n); + LL_SHR(tmp, n, 32); + LL_L2UI(hi, tmp); + hi = htonl(hi); + lo = htonl(lo); + LL_UI2L(n, lo); + LL_SHL(n, n, 32); + LL_UI2L(tmp, hi); + LL_ADD(n, n, tmp); + return n; +#endif +} /* htonll */ + + +/* + * Implementation of PR_GetAddrInfoByName and friends + * + * Compile-time options: + * + * _PR_HAVE_GETADDRINFO Define this macro if the target system provides + * getaddrinfo. With this defined, NSPR will require + * getaddrinfo at run time. If this if not defined, + * then NSPR will attempt to dynamically resolve + * getaddrinfo, falling back to PR_GetHostByName if + * getaddrinfo does not exist on the target system. + * + * Since getaddrinfo is a relatively new system call on many systems, + * we are forced to dynamically resolve it at run time in most cases. + * The exception includes any system (such as Mac OS X) that is known to + * provide getaddrinfo in all versions that NSPR cares to support. + */ + +#if defined(_PR_HAVE_GETADDRINFO) + +#if defined(_PR_INET6) + +typedef struct addrinfo PRADDRINFO; +#define GETADDRINFO getaddrinfo +#define FREEADDRINFO freeaddrinfo +#define GETNAMEINFO getnameinfo + +#elif defined(_PR_INET6_PROBE) + +typedef struct addrinfo PRADDRINFO; + +/* getaddrinfo/freeaddrinfo/getnameinfo prototypes */ +#if defined(WIN32) +#define FUNC_MODIFIER __stdcall +#else +#define FUNC_MODIFIER +#endif +typedef int (FUNC_MODIFIER * FN_GETADDRINFO) + (const char *nodename, + const char *servname, + const PRADDRINFO *hints, + PRADDRINFO **res); +typedef int (FUNC_MODIFIER * FN_FREEADDRINFO) + (PRADDRINFO *ai); +typedef int (FUNC_MODIFIER * FN_GETNAMEINFO) + (const struct sockaddr *addr, int addrlen, + char *host, int hostlen, + char *serv, int servlen, int flags); + +/* global state */ +static FN_GETADDRINFO _pr_getaddrinfo = NULL; +static FN_FREEADDRINFO _pr_freeaddrinfo = NULL; +static FN_GETNAMEINFO _pr_getnameinfo = NULL; + +#if defined(VMS) +#define GETADDRINFO_SYMBOL getenv("GETADDRINFO") +#define FREEADDRINFO_SYMBOL getenv("FREEADDRINFO") +#define GETNAMEINFO_SYMBOL getenv("GETNAMEINFO") +#else +#define GETADDRINFO_SYMBOL "getaddrinfo" +#define FREEADDRINFO_SYMBOL "freeaddrinfo" +#define GETNAMEINFO_SYMBOL "getnameinfo" +#endif + +PRStatus +_pr_find_getaddrinfo(void) +{ + PRLibrary *lib; +#ifdef WIN32 + /* + * On windows, we need to search ws2_32.dll or wship6.dll + * (Microsoft IPv6 Technology Preview for Windows 2000) for + * getaddrinfo and freeaddrinfo. These libraries might not + * be loaded yet. + */ + const char *libname[] = { "ws2_32.dll", "wship6.dll" }; + int i; + + for (i = 0; i < sizeof(libname)/sizeof(libname[0]); i++) { + lib = PR_LoadLibrary(libname[i]); + if (!lib) { + continue; + } + _pr_getaddrinfo = (FN_GETADDRINFO) + PR_FindFunctionSymbol(lib, GETADDRINFO_SYMBOL); + if (!_pr_getaddrinfo) { + PR_UnloadLibrary(lib); + continue; + } + _pr_freeaddrinfo = (FN_FREEADDRINFO) + PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL); + _pr_getnameinfo = (FN_GETNAMEINFO) + PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL); + if (!_pr_freeaddrinfo || !_pr_getnameinfo) { + PR_UnloadLibrary(lib); + continue; + } + /* Keep the library loaded. */ + return PR_SUCCESS; + } + return PR_FAILURE; +#else + /* + * Resolve getaddrinfo by searching all loaded libraries. Then + * search library containing getaddrinfo for freeaddrinfo. + */ + _pr_getaddrinfo = (FN_GETADDRINFO) + PR_FindFunctionSymbolAndLibrary(GETADDRINFO_SYMBOL, &lib); + if (!_pr_getaddrinfo) { + return PR_FAILURE; + } + _pr_freeaddrinfo = (FN_FREEADDRINFO) + PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL); + _pr_getnameinfo = (FN_GETNAMEINFO) + PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL); + PR_UnloadLibrary(lib); + if (!_pr_freeaddrinfo || !_pr_getnameinfo) { + return PR_FAILURE; + } + return PR_SUCCESS; +#endif +} + +#define GETADDRINFO (*_pr_getaddrinfo) +#define FREEADDRINFO (*_pr_freeaddrinfo) +#define GETNAMEINFO (*_pr_getnameinfo) + +#endif /* _PR_INET6 */ + +#endif /* _PR_HAVE_GETADDRINFO */ + +#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE) +/* + * If getaddrinfo does not exist, then we will fall back on + * PR_GetHostByName, which requires that we allocate a buffer for the + * PRHostEnt data structure and its members. + */ +typedef struct PRAddrInfoFB { + char buf[PR_NETDB_BUF_SIZE]; + PRHostEnt hostent; + PRBool has_cname; +} PRAddrInfoFB; + +static PRAddrInfo * +pr_GetAddrInfoByNameFB(const char *hostname, + PRUint16 af, + PRIntn flags) +{ + PRStatus rv; + PRAddrInfoFB *ai; + /* fallback on PR_GetHostByName */ + ai = PR_NEW(PRAddrInfoFB); + if (!ai) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + rv = PR_GetHostByName(hostname, ai->buf, sizeof ai->buf, &ai->hostent); + if (rv == PR_FAILURE) { + PR_Free(ai); + return NULL; + } + ai->has_cname = !(flags & PR_AI_NOCANONNAME); + + return (PRAddrInfo *) ai; +} +#endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */ + +PR_IMPLEMENT(PRAddrInfo *) PR_GetAddrInfoByName(const char *hostname, + PRUint16 af, + PRIntn flags) +{ + /* restrict input to supported values */ + if ((af != PR_AF_INET && af != PR_AF_UNSPEC) || + (flags & ~ PR_AI_NOCANONNAME) != PR_AI_ADDRCONFIG) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if !defined(_PR_HAVE_GETADDRINFO) + return pr_GetAddrInfoByNameFB(hostname, af, flags); +#else +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present()) { + return pr_GetAddrInfoByNameFB(hostname, af, flags); + } +#endif + { + PRADDRINFO *res, hints; + PRStatus rv; + + /* + * we assume a RFC 2553 compliant getaddrinfo. this may at some + * point need to be customized as platforms begin to adopt the + * RFC 3493. + */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = (flags & PR_AI_NOCANONNAME) ? 0: AI_CANONNAME; + hints.ai_family = (af == PR_AF_INET) ? AF_INET : AF_UNSPEC; + + /* + * it is important to select a socket type in the hints, otherwise we + * will get back repetitive entries: one for each socket type. since + * we do not expose ai_socktype through our API, it is okay to do this + * here. the application may still choose to create a socket of some + * other type. + */ + hints.ai_socktype = SOCK_STREAM; + + rv = GETADDRINFO(hostname, NULL, &hints, &res); + if (rv == 0) + return (PRAddrInfo *) res; + + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, rv); + } + return NULL; +#endif +} + +PR_IMPLEMENT(void) PR_FreeAddrInfo(PRAddrInfo *ai) +{ +#if defined(_PR_HAVE_GETADDRINFO) +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present()) + PR_Free((PRAddrInfoFB *) ai); + else +#endif + FREEADDRINFO((PRADDRINFO *) ai); +#else + PR_Free((PRAddrInfoFB *) ai); +#endif +} + +PR_IMPLEMENT(void *) PR_EnumerateAddrInfo(void *iterPtr, + const PRAddrInfo *base, + PRUint16 port, + PRNetAddr *result) +{ +#if defined(_PR_HAVE_GETADDRINFO) + PRADDRINFO *ai; +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present()) { + /* using PRAddrInfoFB */ + PRIntn iter = (PRIntn)(PRPtrdiff) iterPtr; + iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result); + if (iter < 0) + iter = 0; + return (void *)(PRPtrdiff) iter; + } +#endif + + if (iterPtr) + ai = ((PRADDRINFO *) iterPtr)->ai_next; + else + ai = (PRADDRINFO *) base; + + while (ai && ai->ai_addrlen > sizeof(PRNetAddr)) + ai = ai->ai_next; + + if (ai) { + /* copy sockaddr to PRNetAddr */ + memcpy(result, ai->ai_addr, ai->ai_addrlen); + result->raw.family = ai->ai_addr->sa_family; +#ifdef _PR_INET6 + if (AF_INET6 == result->raw.family) + result->raw.family = PR_AF_INET6; +#endif + if (ai->ai_addrlen < sizeof(PRNetAddr)) + memset(((char*)result)+ai->ai_addrlen, 0, sizeof(PRNetAddr) - ai->ai_addrlen); + + if (result->raw.family == PR_AF_INET) + result->inet.port = htons(port); + else + result->ipv6.port = htons(port); + } + + return ai; +#else + /* using PRAddrInfoFB */ + PRIntn iter = (PRIntn) iterPtr; + iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result); + if (iter < 0) + iter = 0; + return (void *) iter; +#endif +} + +PR_IMPLEMENT(const char *) PR_GetCanonNameFromAddrInfo(const PRAddrInfo *ai) +{ +#if defined(_PR_HAVE_GETADDRINFO) +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present()) { + const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai; + return fb->has_cname ? fb->hostent.h_name : NULL; + } +#endif + return ((const PRADDRINFO *) ai)->ai_canonname; +#else + const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai; + return fb->has_cname ? fb->hostent.h_name : NULL; +#endif +} + +#if defined(_PR_HAVE_GETADDRINFO) +static PRStatus pr_StringToNetAddrGAI(const char *string, PRNetAddr *addr) +{ + PRADDRINFO *res, hints; + int rv; /* 0 for success, or the error code EAI_xxx */ + PRNetAddr laddr; + PRStatus status = PR_SUCCESS; + + if (NULL == addr) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + rv = GETADDRINFO(string, NULL, &hints, &res); + if (rv != 0) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv); + return PR_FAILURE; + } + + /* pick up the first addr */ + memcpy(&laddr, res->ai_addr, res->ai_addrlen); + if (AF_INET6 == res->ai_addr->sa_family) + { + addr->ipv6.family = PR_AF_INET6; + addr->ipv6.ip = laddr.ipv6.ip; + addr->ipv6.scope_id = laddr.ipv6.scope_id; + } + else if (AF_INET == res->ai_addr->sa_family) + { + addr->inet.family = PR_AF_INET; + addr->inet.ip = laddr.inet.ip; + } + else + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + status = PR_FAILURE; + } + + FREEADDRINFO(res); + return status; +} +#endif /* _PR_HAVE_GETADDRINFO */ + +#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE) || defined(DARWIN) +static PRStatus pr_StringToNetAddrFB(const char *string, PRNetAddr *addr) +{ + PRStatus status = PR_SUCCESS; + PRIntn rv; + +#if defined(_PR_HAVE_INET_NTOP) + rv = inet_pton(AF_INET6, string, &addr->ipv6.ip); + if (1 == rv) + { + addr->raw.family = PR_AF_INET6; + } + else + { + PR_ASSERT(0 == rv); + /* clean up after the failed inet_pton() call */ + memset(&addr->ipv6.ip, 0, sizeof(addr->ipv6.ip)); + rv = inet_pton(AF_INET, string, &addr->inet.ip); + if (1 == rv) + { + addr->raw.family = AF_INET; + } + else + { + PR_ASSERT(0 == rv); + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + status = PR_FAILURE; + } + } +#else /* _PR_HAVE_INET_NTOP */ + rv = StringToV6Addr(string, &addr->ipv6.ip); + if (1 == rv) { + addr->raw.family = PR_AF_INET6; + return PR_SUCCESS; + } + PR_ASSERT(0 == rv); + /* clean up after the failed StringToV6Addr() call */ + memset(&addr->ipv6.ip, 0, sizeof(addr->ipv6.ip)); + + addr->inet.family = AF_INET; +#ifdef XP_OS2_VACPP + addr->inet.ip = inet_addr((char *)string); +#else + addr->inet.ip = inet_addr(string); +#endif + if ((PRUint32) -1 == addr->inet.ip) + { + /* + * The string argument is a malformed address string. + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + status = PR_FAILURE; + } +#endif /* _PR_HAVE_INET_NTOP */ + + return status; +} +#endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE || DARWIN */ + +PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if !defined(_PR_HAVE_GETADDRINFO) + return pr_StringToNetAddrFB(string, addr); +#else +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present()) + return pr_StringToNetAddrFB(string, addr); +#endif +#if defined(DARWIN) + /* + * On Mac OS X, getaddrinfo with AI_NUMERICHOST is slow. + * So we only use it to convert literal IP addresses that + * contain IPv6 scope IDs, which pr_StringToNetAddrFB + * cannot convert. (See bug 404399.) + */ + if (!strchr(string, '%')) + return pr_StringToNetAddrFB(string, addr); +#endif + return pr_StringToNetAddrGAI(string, addr); +#endif +} + +#if defined(_PR_HAVE_GETADDRINFO) +static PRStatus pr_NetAddrToStringGNI( + const PRNetAddr *addr, char *string, PRUint32 size) +{ + int addrlen; + const PRNetAddr *addrp = addr; +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) + PRUint16 md_af = addr->raw.family; + PRNetAddr addrcopy; +#endif + int rv; /* 0 for success, or the error code EAI_xxx */ + +#ifdef _PR_INET6 + if (addr->raw.family == PR_AF_INET6) + { + md_af = AF_INET6; +#ifndef _PR_HAVE_SOCKADDR_LEN + addrcopy = *addr; + addrcopy.raw.family = AF_INET6; + addrp = &addrcopy; +#endif + } +#endif + + addrlen = PR_NETADDR_SIZE(addr); +#ifdef _PR_HAVE_SOCKADDR_LEN + addrcopy = *addr; + ((struct sockaddr*)&addrcopy)->sa_len = addrlen; + ((struct sockaddr*)&addrcopy)->sa_family = md_af; + addrp = &addrcopy; +#endif + rv = GETNAMEINFO((const struct sockaddr *)addrp, addrlen, + string, size, NULL, 0, NI_NUMERICHOST); + if (rv != 0) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv); + return PR_FAILURE; + } + return PR_SUCCESS; +} +#endif /* _PR_HAVE_GETADDRINFO */ + +#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE) +static PRStatus pr_NetAddrToStringFB( + const PRNetAddr *addr, char *string, PRUint32 size) +{ + if (PR_AF_INET6 == addr->raw.family) + { +#if defined(_PR_HAVE_INET_NTOP) + if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size)) +#else + if (NULL == V6AddrToString(&addr->ipv6.ip, string, size)) +#endif + { + /* the size of the result buffer is inadequate */ + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); + return PR_FAILURE; + } + } + else + { + if (size < 16) goto failed; + if (AF_INET != addr->raw.family) goto failed; + else + { + unsigned char *byte = (unsigned char*)&addr->inet.ip; + PR_snprintf(string, size, "%u.%u.%u.%u", + byte[0], byte[1], byte[2], byte[3]); + } + } + + return PR_SUCCESS; + +failed: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + +} /* pr_NetAddrToStringFB */ +#endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */ + +PR_IMPLEMENT(PRStatus) PR_NetAddrToString( + const PRNetAddr *addr, char *string, PRUint32 size) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if !defined(_PR_HAVE_GETADDRINFO) + return pr_NetAddrToStringFB(addr, string, size); +#else +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present()) + return pr_NetAddrToStringFB(addr, string, size); +#endif + return pr_NetAddrToStringGNI(addr, string, size); +#endif +} /* PR_NetAddrToString */ diff --git a/nsprpub/pr/src/misc/prolock.c b/nsprpub/pr/src/misc/prolock.c new file mode 100644 index 00000000000..f7339bacd72 --- /dev/null +++ b/nsprpub/pr/src/misc/prolock.c @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** prolock.c -- NSPR Ordered Lock +** +** Implement the API defined in prolock.h +** +*/ +#include "prolock.h" +#include "prlog.h" +#include "prerror.h" + +PR_IMPLEMENT(PROrderedLock *) + PR_CreateOrderedLock( + PRInt32 order, + const char *name +) +{ +#ifdef XP_MAC +#pragma unused( order, name ) +#endif + 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 +) +{ +#ifdef XP_MAC +#pragma unused( lock ) +#endif + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); +} /* end PR_DestroyOrderedLock() */ + + +PR_IMPLEMENT(void) + PR_LockOrderedLock( + PROrderedLock *lock +) +{ +#ifdef XP_MAC +#pragma unused( lock ) +#endif + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); +} /* end PR_LockOrderedLock() */ + + +PR_IMPLEMENT(PRStatus) + PR_UnlockOrderedLock( + PROrderedLock *lock +) +{ +#ifdef XP_MAC +#pragma unused( lock ) +#endif + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} /* end PR_UnlockOrderedLock() */ diff --git a/nsprpub/pr/src/misc/prrng.c b/nsprpub/pr/src/misc/prrng.c new file mode 100644 index 00000000000..6cd7e239544 --- /dev/null +++ b/nsprpub/pr/src/misc/prrng.c @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/* + * We were not including in optimized builds. On AIX this + * caused libnspr4.so to export memcpy and some binaries linked with + * libnspr4.so resolved their memcpy references with libnspr4.so. To + * be backward compatible with old libnspr4.so binaries, we do not + * include in optimized builds for AIX. (bug 200561) + */ +#if !(defined(AIX) && !defined(DEBUG)) +#include +#endif + +PRSize _pr_CopyLowBits( + void *dst, + PRSize dstlen, + void *src, + PRSize srclen ) +{ + if (srclen <= dstlen) { + memcpy(dst, src, srclen); + return srclen; + } +#if defined IS_BIG_ENDIAN + memcpy(dst, (char*)src + (srclen - dstlen), dstlen); +#else + memcpy(dst, src, dstlen); +#endif + return dstlen; +} + +PR_IMPLEMENT(PRSize) PR_GetRandomNoise( + void *buf, + PRSize size +) +{ + return( _PR_MD_GET_RANDOM_NOISE( buf, size )); +} /* end PR_GetRandomNoise() */ +/* end prrng.c */ diff --git a/nsprpub/pr/src/misc/prsystem.c b/nsprpub/pr/src/misc/prsystem.c new file mode 100644 index 00000000000..1c6c2825bea --- /dev/null +++ b/nsprpub/pr/src/misc/prsystem.c @@ -0,0 +1,366 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include "prsystem.h" +#include "prprf.h" +#include "prlong.h" + +#if defined(BEOS) +#include +#endif + +#if defined(OS2) +#define INCL_DOS +#define INCL_DOSMISC +#include +/* define the required constant if it is not already defined in the headers */ +#ifndef QSV_NUMPROCESSORS +#define QSV_NUMPROCESSORS 26 +#endif +#endif + +/* BSD-derived systems use sysctl() to get the number of processors */ +#if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \ + || defined(OPENBSD) || defined(DARWIN) +#define _PR_HAVE_SYSCTL +#include +#include +#endif + +#if defined(DARWIN) +#include +#include +#endif + +#if defined(HPUX) +#include +#include +#endif + +#if defined(XP_UNIX) +#include +#include +#endif + +#if defined(AIX) +#include +#include +#endif + +#if defined(WIN32) +/* This struct is not present in VC6 headers, so declare it here */ +typedef struct { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullToalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; +} PR_MEMORYSTATUSEX; + +/* Typedef for dynamic lookup of GlobalMemoryStatusEx(). */ +typedef BOOL (WINAPI *GlobalMemoryStatusExFn)(PR_MEMORYSTATUSEX *); +#endif + +PR_IMPLEMENT(char) PR_GetDirectorySeparator(void) +{ + return PR_DIRECTORY_SEPARATOR; +} /* PR_GetDirectorySeparator */ + +/* +** OBSOLETE -- the function name is misspelled. +*/ +PR_IMPLEMENT(char) PR_GetDirectorySepartor(void) +{ +#if defined(DEBUG) + static PRBool warn = PR_TRUE; + if (warn) { + warn = _PR_Obsolete("PR_GetDirectorySepartor()", + "PR_GetDirectorySeparator()"); + } +#endif + return PR_GetDirectorySeparator(); +} /* PR_GetDirectorySepartor */ + +PR_IMPLEMENT(char) PR_GetPathSeparator(void) +{ + return PR_PATH_SEPARATOR; +} /* PR_GetPathSeparator */ + +PR_IMPLEMENT(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen) +{ + PRUintn len = 0; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + switch(cmd) + { + case PR_SI_HOSTNAME: + case PR_SI_HOSTNAME_UNTRUNCATED: + if (PR_FAILURE == _PR_MD_GETHOSTNAME(buf, (PRUintn)buflen)) + return PR_FAILURE; + + if (cmd == PR_SI_HOSTNAME_UNTRUNCATED) + break; + /* + * On some platforms a system does not have a hostname and + * its IP address is returned instead. The following code + * should be skipped on those platforms. + */ +#ifndef _PR_GET_HOST_ADDR_AS_NAME + /* Return the unqualified hostname */ + while (buf[len] && (len < buflen)) { + if (buf[len] == '.') { + buf[len] = '\0'; + break; + } + len += 1; + } +#endif + break; + + case PR_SI_SYSNAME: + /* Return the operating system name */ +#if defined(XP_UNIX) || defined(WIN32) + if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen)) + return PR_FAILURE; +#else + (void)PR_snprintf(buf, buflen, _PR_SI_SYSNAME); +#endif + break; + + case PR_SI_RELEASE: + /* Return the version of the operating system */ +#if defined(XP_UNIX) || defined(WIN32) + if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen)) + return PR_FAILURE; +#endif +#if defined(XP_OS2) + { + ULONG os2ver[2] = {0}; + DosQuerySysInfo(QSV_VERSION_MINOR, QSV_VERSION_REVISION, + &os2ver, sizeof(os2ver)); + /* Formatting for normal usage (2.11, 3.0, 4.0, 4.5); officially, + Warp 4 is version 2.40.00, WSeB 2.45.00 */ + if (os2ver[0] < 30) + (void)PR_snprintf(buf, buflen, "%s%lu", + "2.", os2ver[0]); + else if (os2ver[0] < 45) + (void)PR_snprintf(buf, buflen, "%lu%s%lu", + os2ver[0]/10, ".", os2ver[1]); + else + (void)PR_snprintf(buf, buflen, "%.1f", + os2ver[0]/10.0); + } +#endif /* OS2 */ + break; + + case PR_SI_ARCHITECTURE: + /* Return the architecture of the machine (ie. x86, mips, alpha, ...)*/ + (void)PR_snprintf(buf, buflen, _PR_SI_ARCHITECTURE); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +/* +** PR_GetNumberOfProcessors() +** +** Implementation notes: +** Every platform does it a bit different. +** numCpus is the returned value. +** for each platform's "if defined" section +** declare your local variable +** do your thing, assign to numCpus +** order of the if defined()s may be important, +** especially for unix variants. Do platform +** specific implementations before XP_UNIX. +** +*/ +PR_IMPLEMENT(PRInt32) PR_GetNumberOfProcessors( void ) +{ + PRInt32 numCpus; +#if defined(WIN32) + SYSTEM_INFO info; + + GetSystemInfo( &info ); + numCpus = info.dwNumberOfProcessors; +#elif defined(XP_MAC) +/* Hard-code the number of processors to 1 on the Mac +** MacOS/9 will always be 1. The MPProcessors() call is for +** MacOS/X, when issued. Leave it commented out for now. */ +/* numCpus = MPProcessors(); */ + numCpus = 1; +#elif defined(BEOS) + system_info sysInfo; + + get_system_info(&sysInfo); + numCpus = sysInfo.cpu_count; +#elif defined(OS2) + DosQuerySysInfo( QSV_NUMPROCESSORS, QSV_NUMPROCESSORS, &numCpus, sizeof(numCpus)); +#elif defined(_PR_HAVE_SYSCTL) + int mib[2]; + int rc; + size_t len = sizeof(numCpus); + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + rc = sysctl( mib, 2, &numCpus, &len, NULL, 0 ); + if ( -1 == rc ) { + numCpus = -1; /* set to -1 for return value on error */ + _PR_MD_MAP_DEFAULT_ERROR( _MD_ERRNO() ); + } +#elif defined(HPUX) + numCpus = mpctl( MPC_GETNUMSPUS, 0, 0 ); + if ( numCpus < 1 ) { + numCpus = -1; /* set to -1 for return value on error */ + _PR_MD_MAP_DEFAULT_ERROR( _MD_ERRNO() ); + } +#elif defined(IRIX) + numCpus = sysconf( _SC_NPROC_ONLN ); +#elif defined(RISCOS) + numCpus = 1; +#elif defined(XP_UNIX) + numCpus = sysconf( _SC_NPROCESSORS_ONLN ); +#else +#error "An implementation is required" +#endif + return(numCpus); +} /* end PR_GetNumberOfProcessors() */ + +/* +** PR_GetPhysicalMemorySize() +** +** Implementation notes: +** Every platform does it a bit different. +** bytes is the returned value. +** for each platform's "if defined" section +** declare your local variable +** do your thing, assign to bytes. +** +*/ +PR_IMPLEMENT(PRUint64) PR_GetPhysicalMemorySize(void) +{ + PRUint64 bytes = 0; + +#if defined(LINUX) || defined(SOLARIS) + + long pageSize = sysconf(_SC_PAGESIZE); + long pageCount = sysconf(_SC_PHYS_PAGES); + bytes = (PRUint64) pageSize * pageCount; + +#elif defined(HPUX) + + struct pst_static info; + int result = pstat_getstatic(&info, sizeof(info), 1, 0); + if (result == 1) + bytes = (PRUint64) info.physical_memory * info.page_size; + +#elif defined(DARWIN) + + struct host_basic_info hInfo; + mach_msg_type_number_t count; + + int result = host_info(mach_host_self(), + HOST_BASIC_INFO, + (host_info_t) &hInfo, + &count); + if (result == KERN_SUCCESS) + bytes = hInfo.memory_size; + +#elif defined(WIN32) + + /* Try to use the newer GlobalMemoryStatusEx API for Windows 2000+. */ + GlobalMemoryStatusExFn globalMemory = (GlobalMemoryStatusExFn) NULL; + HMODULE module = GetModuleHandle("kernel32.dll"); + + if (module) { + globalMemory = (GlobalMemoryStatusExFn)GetProcAddress(module, "GlobalMemoryStatusEx"); + + if (globalMemory) { + PR_MEMORYSTATUSEX memStat; + memStat.dwLength = sizeof(memStat); + + if (globalMemory(&memStat)) + bytes = memStat.ullTotalPhys; + } + } + + if (!bytes) { + /* Fall back to the older API. */ + MEMORYSTATUS memStat; + memset(&memStat, 0, sizeof(memStat)); + GlobalMemoryStatus(&memStat); + bytes = memStat.dwTotalPhys; + } + +#elif defined(OS2) + + ULONG ulPhysMem; + DosQuerySysInfo(QSV_TOTPHYSMEM, + QSV_TOTPHYSMEM, + &ulPhysMem, + sizeof(ulPhysMem)); + bytes = ulPhysMem; + +#elif defined(AIX) + + if (odm_initialize() == 0) { + int how_many; + struct CuAt *obj = getattr("sys0", "realmem", 0, &how_many); + if (obj != NULL) { + bytes = (PRUint64) atoi(obj->value) * 1024; + free(obj); + } + odm_terminate(); + } + +#else + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + +#endif + + return bytes; +} /* end PR_GetPhysicalMemorySize() */ diff --git a/nsprpub/pr/src/misc/prthinfo.c b/nsprpub/pr/src/misc/prthinfo.c new file mode 100644 index 00000000000..76c44888461 --- /dev/null +++ b/nsprpub/pr/src/misc/prthinfo.c @@ -0,0 +1,247 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prlog.h" +#include "prthread.h" +#ifdef XP_MAC +#include "pprthred.h" +#else +#include "private/pprthred.h" +#endif +#include "primpl.h" + +PR_IMPLEMENT(PRWord *) +PR_GetGCRegisters(PRThread *t, int isCurrent, int *np) +{ + return _MD_HomeGCRegisters(t, isCurrent, np); +} + +PR_IMPLEMENT(PRStatus) +PR_ThreadScanStackPointers(PRThread* t, + PRScanStackFun scanFun, void* scanClosure) +{ + PRThread* current = PR_GetCurrentThread(); + PRWord *sp, *esp, *p0; + int n; + void **ptd; + PRStatus status; + PRUint32 index; + int stack_end; + + /* + ** Store the thread's registers in the thread structure so the GC + ** can scan them. Then scan them. + */ + p0 = _MD_HomeGCRegisters(t, t == current, &n); + status = scanFun(t, (void**)p0, n, scanClosure); + if (status != PR_SUCCESS) + return status; + + /* Scan the C stack for pointers into the GC heap */ +#if defined(XP_PC) && defined(WIN16) + /* + ** Under WIN16, the stack of the current thread is always mapped into + ** the "task stack" (at SS:xxxx). So, if t is the current thread, scan + ** the "task stack". Otherwise, scan the "cached stack" of the inactive + ** thread... + */ + if (t == current) { + sp = (PRWord*) &stack_end; + esp = (PRWord*) _pr_top_of_task_stack; + + PR_ASSERT(sp <= esp); + } else { + sp = (PRWord*) PR_GetSP(t); + esp = (PRWord*) t->stack->stackTop; + + PR_ASSERT((t->stack->stackSize == 0) || + ((sp > (PRWord*)t->stack->stackBottom) && + (sp <= (PRWord*)t->stack->stackTop))); + } +#else /* ! WIN16 */ +#ifdef HAVE_STACK_GROWING_UP + if (t == current) { + esp = (PRWord*) &stack_end; + } else { + esp = (PRWord*) PR_GetSP(t); + } + sp = (PRWord*) t->stack->stackTop; + if (t->stack->stackSize) { + PR_ASSERT((esp > (PRWord*)t->stack->stackTop) && + (esp < (PRWord*)t->stack->stackBottom)); + } +#else /* ! HAVE_STACK_GROWING_UP */ + if (t == current) { + sp = (PRWord*) &stack_end; + } else { + sp = (PRWord*) PR_GetSP(t); + } + esp = (PRWord*) t->stack->stackTop; + if (t->stack->stackSize) { + PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) && + (sp < (PRWord*)t->stack->stackTop)); + } +#endif /* ! HAVE_STACK_GROWING_UP */ +#endif /* ! WIN16 */ + +#if defined(WIN16) + { + prword_t scan; + prword_t limit; + + scan = (prword_t) sp; + limit = (prword_t) esp; + while (scan < limit) { + prword_t *test; + + test = *((prword_t **)scan); + status = scanFun(t, (void**)&test, 1, scanClosure); + if (status != PR_SUCCESS) + return status; + scan += sizeof(char); + } + } +#else + if (sp < esp) { + status = scanFun(t, (void**)sp, esp - sp, scanClosure); + if (status != PR_SUCCESS) + return status; + } +#endif + + /* + ** Mark all of the per-thread-data items attached to this thread + ** + ** 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; + +#ifndef GC_LEAK_DETECTOR + /* if thread is not allocated on stack, this is redundant. */ + ptd = t->privateData; + for (index = 0; index < t->tpdLength; index++, ptd++) { + status = scanFun(t, (void**)ptd, 1, scanClosure); + if (status != PR_SUCCESS) + return status; + } +#endif + + return PR_SUCCESS; +} + +/* transducer for PR_EnumerateThreads */ +typedef struct PRScanStackData { + PRScanStackFun scanFun; + void* scanClosure; +} PRScanStackData; + +static PRStatus PR_CALLBACK +pr_ScanStack(PRThread* t, int i, void* arg) +{ +#if defined(XP_MAC) +#pragma unused (i) +#endif + PRScanStackData* data = (PRScanStackData*)arg; + return PR_ThreadScanStackPointers(t, data->scanFun, data->scanClosure); +} + +PR_IMPLEMENT(PRStatus) +PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure) +{ + PRScanStackData data; + data.scanFun = scanFun; + data.scanClosure = scanClosure; + return PR_EnumerateThreads(pr_ScanStack, &data); +} + +PR_IMPLEMENT(PRUword) +PR_GetStackSpaceLeft(PRThread* t) +{ + PRThread *current = PR_GetCurrentThread(); + PRWord *sp, *esp; + int stack_end; + +#if defined(WIN16) + /* + ** Under WIN16, the stack of the current thread is always mapped into + ** the "task stack" (at SS:xxxx). So, if t is the current thread, scan + ** the "task stack". Otherwise, scan the "cached stack" of the inactive + ** thread... + */ + if (t == current) { + sp = (PRWord*) &stack_end; + esp = (PRWord*) _pr_top_of_task_stack; + + PR_ASSERT(sp <= esp); + } else { + sp = (PRWord*) PR_GetSP(t); + esp = (PRWord*) t->stack->stackTop; + + PR_ASSERT((t->stack->stackSize == 0) || + ((sp > (PRWord*)t->stack->stackBottom) && + (sp <= (PRWord*)t->stack->stackTop))); + } +#else /* ! WIN16 */ +#ifdef HAVE_STACK_GROWING_UP + if (t == current) { + esp = (PRWord*) &stack_end; + } else { + esp = (PRWord*) PR_GetSP(t); + } + sp = (PRWord*) t->stack->stackTop; + if (t->stack->stackSize) { + PR_ASSERT((esp > (PRWord*)t->stack->stackTop) && + (esp < (PRWord*)t->stack->stackBottom)); + } +#else /* ! HAVE_STACK_GROWING_UP */ + if (t == current) { + sp = (PRWord*) &stack_end; + } else { + sp = (PRWord*) PR_GetSP(t); + } + esp = (PRWord*) t->stack->stackTop; + if (t->stack->stackSize) { + PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) && + (sp < (PRWord*)t->stack->stackTop)); + } +#endif /* ! HAVE_STACK_GROWING_UP */ +#endif /* ! WIN16 */ + return (PRUword)t->stack->stackSize - ((PRWord)esp - (PRWord)sp); +} diff --git a/nsprpub/pr/src/misc/prtime.c b/nsprpub/pr/src/misc/prtime.c new file mode 100644 index 00000000000..0a0045c8282 --- /dev/null +++ b/nsprpub/pr/src/misc/prtime.c @@ -0,0 +1,2015 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * prtime.c -- + * + * NSPR date and time functions + * + */ + +#include "prinit.h" +#include "prtime.h" +#include "prlock.h" +#include "prprf.h" +#include "prlog.h" + +#include +#include + +#ifdef XP_MAC +#include +#endif + +/* + * The COUNT_LEAPS macro counts the number of leap years passed by + * till the start of the given year Y. At the start of the year 4 + * A.D. the number of leap years passed by is 0, while at the start of + * the year 5 A.D. this count is 1. The number of years divisible by + * 100 but not divisible by 400 (the non-leap years) is deducted from + * the count to get the correct number of leap years. + * + * The COUNT_DAYS macro counts the number of days since 01/01/01 till the + * start of the given year Y. The number of days at the start of the year + * 1 is 0 while the number of days at the start of the year 2 is 365 + * (which is ((2)-1) * 365) and so on. The reference point is 01/01/01 + * midnight 00:00:00. + */ + +#define COUNT_LEAPS(Y) ( ((Y)-1)/4 - ((Y)-1)/100 + ((Y)-1)/400 ) +#define COUNT_DAYS(Y) ( ((Y)-1)*365 + COUNT_LEAPS(Y) ) +#define DAYS_BETWEEN_YEARS(A, B) (COUNT_DAYS(B) - COUNT_DAYS(A)) + + + + +/* + * Static variables used by functions in this file + */ + +/* + * The following array contains the day of year for the last day of + * each month, where index 1 is January, and day 0 is January 1. + */ + +static const int lastDayOfMonth[2][13] = { + {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, + {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365} +}; + +/* + * The number of days in a month + */ + +static const PRInt8 nDays[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +}; + +/* + * Declarations for internal functions defined later in this file. + */ + +static void ComputeGMT(PRTime time, PRExplodedTime *gmt); +static int IsLeapYear(PRInt16 year); +static void ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset); + +/* + *------------------------------------------------------------------------ + * + * ComputeGMT -- + * + * Caveats: + * - we ignore leap seconds + * - our leap-year calculation is only correct for years 1901-2099 + * + *------------------------------------------------------------------------ + */ + +static void +ComputeGMT(PRTime time, PRExplodedTime *gmt) +{ + PRInt32 tmp, rem; + PRInt32 numDays; + PRInt64 numDays64, rem64; + int isLeap; + PRInt64 sec; + PRInt64 usec; + PRInt64 usecPerSec; + PRInt64 secPerDay; + + /* + * We first do the usec, sec, min, hour thing so that we do not + * have to do LL arithmetic. + */ + + LL_I2L(usecPerSec, 1000000L); + LL_DIV(sec, time, usecPerSec); + LL_MOD(usec, time, usecPerSec); + LL_L2I(gmt->tm_usec, usec); + /* Correct for weird mod semantics so the remainder is always positive */ + if (gmt->tm_usec < 0) { + PRInt64 one; + + LL_I2L(one, 1L); + LL_SUB(sec, sec, one); + gmt->tm_usec += 1000000L; + } + + LL_I2L(secPerDay, 86400L); + LL_DIV(numDays64, sec, secPerDay); + LL_MOD(rem64, sec, secPerDay); + /* We are sure both of these numbers can fit into PRInt32 */ + LL_L2I(numDays, numDays64); + LL_L2I(rem, rem64); + if (rem < 0) { + numDays--; + rem += 86400L; + } + + /* Compute day of week. Epoch started on a Thursday. */ + + gmt->tm_wday = (numDays + 4) % 7; + if (gmt->tm_wday < 0) { + gmt->tm_wday += 7; + } + + /* Compute the time of day. */ + + gmt->tm_hour = rem / 3600; + rem %= 3600; + gmt->tm_min = rem / 60; + gmt->tm_sec = rem % 60; + + /* Compute the four-year span containing the specified time */ + + tmp = numDays / (4 * 365 + 1); + rem = numDays % (4 * 365 + 1); + + if (rem < 0) { + tmp--; + rem += (4 * 365 + 1); + } + + /* + * Compute the year after 1900 by taking the four-year span and + * adjusting for the remainder. This works because 2000 is a + * leap year, and 1900 and 2100 are out of the range. + */ + + tmp = (tmp * 4) + 1970; + isLeap = 0; + + /* + * 1970 has 365 days + * 1971 has 365 days + * 1972 has 366 days (leap year) + * 1973 has 365 days + */ + + if (rem >= 365) { /* 1971, etc. */ + tmp++; + rem -= 365; + if (rem >= 365) { /* 1972, etc. */ + tmp++; + rem -= 365; + if (rem >= 366) { /* 1973, etc. */ + tmp++; + rem -= 366; + } else { + isLeap = 1; + } + } + } + + gmt->tm_year = tmp; + gmt->tm_yday = rem; + + /* Compute the month and day of month. */ + + for (tmp = 1; lastDayOfMonth[isLeap][tmp] < gmt->tm_yday; tmp++) { + } + gmt->tm_month = --tmp; + gmt->tm_mday = gmt->tm_yday - lastDayOfMonth[isLeap][tmp]; + + gmt->tm_params.tp_gmt_offset = 0; + gmt->tm_params.tp_dst_offset = 0; +} + + +/* + *------------------------------------------------------------------------ + * + * PR_ExplodeTime -- + * + * Cf. struct tm *gmtime(const time_t *tp) and + * struct tm *localtime(const time_t *tp) + * + *------------------------------------------------------------------------ + */ + +PR_IMPLEMENT(void) +PR_ExplodeTime( + PRTime usecs, + PRTimeParamFn params, + PRExplodedTime *exploded) +{ + ComputeGMT(usecs, exploded); + exploded->tm_params = params(exploded); + ApplySecOffset(exploded, exploded->tm_params.tp_gmt_offset + + exploded->tm_params.tp_dst_offset); +} + + +/* + *------------------------------------------------------------------------ + * + * PR_ImplodeTime -- + * + * Cf. time_t mktime(struct tm *tp) + * Note that 1 year has < 2^25 seconds. So an PRInt32 is large enough. + * + *------------------------------------------------------------------------ + */ +#if defined(HAVE_WATCOM_BUG_2) +PRTime __pascal __export __loadds +#else +PR_IMPLEMENT(PRTime) +#endif +PR_ImplodeTime(const PRExplodedTime *exploded) +{ + PRExplodedTime copy; + PRTime retVal; + PRInt64 secPerDay, usecPerSec; + PRInt64 temp; + PRInt64 numSecs64; + PRInt32 numDays; + PRInt32 numSecs; + + /* Normalize first. Do this on our copy */ + copy = *exploded; + PR_NormalizeTime(©, PR_GMTParameters); + + numDays = DAYS_BETWEEN_YEARS(1970, copy.tm_year); + + numSecs = copy.tm_yday * 86400 + copy.tm_hour * 3600 + + copy.tm_min * 60 + copy.tm_sec; + + LL_I2L(temp, numDays); + LL_I2L(secPerDay, 86400); + LL_MUL(temp, temp, secPerDay); + LL_I2L(numSecs64, numSecs); + LL_ADD(numSecs64, numSecs64, temp); + + /* apply the GMT and DST offsets */ + LL_I2L(temp, copy.tm_params.tp_gmt_offset); + LL_SUB(numSecs64, numSecs64, temp); + LL_I2L(temp, copy.tm_params.tp_dst_offset); + LL_SUB(numSecs64, numSecs64, temp); + + LL_I2L(usecPerSec, 1000000L); + LL_MUL(temp, numSecs64, usecPerSec); + LL_I2L(retVal, copy.tm_usec); + LL_ADD(retVal, retVal, temp); + + return retVal; +} + +/* + *------------------------------------------------------------------------- + * + * IsLeapYear -- + * + * Returns 1 if the year is a leap year, 0 otherwise. + * + *------------------------------------------------------------------------- + */ + +static int IsLeapYear(PRInt16 year) +{ + if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) + return 1; + else + return 0; +} + +/* + * 'secOffset' should be less than 86400 (i.e., a day). + * 'time' should point to a normalized PRExplodedTime. + */ + +static void +ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset) +{ + time->tm_sec += secOffset; + + /* Note that in this implementation we do not count leap seconds */ + if (time->tm_sec < 0 || time->tm_sec >= 60) { + time->tm_min += time->tm_sec / 60; + time->tm_sec %= 60; + if (time->tm_sec < 0) { + time->tm_sec += 60; + time->tm_min--; + } + } + + if (time->tm_min < 0 || time->tm_min >= 60) { + time->tm_hour += time->tm_min / 60; + time->tm_min %= 60; + if (time->tm_min < 0) { + time->tm_min += 60; + time->tm_hour--; + } + } + + if (time->tm_hour < 0) { + /* Decrement mday, yday, and wday */ + time->tm_hour += 24; + time->tm_mday--; + time->tm_yday--; + if (time->tm_mday < 1) { + time->tm_month--; + if (time->tm_month < 0) { + time->tm_month = 11; + time->tm_year--; + if (IsLeapYear(time->tm_year)) + time->tm_yday = 365; + else + time->tm_yday = 364; + } + time->tm_mday = nDays[IsLeapYear(time->tm_year)][time->tm_month]; + } + time->tm_wday--; + if (time->tm_wday < 0) + time->tm_wday = 6; + } else if (time->tm_hour > 23) { + /* Increment mday, yday, and wday */ + time->tm_hour -= 24; + time->tm_mday++; + time->tm_yday++; + if (time->tm_mday > + nDays[IsLeapYear(time->tm_year)][time->tm_month]) { + time->tm_mday = 1; + time->tm_month++; + if (time->tm_month > 11) { + time->tm_month = 0; + time->tm_year++; + time->tm_yday = 0; + } + } + time->tm_wday++; + if (time->tm_wday > 6) + time->tm_wday = 0; + } +} + +PR_IMPLEMENT(void) +PR_NormalizeTime(PRExplodedTime *time, PRTimeParamFn params) +{ + int daysInMonth; + PRInt32 numDays; + + /* Get back to GMT */ + time->tm_sec -= time->tm_params.tp_gmt_offset + + time->tm_params.tp_dst_offset; + time->tm_params.tp_gmt_offset = 0; + time->tm_params.tp_dst_offset = 0; + + /* Now normalize GMT */ + + if (time->tm_usec < 0 || time->tm_usec >= 1000000) { + time->tm_sec += time->tm_usec / 1000000; + time->tm_usec %= 1000000; + if (time->tm_usec < 0) { + time->tm_usec += 1000000; + time->tm_sec--; + } + } + + /* Note that we do not count leap seconds in this implementation */ + if (time->tm_sec < 0 || time->tm_sec >= 60) { + time->tm_min += time->tm_sec / 60; + time->tm_sec %= 60; + if (time->tm_sec < 0) { + time->tm_sec += 60; + time->tm_min--; + } + } + + if (time->tm_min < 0 || time->tm_min >= 60) { + time->tm_hour += time->tm_min / 60; + time->tm_min %= 60; + if (time->tm_min < 0) { + time->tm_min += 60; + time->tm_hour--; + } + } + + if (time->tm_hour < 0 || time->tm_hour >= 24) { + time->tm_mday += time->tm_hour / 24; + time->tm_hour %= 24; + if (time->tm_hour < 0) { + time->tm_hour += 24; + time->tm_mday--; + } + } + + /* Normalize month and year before mday */ + if (time->tm_month < 0 || time->tm_month >= 12) { + time->tm_year += time->tm_month / 12; + time->tm_month %= 12; + if (time->tm_month < 0) { + time->tm_month += 12; + time->tm_year--; + } + } + + /* Now that month and year are in proper range, normalize mday */ + + if (time->tm_mday < 1) { + /* mday too small */ + do { + /* the previous month */ + time->tm_month--; + if (time->tm_month < 0) { + time->tm_month = 11; + time->tm_year--; + } + time->tm_mday += nDays[IsLeapYear(time->tm_year)][time->tm_month]; + } while (time->tm_mday < 1); + } else { + daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month]; + while (time->tm_mday > daysInMonth) { + /* mday too large */ + time->tm_mday -= daysInMonth; + time->tm_month++; + if (time->tm_month > 11) { + time->tm_month = 0; + time->tm_year++; + } + daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month]; + } + } + + /* Recompute yday and wday */ + time->tm_yday = time->tm_mday + + lastDayOfMonth[IsLeapYear(time->tm_year)][time->tm_month]; + + numDays = DAYS_BETWEEN_YEARS(1970, time->tm_year) + time->tm_yday; + time->tm_wday = (numDays + 4) % 7; + if (time->tm_wday < 0) { + time->tm_wday += 7; + } + + /* Recompute time parameters */ + + time->tm_params = params(time); + + ApplySecOffset(time, time->tm_params.tp_gmt_offset + + time->tm_params.tp_dst_offset); +} + + +/* + *------------------------------------------------------------------------- + * + * PR_LocalTimeParameters -- + * + * returns the time parameters for the local time zone + * + * The following uses localtime() from the standard C library. + * (time.h) This is our fallback implementation. Unix and PC + * use this version. Mac has its own machine-dependent + * implementation of this function. + * + *------------------------------------------------------------------------- + */ + +#include + +#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) == -1 ? NULL: result) + +#elif defined(HAVE_POINTER_LOCALTIME_R) + +#define MT_safe_localtime localtime_r + +#else + +#if defined(XP_MAC) +extern struct tm *Maclocaltime(const time_t * t); +#endif + +#define HAVE_LOCALTIME_MONITOR 1 /* We use 'monitor' to serialize our calls + * to localtime(). */ +static PRLock *monitor = NULL; + +static struct tm *MT_safe_localtime(const time_t *clock, struct tm *result) +{ + struct tm *tmPtr; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) PR_Lock(monitor); + + /* + * Microsoft (all flavors) localtime() returns a NULL pointer if 'clock' + * represents a time before midnight January 1, 1970. In + * that case, we also return a NULL pointer and the struct tm + * object pointed to by 'result' is not modified. + * + * Watcom C/C++ 11.0 localtime() treats time_t as unsigned long + * hence, does not recognize negative values of clock as pre-1/1/70. + * We have to manually check (WIN16 only) for negative value of + * clock and return NULL. + * + * With negative values of clock, emx returns the struct tm for + * clock plus ULONG_MAX. So we also have to check for the invalid + * structs returned for timezones west of Greenwich when clock == 0. + */ + +#if defined(XP_MAC) + tmPtr = Maclocaltime(clock); +#else + tmPtr = localtime(clock); +#endif + +#if defined(WIN16) || defined(XP_OS2_EMX) + if ( (PRInt32) *clock < 0 || + ( (PRInt32) *clock == 0 && tmPtr->tm_year != 70)) + result = NULL; + else + *result = *tmPtr; +#else + if (tmPtr) { + *result = *tmPtr; + } else { + result = NULL; + } +#endif /* WIN16 */ + + if (needLock) PR_Unlock(monitor); + + return result; +} + +#endif /* definition of MT_safe_localtime() */ + +void _PR_InitTime(void) +{ +#ifdef HAVE_LOCALTIME_MONITOR + monitor = PR_NewLock(); +#endif +} + +void _PR_CleanupTime(void) +{ +#ifdef HAVE_LOCALTIME_MONITOR + if (monitor) { + PR_DestroyLock(monitor); + monitor = NULL; + } +#endif +} + +#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS) + +PR_IMPLEMENT(PRTimeParameters) +PR_LocalTimeParameters(const PRExplodedTime *gmt) +{ + + PRTimeParameters retVal; + struct tm localTime; + time_t secs; + PRTime secs64; + PRInt64 usecPerSec; + PRInt64 usecPerSec_1; + PRInt64 maxInt32; + PRInt64 minInt32; + PRInt32 dayOffset; + PRInt32 offset2Jan1970; + PRInt32 offsetNew; + int isdst2Jan1970; + + /* + * Calculate the GMT offset. First, figure out what is + * 00:00:00 Jan. 2, 1970 GMT (which is exactly a day, or 86400 + * seconds, since the epoch) in local time. Then we calculate + * the difference between local time and GMT in seconds: + * gmt_offset = local_time - GMT + * + * Caveat: the validity of this calculation depends on two + * assumptions: + * 1. Daylight saving time was not in effect on Jan. 2, 1970. + * 2. The time zone of the geographic location has not changed + * since Jan. 2, 1970. + */ + + secs = 86400L; + (void) MT_safe_localtime(&secs, &localTime); + + /* GMT is 00:00:00, 2nd of Jan. */ + + offset2Jan1970 = (PRInt32)localTime.tm_sec + + 60L * (PRInt32)localTime.tm_min + + 3600L * (PRInt32)localTime.tm_hour + + 86400L * (PRInt32)((PRInt32)localTime.tm_mday - 2L); + + isdst2Jan1970 = localTime.tm_isdst; + + /* + * Now compute DST offset. We calculate the overall offset + * of local time from GMT, similar to above. The overall + * offset has two components: gmt offset and dst offset. + * We subtract gmt offset from the overall offset to get + * the dst offset. + * overall_offset = local_time - GMT + * overall_offset = gmt_offset + dst_offset + * ==> dst_offset = local_time - GMT - gmt_offset + */ + + secs64 = PR_ImplodeTime(gmt); /* This is still in microseconds */ + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_I2L(usecPerSec_1, PR_USEC_PER_SEC - 1); + /* Convert to seconds, truncating down (3.1 -> 3 and -3.1 -> -4) */ + if (LL_GE_ZERO(secs64)) { + LL_DIV(secs64, secs64, usecPerSec); + } else { + LL_NEG(secs64, secs64); + LL_ADD(secs64, secs64, usecPerSec_1); + LL_DIV(secs64, secs64, usecPerSec); + LL_NEG(secs64, secs64); + } + LL_I2L(maxInt32, PR_INT32_MAX); + LL_I2L(minInt32, PR_INT32_MIN); + if (LL_CMP(secs64, >, maxInt32) || LL_CMP(secs64, <, minInt32)) { + /* secs64 is too large or too small for time_t (32-bit integer) */ + retVal.tp_gmt_offset = offset2Jan1970; + retVal.tp_dst_offset = 0; + return retVal; + } + LL_L2I(secs, secs64); + + /* + * On Windows, localtime() (and our MT_safe_localtime() too) + * returns a NULL pointer for time before midnight January 1, + * 1970 GMT. In that case, we just use the GMT offset for + * Jan 2, 1970 and assume that DST was not in effect. + */ + + if (MT_safe_localtime(&secs, &localTime) == NULL) { + retVal.tp_gmt_offset = offset2Jan1970; + retVal.tp_dst_offset = 0; + return retVal; + } + + /* + * dayOffset is the offset between local time and GMT in + * the day component, which can only be -1, 0, or 1. We + * use the day of the week to compute dayOffset. + */ + + dayOffset = (PRInt32) localTime.tm_wday - gmt->tm_wday; + + /* + * Need to adjust for wrapping around of day of the week from + * 6 back to 0. + */ + + if (dayOffset == -6) { + /* Local time is Sunday (0) and GMT is Saturday (6) */ + dayOffset = 1; + } else if (dayOffset == 6) { + /* Local time is Saturday (6) and GMT is Sunday (0) */ + dayOffset = -1; + } + + offsetNew = (PRInt32)localTime.tm_sec - gmt->tm_sec + + 60L * ((PRInt32)localTime.tm_min - gmt->tm_min) + + 3600L * ((PRInt32)localTime.tm_hour - gmt->tm_hour) + + 86400L * (PRInt32)dayOffset; + + if (localTime.tm_isdst <= 0) { + /* DST is not in effect */ + retVal.tp_gmt_offset = offsetNew; + retVal.tp_dst_offset = 0; + } else { + /* DST is in effect */ + if (isdst2Jan1970 <=0) { + /* + * DST was not in effect back in 2 Jan. 1970. + * Use the offset back then as the GMT offset, + * assuming the time zone has not changed since then. + */ + retVal.tp_gmt_offset = offset2Jan1970; + retVal.tp_dst_offset = offsetNew - offset2Jan1970; + } else { + /* + * DST was also in effect back in 2 Jan. 1970. + * Then our clever trick (or rather, ugly hack) fails. + * We will just assume DST offset is an hour. + */ + retVal.tp_gmt_offset = offsetNew - 3600; + retVal.tp_dst_offset = 3600; + } + } + + return retVal; +} + +#endif /* defined(XP_UNIX) !! defined(XP_PC) */ + +/* + *------------------------------------------------------------------------ + * + * PR_USPacificTimeParameters -- + * + * The time parameters function for the US Pacific Time Zone. + * + *------------------------------------------------------------------------ + */ + +/* + * Returns the mday of the first sunday of the month, where + * mday and wday are for a given day in the month. + * mdays start with 1 (e.g. 1..31). + * wdays start with 0 and are in the range 0..6. 0 = Sunday. + */ +#define firstSunday(mday, wday) (((mday - wday + 7 - 1) % 7) + 1) + +/* + * Returns the mday for the N'th Sunday of the month, where + * mday and wday are for a given day in the month. + * mdays start with 1 (e.g. 1..31). + * wdays start with 0 and are in the range 0..6. 0 = Sunday. + * N has the following values: 0 = first, 1 = second (etc), -1 = last. + * ndays is the number of days in that month, the same value as the + * mday of the last day of the month. + */ +static PRInt32 +NthSunday(PRInt32 mday, PRInt32 wday, PRInt32 N, PRInt32 ndays) +{ + PRInt32 firstSun = firstSunday(mday, wday); + + if (N < 0) + N = (ndays - firstSun) / 7; + return firstSun + (7 * N); +} + +typedef struct DSTParams { + PRInt8 dst_start_month; /* 0 = January */ + PRInt8 dst_start_Nth_Sunday; /* N as defined above */ + PRInt8 dst_start_month_ndays; /* ndays as defined above */ + PRInt8 dst_end_month; /* 0 = January */ + PRInt8 dst_end_Nth_Sunday; /* N as defined above */ + PRInt8 dst_end_month_ndays; /* ndays as defined above */ +} DSTParams; + +static const DSTParams dstParams[2] = { + /* year < 2007: First April Sunday - Last October Sunday */ + { 3, 0, 30, 9, -1, 31 }, + /* year >= 2007: Second March Sunday - First November Sunday */ + { 2, 1, 31, 10, 0, 30 } +}; + +PR_IMPLEMENT(PRTimeParameters) +PR_USPacificTimeParameters(const PRExplodedTime *gmt) +{ + const DSTParams *dst; + PRTimeParameters retVal; + PRExplodedTime st; + + /* + * Based on geographic location and GMT, figure out offset of + * standard time from GMT. In this example implementation, we + * assume the local time zone is US Pacific Time. + */ + + retVal.tp_gmt_offset = -8L * 3600L; + + /* + * Make a copy of GMT. Note that the tm_params field of this copy + * is ignored. + */ + + st.tm_usec = gmt->tm_usec; + st.tm_sec = gmt->tm_sec; + st.tm_min = gmt->tm_min; + st.tm_hour = gmt->tm_hour; + st.tm_mday = gmt->tm_mday; + st.tm_month = gmt->tm_month; + st.tm_year = gmt->tm_year; + st.tm_wday = gmt->tm_wday; + st.tm_yday = gmt->tm_yday; + + /* Apply the offset to GMT to obtain the local standard time */ + ApplySecOffset(&st, retVal.tp_gmt_offset); + + if (st.tm_year < 2007) { /* first April Sunday - Last October Sunday */ + dst = &dstParams[0]; + } else { /* Second March Sunday - First November Sunday */ + dst = &dstParams[1]; + } + + /* + * Apply the rules on standard time or GMT to obtain daylight saving + * time offset. In this implementation, we use the US DST rule. + */ + if (st.tm_month < dst->dst_start_month) { + retVal.tp_dst_offset = 0L; + } else if (st.tm_month == dst->dst_start_month) { + int NthSun = NthSunday(st.tm_mday, st.tm_wday, + dst->dst_start_Nth_Sunday, + dst->dst_start_month_ndays); + if (st.tm_mday < NthSun) { /* Before starting Sunday */ + retVal.tp_dst_offset = 0L; + } else if (st.tm_mday == NthSun) { /* Starting Sunday */ + /* 01:59:59 PST -> 03:00:00 PDT */ + if (st.tm_hour < 2) { + retVal.tp_dst_offset = 0L; + } else { + retVal.tp_dst_offset = 3600L; + } + } else { /* After starting Sunday */ + retVal.tp_dst_offset = 3600L; + } + } else if (st.tm_month < dst->dst_end_month) { + retVal.tp_dst_offset = 3600L; + } else if (st.tm_month == dst->dst_end_month) { + int NthSun = NthSunday(st.tm_mday, st.tm_wday, + dst->dst_end_Nth_Sunday, + dst->dst_end_month_ndays); + if (st.tm_mday < NthSun) { /* Before ending Sunday */ + retVal.tp_dst_offset = 3600L; + } else if (st.tm_mday == NthSun) { /* Ending Sunday */ + /* 01:59:59 PDT -> 01:00:00 PST */ + if (st.tm_hour < 1) { + retVal.tp_dst_offset = 3600L; + } else { + retVal.tp_dst_offset = 0L; + } + } else { /* After ending Sunday */ + retVal.tp_dst_offset = 0L; + } + } else { + retVal.tp_dst_offset = 0L; + } + return retVal; +} + +/* + *------------------------------------------------------------------------ + * + * PR_GMTParameters -- + * + * Returns the PRTimeParameters for Greenwich Mean Time. + * Trivially, both the tp_gmt_offset and tp_dst_offset fields are 0. + * + *------------------------------------------------------------------------ + */ + +PR_IMPLEMENT(PRTimeParameters) +PR_GMTParameters(const PRExplodedTime *gmt) +{ +#if defined(XP_MAC) +#pragma unused (gmt) +#endif + + PRTimeParameters retVal = { 0, 0 }; + return retVal; +} + +/* + * The following code implements PR_ParseTimeString(). It is based on + * ns/lib/xp/xp_time.c, revision 1.25, by Jamie Zawinski . + */ + +/* + * We only recognize the abbreviations of a small subset of time zones + * in North America, Europe, and Japan. + * + * PST/PDT: Pacific Standard/Daylight Time + * MST/MDT: Mountain Standard/Daylight Time + * CST/CDT: Central Standard/Daylight Time + * EST/EDT: Eastern Standard/Daylight Time + * AST: Atlantic Standard Time + * NST: Newfoundland Standard Time + * GMT: Greenwich Mean Time + * BST: British Summer Time + * MET: Middle Europe Time + * EET: Eastern Europe Time + * JST: Japan Standard Time + */ + +typedef enum +{ + TT_UNKNOWN, + + TT_SUN, TT_MON, TT_TUE, TT_WED, TT_THU, TT_FRI, TT_SAT, + + TT_JAN, TT_FEB, TT_MAR, TT_APR, TT_MAY, TT_JUN, + TT_JUL, TT_AUG, TT_SEP, TT_OCT, TT_NOV, TT_DEC, + + TT_PST, TT_PDT, TT_MST, TT_MDT, TT_CST, TT_CDT, TT_EST, TT_EDT, + TT_AST, TT_NST, TT_GMT, TT_BST, TT_MET, TT_EET, TT_JST +} TIME_TOKEN; + +/* + * This parses a time/date string into a PRTime + * (microseconds after "1-Jan-1970 00:00:00 GMT"). + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + * + * Many formats are handled, including: + * + * 14 Apr 89 03:20:12 + * 14 Apr 89 03:20 GMT + * Fri, 17 Mar 89 4:01:33 + * Fri, 17 Mar 89 4:01 GMT + * Mon Jan 16 16:12 PDT 1989 + * Mon Jan 16 16:12 +0130 1989 + * 6 May 1992 16:41-JST (Wednesday) + * 22-AUG-1993 10:59:12.82 + * 22-AUG-1993 10:59pm + * 22-AUG-1993 12:59am + * 22-AUG-1993 12:59 PM + * Friday, August 04, 1995 3:54 PM + * 06/21/95 04:24:34 PM + * 20/06/95 21:07 + * 95-06-08 19:32:48 EDT + * + * If the input string doesn't contain a description of the timezone, + * we consult the `default_to_gmt' to decide whether the string should + * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE). + * The correct value for this argument depends on what standard specified + * the time string which you are parsing. + */ + +PR_IMPLEMENT(PRStatus) +PR_ParseTimeStringToExplodedTime( + const char *string, + PRBool default_to_gmt, + PRExplodedTime *result) +{ + TIME_TOKEN dotw = TT_UNKNOWN; + TIME_TOKEN month = TT_UNKNOWN; + TIME_TOKEN zone = TT_UNKNOWN; + int zone_offset = -1; + int dst_offset = 0; + int date = -1; + PRInt32 year = -1; + int hour = -1; + int min = -1; + int sec = -1; + + const char *rest = string; + + int iterations = 0; + + PR_ASSERT(string && result); + if (!string || !result) return PR_FAILURE; + + while (*rest) + { + + if (iterations++ > 1000) + { + return PR_FAILURE; + } + + switch (*rest) + { + case 'a': case 'A': + if (month == TT_UNKNOWN && + (rest[1] == 'p' || rest[1] == 'P') && + (rest[2] == 'r' || rest[2] == 'R')) + month = TT_APR; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_AST; + else if (month == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'g' || rest[2] == 'G')) + month = TT_AUG; + break; + case 'b': case 'B': + if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_BST; + break; + case 'c': case 'C': + if (zone == TT_UNKNOWN && + (rest[1] == 'd' || rest[1] == 'D') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_CDT; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_CST; + break; + case 'd': case 'D': + if (month == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 'c' || rest[2] == 'C')) + month = TT_DEC; + break; + case 'e': case 'E': + if (zone == TT_UNKNOWN && + (rest[1] == 'd' || rest[1] == 'D') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_EDT; + else if (zone == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_EET; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_EST; + break; + case 'f': case 'F': + if (month == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 'b' || rest[2] == 'B')) + month = TT_FEB; + else if (dotw == TT_UNKNOWN && + (rest[1] == 'r' || rest[1] == 'R') && + (rest[2] == 'i' || rest[2] == 'I')) + dotw = TT_FRI; + break; + case 'g': case 'G': + if (zone == TT_UNKNOWN && + (rest[1] == 'm' || rest[1] == 'M') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_GMT; + break; + case 'j': case 'J': + if (month == TT_UNKNOWN && + (rest[1] == 'a' || rest[1] == 'A') && + (rest[2] == 'n' || rest[2] == 'N')) + month = TT_JAN; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_JST; + else if (month == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'l' || rest[2] == 'L')) + month = TT_JUL; + else if (month == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'n' || rest[2] == 'N')) + month = TT_JUN; + break; + case 'm': case 'M': + if (month == TT_UNKNOWN && + (rest[1] == 'a' || rest[1] == 'A') && + (rest[2] == 'r' || rest[2] == 'R')) + month = TT_MAR; + else if (month == TT_UNKNOWN && + (rest[1] == 'a' || rest[1] == 'A') && + (rest[2] == 'y' || rest[2] == 'Y')) + month = TT_MAY; + else if (zone == TT_UNKNOWN && + (rest[1] == 'd' || rest[1] == 'D') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_MDT; + else if (zone == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_MET; + else if (dotw == TT_UNKNOWN && + (rest[1] == 'o' || rest[1] == 'O') && + (rest[2] == 'n' || rest[2] == 'N')) + dotw = TT_MON; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_MST; + break; + case 'n': case 'N': + if (month == TT_UNKNOWN && + (rest[1] == 'o' || rest[1] == 'O') && + (rest[2] == 'v' || rest[2] == 'V')) + month = TT_NOV; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_NST; + break; + case 'o': case 'O': + if (month == TT_UNKNOWN && + (rest[1] == 'c' || rest[1] == 'C') && + (rest[2] == 't' || rest[2] == 'T')) + month = TT_OCT; + break; + case 'p': case 'P': + if (zone == TT_UNKNOWN && + (rest[1] == 'd' || rest[1] == 'D') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_PDT; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_PST; + break; + case 's': case 'S': + if (dotw == TT_UNKNOWN && + (rest[1] == 'a' || rest[1] == 'A') && + (rest[2] == 't' || rest[2] == 'T')) + dotw = TT_SAT; + else if (month == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 'p' || rest[2] == 'P')) + month = TT_SEP; + else if (dotw == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'n' || rest[2] == 'N')) + dotw = TT_SUN; + break; + case 't': case 'T': + if (dotw == TT_UNKNOWN && + (rest[1] == 'h' || rest[1] == 'H') && + (rest[2] == 'u' || rest[2] == 'U')) + dotw = TT_THU; + else if (dotw == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'e' || rest[2] == 'E')) + dotw = TT_TUE; + break; + case 'u': case 'U': + if (zone == TT_UNKNOWN && + (rest[1] == 't' || rest[1] == 'T') && + !(rest[2] >= 'A' && rest[2] <= 'Z') && + !(rest[2] >= 'a' && rest[2] <= 'z')) + /* UT is the same as GMT but UTx is not. */ + zone = TT_GMT; + break; + case 'w': case 'W': + if (dotw == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 'd' || rest[2] == 'D')) + dotw = TT_WED; + break; + + case '+': case '-': + { + const char *end; + int sign; + if (zone_offset != -1) + { + /* already got one... */ + rest++; + break; + } + if (zone != TT_UNKNOWN && zone != TT_GMT) + { + /* GMT+0300 is legal, but PST+0300 is not. */ + rest++; + break; + } + + sign = ((*rest == '+') ? 1 : -1); + rest++; /* move over sign */ + end = rest; + while (*end >= '0' && *end <= '9') + end++; + if (rest == end) /* no digits here */ + break; + + if ((end - rest) == 4) + /* offset in HHMM */ + zone_offset = (((((rest[0]-'0')*10) + (rest[1]-'0')) * 60) + + (((rest[2]-'0')*10) + (rest[3]-'0'))); + else if ((end - rest) == 2) + /* offset in hours */ + zone_offset = (((rest[0]-'0')*10) + (rest[1]-'0')) * 60; + else if ((end - rest) == 1) + /* offset in hours */ + zone_offset = (rest[0]-'0') * 60; + else + /* 3 or >4 */ + break; + + zone_offset *= sign; + zone = TT_GMT; + break; + } + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int tmp_hour = -1; + int tmp_min = -1; + int tmp_sec = -1; + const char *end = rest + 1; + while (*end >= '0' && *end <= '9') + end++; + + /* end is now the first character after a range of digits. */ + + if (*end == ':') + { + if (hour >= 0 && min >= 0) /* already got it */ + break; + + /* We have seen "[0-9]+:", so this is probably HH:MM[:SS] */ + if ((end - rest) > 2) + /* it is [0-9][0-9][0-9]+: */ + break; + else if ((end - rest) == 2) + tmp_hour = ((rest[0]-'0')*10 + + (rest[1]-'0')); + else + tmp_hour = (rest[0]-'0'); + + /* move over the colon, and parse minutes */ + + rest = ++end; + while (*end >= '0' && *end <= '9') + end++; + + if (end == rest) + /* no digits after first colon? */ + break; + else if ((end - rest) > 2) + /* it is [0-9][0-9][0-9]+: */ + break; + else if ((end - rest) == 2) + tmp_min = ((rest[0]-'0')*10 + + (rest[1]-'0')); + else + tmp_min = (rest[0]-'0'); + + /* now go for seconds */ + rest = end; + if (*rest == ':') + rest++; + end = rest; + while (*end >= '0' && *end <= '9') + end++; + + if (end == rest) + /* no digits after second colon - that's ok. */ + ; + else if ((end - rest) > 2) + /* it is [0-9][0-9][0-9]+: */ + break; + else if ((end - rest) == 2) + tmp_sec = ((rest[0]-'0')*10 + + (rest[1]-'0')); + else + tmp_sec = (rest[0]-'0'); + + /* If we made it here, we've parsed hour and min, + and possibly sec, so it worked as a unit. */ + + /* skip over whitespace and see if there's an AM or PM + directly following the time. + */ + if (tmp_hour <= 12) + { + const char *s = end; + while (*s && (*s == ' ' || *s == '\t')) + s++; + if ((s[0] == 'p' || s[0] == 'P') && + (s[1] == 'm' || s[1] == 'M')) + /* 10:05pm == 22:05, and 12:05pm == 12:05 */ + tmp_hour = (tmp_hour == 12 ? 12 : tmp_hour + 12); + else if (tmp_hour == 12 && + (s[0] == 'a' || s[0] == 'A') && + (s[1] == 'm' || s[1] == 'M')) + /* 12:05am == 00:05 */ + tmp_hour = 0; + } + + hour = tmp_hour; + min = tmp_min; + sec = tmp_sec; + rest = end; + break; + } + else if ((*end == '/' || *end == '-') && + end[1] >= '0' && end[1] <= '9') + { + /* Perhaps this is 6/16/95, 16/6/95, 6-16-95, or 16-6-95 + or even 95-06-05... + #### But it doesn't handle 1995-06-22. + */ + int n1, n2, n3; + const char *s; + + if (month != TT_UNKNOWN) + /* if we saw a month name, this can't be. */ + break; + + s = rest; + + n1 = (*s++ - '0'); /* first 1 or 2 digits */ + if (*s >= '0' && *s <= '9') + n1 = n1*10 + (*s++ - '0'); + + if (*s != '/' && *s != '-') /* slash */ + break; + s++; + + if (*s < '0' || *s > '9') /* second 1 or 2 digits */ + break; + n2 = (*s++ - '0'); + if (*s >= '0' && *s <= '9') + n2 = n2*10 + (*s++ - '0'); + + if (*s != '/' && *s != '-') /* slash */ + break; + s++; + + if (*s < '0' || *s > '9') /* third 1, 2, 4, or 5 digits */ + break; + n3 = (*s++ - '0'); + if (*s >= '0' && *s <= '9') + n3 = n3*10 + (*s++ - '0'); + + if (*s >= '0' && *s <= '9') /* optional digits 3, 4, and 5 */ + { + n3 = n3*10 + (*s++ - '0'); + if (*s < '0' || *s > '9') + break; + n3 = n3*10 + (*s++ - '0'); + if (*s >= '0' && *s <= '9') + n3 = n3*10 + (*s++ - '0'); + } + + if ((*s >= '0' && *s <= '9') || /* followed by non-alphanum */ + (*s >= 'A' && *s <= 'Z') || + (*s >= 'a' && *s <= 'z')) + break; + + /* Ok, we parsed three 1-2 digit numbers, with / or - + between them. Now decide what the hell they are + (DD/MM/YY or MM/DD/YY or YY/MM/DD.) + */ + + if (n1 > 31 || n1 == 0) /* must be YY/MM/DD */ + { + if (n2 > 12) break; + if (n3 > 31) break; + year = n1; + if (year < 70) + year += 2000; + else if (year < 100) + year += 1900; + month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1); + date = n3; + rest = s; + break; + } + + if (n1 > 12 && n2 > 12) /* illegal */ + { + rest = s; + break; + } + + if (n3 < 70) + n3 += 2000; + else if (n3 < 100) + n3 += 1900; + + if (n1 > 12) /* must be DD/MM/YY */ + { + date = n1; + month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1); + year = n3; + } + else /* assume MM/DD/YY */ + { + /* #### In the ambiguous case, should we consult the + locale to find out the local default? */ + month = (TIME_TOKEN)(n1 + ((int)TT_JAN) - 1); + date = n2; + year = n3; + } + rest = s; + } + else if ((*end >= 'A' && *end <= 'Z') || + (*end >= 'a' && *end <= 'z')) + /* Digits followed by non-punctuation - what's that? */ + ; + else if ((end - rest) == 5) /* five digits is a year */ + year = (year < 0 + ? ((rest[0]-'0')*10000L + + (rest[1]-'0')*1000L + + (rest[2]-'0')*100L + + (rest[3]-'0')*10L + + (rest[4]-'0')) + : year); + else if ((end - rest) == 4) /* four digits is a year */ + year = (year < 0 + ? ((rest[0]-'0')*1000L + + (rest[1]-'0')*100L + + (rest[2]-'0')*10L + + (rest[3]-'0')) + : year); + else if ((end - rest) == 2) /* two digits - date or year */ + { + int n = ((rest[0]-'0')*10 + + (rest[1]-'0')); + /* If we don't have a date (day of the month) and we see a number + less than 32, then assume that is the date. + + Otherwise, if we have a date and not a year, assume this is the + year. If it is less than 70, then assume it refers to the 21st + century. If it is two digits (>= 70), assume it refers to this + century. Otherwise, assume it refers to an unambiguous year. + + The world will surely end soon. + */ + if (date < 0 && n < 32) + date = n; + else if (year < 0) + { + if (n < 70) + year = 2000 + n; + else if (n < 100) + year = 1900 + n; + else + year = n; + } + /* else what the hell is this. */ + } + else if ((end - rest) == 1) /* one digit - date */ + date = (date < 0 ? (rest[0]-'0') : date); + /* else, three or more than five digits - what's that? */ + + break; + } + } + + /* Skip to the end of this token, whether we parsed it or not. + Tokens are delimited by whitespace, or ,;-/ + But explicitly not :+-. + */ + while (*rest && + *rest != ' ' && *rest != '\t' && + *rest != ',' && *rest != ';' && + *rest != '-' && *rest != '+' && + *rest != '/' && + *rest != '(' && *rest != ')' && *rest != '[' && *rest != ']') + rest++; + /* skip over uninteresting chars. */ + SKIP_MORE: + while (*rest && + (*rest == ' ' || *rest == '\t' || + *rest == ',' || *rest == ';' || *rest == '/' || + *rest == '(' || *rest == ')' || *rest == '[' || *rest == ']')) + rest++; + + /* "-" is ignored at the beginning of a token if we have not yet + parsed a year (e.g., the second "-" in "30-AUG-1966"), or if + the character after the dash is not a digit. */ + if (*rest == '-' && ((rest > string && isalpha(rest[-1]) && year < 0) + || rest[1] < '0' || rest[1] > '9')) + { + rest++; + goto SKIP_MORE; + } + + } + + if (zone != TT_UNKNOWN && zone_offset == -1) + { + switch (zone) + { + case TT_PST: zone_offset = -8 * 60; break; + case TT_PDT: zone_offset = -8 * 60; dst_offset = 1 * 60; break; + case TT_MST: zone_offset = -7 * 60; break; + case TT_MDT: zone_offset = -7 * 60; dst_offset = 1 * 60; break; + case TT_CST: zone_offset = -6 * 60; break; + case TT_CDT: zone_offset = -6 * 60; dst_offset = 1 * 60; break; + case TT_EST: zone_offset = -5 * 60; break; + case TT_EDT: zone_offset = -5 * 60; dst_offset = 1 * 60; break; + case TT_AST: zone_offset = -4 * 60; break; + case TT_NST: zone_offset = -3 * 60 - 30; break; + case TT_GMT: zone_offset = 0 * 60; break; + case TT_BST: zone_offset = 0 * 60; dst_offset = 1 * 60; break; + case TT_MET: zone_offset = 1 * 60; break; + case TT_EET: zone_offset = 2 * 60; break; + case TT_JST: zone_offset = 9 * 60; break; + default: + PR_ASSERT (0); + break; + } + } + + /* If we didn't find a year, month, or day-of-the-month, we can't + possibly parse this, and in fact, mktime() will do something random + (I'm seeing it return "Tue Feb 5 06:28:16 2036", which is no doubt + a numerologically significant date... */ + if (month == TT_UNKNOWN || date == -1 || year == -1 || year > PR_INT16_MAX) + return PR_FAILURE; + + memset(result, 0, sizeof(*result)); + if (sec != -1) + result->tm_sec = sec; + if (min != -1) + result->tm_min = min; + if (hour != -1) + result->tm_hour = hour; + if (date != -1) + result->tm_mday = date; + if (month != TT_UNKNOWN) + result->tm_month = (((int)month) - ((int)TT_JAN)); + if (year != -1) + result->tm_year = year; + if (dotw != TT_UNKNOWN) + result->tm_wday = (((int)dotw) - ((int)TT_SUN)); + + if (zone == TT_UNKNOWN && default_to_gmt) + { + /* No zone was specified, so pretend the zone was GMT. */ + zone = TT_GMT; + zone_offset = 0; + } + + if (zone_offset == -1) + { + /* no zone was specified, and we're to assume that everything + is local. */ + struct tm localTime; + time_t secs; + + PR_ASSERT(result->tm_month > -1 && + result->tm_mday > 0 && + result->tm_hour > -1 && + result->tm_min > -1 && + result->tm_sec > -1); + + /* + * To obtain time_t from a tm structure representing the local + * time, we call mktime(). However, we need to see if we are + * on 1-Jan-1970 or before. If we are, we can't call mktime() + * because mktime() will crash on win16. In that case, we + * calculate zone_offset based on the zone offset at + * 00:00:00, 2 Jan 1970 GMT, and subtract zone_offset from the + * date we are parsing to transform the date to GMT. We also + * do so if mktime() returns (time_t) -1 (time out of range). + */ + + /* month, day, hours, mins and secs are always non-negative + so we dont need to worry about them. */ + if(result->tm_year >= 1970) + { + PRInt64 usec_per_sec; + + localTime.tm_sec = result->tm_sec; + localTime.tm_min = result->tm_min; + localTime.tm_hour = result->tm_hour; + localTime.tm_mday = result->tm_mday; + localTime.tm_mon = result->tm_month; + localTime.tm_year = result->tm_year - 1900; + /* Set this to -1 to tell mktime "I don't care". If you set + it to 0 or 1, you are making assertions about whether the + date you are handing it is in daylight savings mode or not; + and if you're wrong, it will "fix" it for you. */ + localTime.tm_isdst = -1; + secs = mktime(&localTime); + if (secs != (time_t) -1) + { + PRTime usecs64; + LL_I2L(usecs64, secs); + LL_I2L(usec_per_sec, PR_USEC_PER_SEC); + LL_MUL(usecs64, usecs64, usec_per_sec); + PR_ExplodeTime(usecs64, PR_LocalTimeParameters, result); + return PR_SUCCESS; + } + } + + /* So mktime() can't handle this case. We assume the + zone_offset for the date we are parsing is the same as + the zone offset on 00:00:00 2 Jan 1970 GMT. */ + secs = 86400; + (void) MT_safe_localtime(&secs, &localTime); + zone_offset = localTime.tm_min + + 60 * localTime.tm_hour + + 1440 * (localTime.tm_mday - 2); + } + + /* mainly to compute wday and yday */ + PR_NormalizeTime(result, PR_GMTParameters); + result->tm_params.tp_gmt_offset = zone_offset * 60; + result->tm_params.tp_dst_offset = dst_offset * 60; + + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) +PR_ParseTimeString( + const char *string, + PRBool default_to_gmt, + PRTime *result) +{ + PRExplodedTime tm; + PRStatus rv; + + rv = PR_ParseTimeStringToExplodedTime(string, + default_to_gmt, + &tm); + if (rv != PR_SUCCESS) + return rv; + + *result = PR_ImplodeTime(&tm); + + return PR_SUCCESS; +} + +/* + ******************************************************************* + ******************************************************************* + ** + ** OLD COMPATIBILITY FUNCTIONS + ** + ******************************************************************* + ******************************************************************* + */ + + +/* + *----------------------------------------------------------------------- + * + * PR_FormatTime -- + * + * Format a time value into a buffer. Same semantics as strftime(). + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRUint32) +PR_FormatTime(char *buf, int buflen, const char *fmt, const PRExplodedTime *tm) +{ + struct tm a; + a.tm_sec = tm->tm_sec; + a.tm_min = tm->tm_min; + a.tm_hour = tm->tm_hour; + a.tm_mday = tm->tm_mday; + a.tm_mon = tm->tm_month; + a.tm_wday = tm->tm_wday; + a.tm_year = tm->tm_year - 1900; + a.tm_yday = tm->tm_yday; + a.tm_isdst = tm->tm_params.tp_dst_offset ? 1 : 0; + +/* + * On some platforms, for example SunOS 4, struct tm has two additional + * fields: tm_zone and tm_gmtoff. + */ + +#if defined(SUNOS4) || (__GLIBC__ >= 2) || defined(XP_BEOS) \ + || defined(NETBSD) || defined(OPENBSD) || defined(FREEBSD) \ + || defined(DARWIN) + a.tm_zone = NULL; + a.tm_gmtoff = tm->tm_params.tp_gmt_offset + tm->tm_params.tp_dst_offset; +#endif + + return strftime(buf, buflen, fmt, &a); +} + + +/* + * The following string arrays and macros are used by PR_FormatTimeUSEnglish(). + */ + +static const char* abbrevDays[] = +{ + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" +}; + +static const char* days[] = +{ + "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday" +}; + +static const char* abbrevMonths[] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static const char* months[] = +{ + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" +}; + + +/* + * Add a single character to the given buffer, incrementing the buffer pointer + * and decrementing the buffer size. Return 0 on error. + */ +#define ADDCHAR( buf, bufSize, ch ) \ +do \ +{ \ + if( bufSize < 1 ) \ + { \ + *(--buf) = '\0'; \ + return 0; \ + } \ + *buf++ = ch; \ + bufSize--; \ +} \ +while(0) + + +/* + * Add a string to the given buffer, incrementing the buffer pointer + * and decrementing the buffer size appropriately. Return 0 on error. + */ +#define ADDSTR( buf, bufSize, str ) \ +do \ +{ \ + PRUint32 strSize = strlen( str ); \ + if( strSize > bufSize ) \ + { \ + if( bufSize==0 ) \ + *(--buf) = '\0'; \ + else \ + *buf = '\0'; \ + return 0; \ + } \ + memcpy(buf, str, strSize); \ + buf += strSize; \ + bufSize -= strSize; \ +} \ +while(0) + +/* Needed by PR_FormatTimeUSEnglish() */ +static unsigned int pr_WeekOfYear(const PRExplodedTime* time, + unsigned int firstDayOfWeek); + + +/*********************************************************************************** + * + * Description: + * This is a dumbed down version of strftime that will format the date in US + * English regardless of the setting of the global locale. This functionality is + * needed to write things like MIME headers which must always be in US English. + * + **********************************************************************************/ + +PR_IMPLEMENT(PRUint32) +PR_FormatTimeUSEnglish( char* buf, PRUint32 bufSize, + const char* format, const PRExplodedTime* time ) +{ + char* bufPtr = buf; + const char* fmtPtr; + char tmpBuf[ 40 ]; + const int tmpBufSize = sizeof( tmpBuf ); + + + for( fmtPtr=format; *fmtPtr != '\0'; fmtPtr++ ) + { + if( *fmtPtr != '%' ) + { + ADDCHAR( bufPtr, bufSize, *fmtPtr ); + } + else + { + switch( *(++fmtPtr) ) + { + case '%': + /* escaped '%' character */ + ADDCHAR( bufPtr, bufSize, '%' ); + break; + + case 'a': + /* abbreviated weekday name */ + ADDSTR( bufPtr, bufSize, abbrevDays[ time->tm_wday ] ); + break; + + case 'A': + /* full weekday name */ + ADDSTR( bufPtr, bufSize, days[ time->tm_wday ] ); + break; + + case 'b': + /* abbreviated month name */ + ADDSTR( bufPtr, bufSize, abbrevMonths[ time->tm_month ] ); + break; + + case 'B': + /* full month name */ + ADDSTR(bufPtr, bufSize, months[ time->tm_month ] ); + break; + + case 'c': + /* Date and time. */ + PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%a %b %d %H:%M:%S %Y", time ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'd': + /* day of month ( 01 - 31 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_mday ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'H': + /* hour ( 00 - 23 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_hour ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'I': + /* hour ( 01 - 12 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld", + (time->tm_hour%12) ? time->tm_hour%12 : (PRInt32) 12 ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'j': + /* day number of year ( 001 - 366 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.3d",time->tm_yday + 1); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'm': + /* month number ( 01 - 12 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_month+1); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'M': + /* minute ( 00 - 59 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_min ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'p': + /* locale's equivalent of either AM or PM */ + ADDSTR( bufPtr, bufSize, (time->tm_hour<12)?"AM":"PM" ); + break; + + case 'S': + /* seconds ( 00 - 61 ), allows for leap seconds */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_sec ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'U': + /* week number of year ( 00 - 53 ), Sunday is the first day of week 1 */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 0 ) ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'w': + /* weekday number ( 0 - 6 ), Sunday = 0 */ + PR_snprintf(tmpBuf,tmpBufSize,"%d",time->tm_wday ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'W': + /* Week number of year ( 00 - 53 ), Monday is the first day of week 1 */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 1 ) ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'x': + /* Date representation */ + PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%m/%d/%y", time ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'X': + /* Time representation. */ + PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%H:%M:%S", time ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'y': + /* year within century ( 00 - 99 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_year % 100 ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'Y': + /* year as ccyy ( for example 1986 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.4d",time->tm_year ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'Z': + /* Time zone name or no characters if no time zone exists. + * Since time zone name is supposed to be independant of locale, we + * defer to PR_FormatTime() for this option. + */ + PR_FormatTime( tmpBuf, tmpBufSize, "%Z", time ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + default: + /* Unknown format. Simply copy format into output buffer. */ + ADDCHAR( bufPtr, bufSize, '%' ); + ADDCHAR( bufPtr, bufSize, *fmtPtr ); + break; + + } + } + } + + ADDCHAR( bufPtr, bufSize, '\0' ); + return (PRUint32)(bufPtr - buf - 1); +} + + + +/*********************************************************************************** + * + * Description: + * Returns the week number of the year (0-53) for the given time. firstDayOfWeek + * is the day on which the week is considered to start (0=Sun, 1=Mon, ...). + * Week 1 starts the first time firstDayOfWeek occurs in the year. In other words, + * a partial week at the start of the year is considered week 0. + * + **********************************************************************************/ + +static unsigned int +pr_WeekOfYear(const PRExplodedTime* time, unsigned int firstDayOfWeek) +{ + int dayOfWeek; + int dayOfYear; + + /* Get the day of the year for the given time then adjust it to represent the + * first day of the week containing the given time. + */ + dayOfWeek = time->tm_wday - firstDayOfWeek; + if (dayOfWeek < 0) + dayOfWeek += 7; + + dayOfYear = time->tm_yday - dayOfWeek; + + + if( dayOfYear <= 0 ) + { + /* If dayOfYear is <= 0, it is in the first partial week of the year. */ + return 0; + } + else + { + /* Count the number of full weeks ( dayOfYear / 7 ) then add a week if there + * are any days left over ( dayOfYear % 7 ). Because we are only counting to + * the first day of the week containing the given time, rather than to the + * actual day representing the given time, any days in week 0 will be "absorbed" + * as extra days in the given week. + */ + return (dayOfYear / 7) + ( (dayOfYear % 7) == 0 ? 0 : 1 ); + } +} + diff --git a/nsprpub/pr/src/misc/prtpool.c b/nsprpub/pr/src/misc/prtpool.c new file mode 100644 index 00000000000..e23bb9d014f --- /dev/null +++ b/nsprpub/pr/src/misc/prtpool.c @@ -0,0 +1,1219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" + +/* + * Thread pools + * Thread pools create and manage threads to provide support for + * scheduling jobs onto one or more threads. + * + */ +#ifdef OPT_WINNT +#include +#endif + +/* + * worker thread + */ +typedef struct wthread { + PRCList links; + PRThread *thread; +} wthread; + +/* + * queue of timer jobs + */ +typedef struct timer_jobq { + PRCList list; + PRLock *lock; + PRCondVar *cv; + PRInt32 cnt; + PRCList wthreads; +} timer_jobq; + +/* + * queue of jobs + */ +typedef struct tp_jobq { + PRCList list; + PRInt32 cnt; + PRLock *lock; + PRCondVar *cv; + PRCList wthreads; +#ifdef OPT_WINNT + HANDLE nt_completion_port; +#endif +} tp_jobq; + +/* + * queue of IO jobs + */ +typedef struct io_jobq { + PRCList list; + PRPollDesc *pollfds; + PRInt32 npollfds; + PRJob **polljobs; + PRLock *lock; + PRInt32 cnt; + PRFileDesc *notify_fd; + PRCList wthreads; +} io_jobq; + +/* + * Threadpool + */ +struct PRThreadPool { + PRInt32 init_threads; + PRInt32 max_threads; + PRInt32 current_threads; + PRInt32 idle_threads; + PRUint32 stacksize; + tp_jobq jobq; + io_jobq ioq; + timer_jobq timerq; + PRLock *join_lock; /* used with jobp->join_cv */ + PRCondVar *shutdown_cv; + PRBool shutdown; +}; + +typedef enum io_op_type + { JOB_IO_READ, JOB_IO_WRITE, JOB_IO_CONNECT, JOB_IO_ACCEPT } io_op_type; + +#ifdef OPT_WINNT +typedef struct NT_notifier { + OVERLAPPED overlapped; /* must be first */ + PRJob *jobp; +} NT_notifier; +#endif + +struct PRJob { + PRCList links; /* for linking jobs */ + PRBool on_ioq; /* job on ioq */ + PRBool on_timerq; /* job on timerq */ + PRJobFn job_func; + void *job_arg; + PRCondVar *join_cv; + PRBool join_wait; /* == PR_TRUE, when waiting to join */ + PRCondVar *cancel_cv; /* for cancelling IO jobs */ + PRBool cancel_io; /* for cancelling IO jobs */ + PRThreadPool *tpool; /* back pointer to thread pool */ + PRJobIoDesc *iod; + io_op_type io_op; + PRInt16 io_poll_flags; + PRNetAddr *netaddr; + PRIntervalTime timeout; /* relative value */ + PRIntervalTime absolute; +#ifdef OPT_WINNT + NT_notifier nt_notifier; +#endif +}; + +#define JOB_LINKS_PTR(_qp) \ + ((PRJob *) ((char *) (_qp) - offsetof(PRJob, links))) + +#define WTHREAD_LINKS_PTR(_qp) \ + ((wthread *) ((char *) (_qp) - offsetof(wthread, links))) + +#define JOINABLE_JOB(_jobp) (NULL != (_jobp)->join_cv) + +#define JOIN_NOTIFY(_jobp) \ + PR_BEGIN_MACRO \ + PR_Lock(_jobp->tpool->join_lock); \ + _jobp->join_wait = PR_FALSE; \ + PR_NotifyCondVar(_jobp->join_cv); \ + PR_Unlock(_jobp->tpool->join_lock); \ + PR_END_MACRO + +#define CANCEL_IO_JOB(jobp) \ + PR_BEGIN_MACRO \ + jobp->cancel_io = PR_FALSE; \ + jobp->on_ioq = PR_FALSE; \ + PR_REMOVE_AND_INIT_LINK(&jobp->links); \ + tp->ioq.cnt--; \ + PR_NotifyCondVar(jobp->cancel_cv); \ + PR_END_MACRO + +static void delete_job(PRJob *jobp); +static PRThreadPool * alloc_threadpool(void); +static PRJob * alloc_job(PRBool joinable, PRThreadPool *tp); +static void notify_ioq(PRThreadPool *tp); +static void notify_timerq(PRThreadPool *tp); + +/* + * locks are acquired in the following order + * + * tp->ioq.lock,tp->timerq.lock + * | + * V + * tp->jobq->lock + */ + +/* + * worker thread function + */ +static void wstart(void *arg) +{ +PRThreadPool *tp = (PRThreadPool *) arg; +PRCList *head; + + /* + * execute jobs until shutdown + */ + while (!tp->shutdown) { + PRJob *jobp; +#ifdef OPT_WINNT + BOOL rv; + DWORD unused, shutdown; + LPOVERLAPPED olp; + + PR_Lock(tp->jobq.lock); + tp->idle_threads++; + PR_Unlock(tp->jobq.lock); + rv = GetQueuedCompletionStatus(tp->jobq.nt_completion_port, + &unused, &shutdown, &olp, INFINITE); + + PR_ASSERT(rv); + if (shutdown) + break; + jobp = ((NT_notifier *) olp)->jobp; + PR_Lock(tp->jobq.lock); + tp->idle_threads--; + tp->jobq.cnt--; + PR_Unlock(tp->jobq.lock); +#else + + PR_Lock(tp->jobq.lock); + while (PR_CLIST_IS_EMPTY(&tp->jobq.list) && (!tp->shutdown)) { + tp->idle_threads++; + PR_WaitCondVar(tp->jobq.cv, PR_INTERVAL_NO_TIMEOUT); + tp->idle_threads--; + } + if (tp->shutdown) { + PR_Unlock(tp->jobq.lock); + break; + } + head = PR_LIST_HEAD(&tp->jobq.list); + /* + * remove job from queue + */ + PR_REMOVE_AND_INIT_LINK(head); + tp->jobq.cnt--; + jobp = JOB_LINKS_PTR(head); + PR_Unlock(tp->jobq.lock); +#endif + + jobp->job_func(jobp->job_arg); + if (!JOINABLE_JOB(jobp)) { + delete_job(jobp); + } else { + JOIN_NOTIFY(jobp); + } + } + PR_Lock(tp->jobq.lock); + tp->current_threads--; + PR_Unlock(tp->jobq.lock); +} + +/* + * add a job to the work queue + */ +static void +add_to_jobq(PRThreadPool *tp, PRJob *jobp) +{ + /* + * add to jobq + */ +#ifdef OPT_WINNT + PR_Lock(tp->jobq.lock); + tp->jobq.cnt++; + PR_Unlock(tp->jobq.lock); + /* + * notify worker thread(s) + */ + PostQueuedCompletionStatus(tp->jobq.nt_completion_port, 0, + FALSE, &jobp->nt_notifier.overlapped); +#else + PR_Lock(tp->jobq.lock); + PR_APPEND_LINK(&jobp->links,&tp->jobq.list); + tp->jobq.cnt++; + if ((tp->idle_threads < tp->jobq.cnt) && + (tp->current_threads < tp->max_threads)) { + wthread *wthrp; + /* + * increment thread count and unlock the jobq lock + */ + tp->current_threads++; + PR_Unlock(tp->jobq.lock); + /* create new worker thread */ + wthrp = PR_NEWZAP(wthread); + if (wthrp) { + wthrp->thread = PR_CreateThread(PR_USER_THREAD, wstart, + tp, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,tp->stacksize); + if (NULL == wthrp->thread) { + PR_DELETE(wthrp); /* this sets wthrp to NULL */ + } + } + PR_Lock(tp->jobq.lock); + if (NULL == wthrp) { + tp->current_threads--; + } else { + PR_APPEND_LINK(&wthrp->links, &tp->jobq.wthreads); + } + } + /* + * wakeup a worker thread + */ + PR_NotifyCondVar(tp->jobq.cv); + PR_Unlock(tp->jobq.lock); +#endif +} + +/* + * io worker thread function + */ +static void io_wstart(void *arg) +{ +PRThreadPool *tp = (PRThreadPool *) arg; +int pollfd_cnt, pollfds_used; +int rv; +PRCList *qp, *nextqp; +PRPollDesc *pollfds; +PRJob **polljobs; +int poll_timeout; +PRIntervalTime now; + + /* + * scan io_jobq + * construct poll list + * call PR_Poll + * for all fds, for which poll returns true, move the job to + * jobq and wakeup worker thread. + */ + while (!tp->shutdown) { + PRJob *jobp; + + pollfd_cnt = tp->ioq.cnt + 10; + if (pollfd_cnt > tp->ioq.npollfds) { + + /* + * re-allocate pollfd array if the current one is not large + * enough + */ + if (NULL != tp->ioq.pollfds) + PR_Free(tp->ioq.pollfds); + tp->ioq.pollfds = (PRPollDesc *) PR_Malloc(pollfd_cnt * + (sizeof(PRPollDesc) + sizeof(PRJob *))); + PR_ASSERT(NULL != tp->ioq.pollfds); + /* + * array of pollfds + */ + pollfds = tp->ioq.pollfds; + tp->ioq.polljobs = (PRJob **) (&tp->ioq.pollfds[pollfd_cnt]); + /* + * parallel array of jobs + */ + polljobs = tp->ioq.polljobs; + tp->ioq.npollfds = pollfd_cnt; + } + + pollfds_used = 0; + /* + * add the notify fd; used for unblocking io thread(s) + */ + pollfds[pollfds_used].fd = tp->ioq.notify_fd; + pollfds[pollfds_used].in_flags = PR_POLL_READ; + pollfds[pollfds_used].out_flags = 0; + polljobs[pollfds_used] = NULL; + pollfds_used++; + /* + * fill in the pollfd array + */ + PR_Lock(tp->ioq.lock); + for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) { + nextqp = qp->next; + jobp = JOB_LINKS_PTR(qp); + if (jobp->cancel_io) { + CANCEL_IO_JOB(jobp); + continue; + } + if (pollfds_used == (pollfd_cnt)) + break; + pollfds[pollfds_used].fd = jobp->iod->socket; + pollfds[pollfds_used].in_flags = jobp->io_poll_flags; + pollfds[pollfds_used].out_flags = 0; + polljobs[pollfds_used] = jobp; + + pollfds_used++; + } + if (!PR_CLIST_IS_EMPTY(&tp->ioq.list)) { + qp = tp->ioq.list.next; + jobp = JOB_LINKS_PTR(qp); + if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout) + poll_timeout = PR_INTERVAL_NO_TIMEOUT; + else if (PR_INTERVAL_NO_WAIT == jobp->timeout) + poll_timeout = PR_INTERVAL_NO_WAIT; + else { + poll_timeout = jobp->absolute - PR_IntervalNow(); + if (poll_timeout <= 0) /* already timed out */ + poll_timeout = PR_INTERVAL_NO_WAIT; + } + } else { + poll_timeout = PR_INTERVAL_NO_TIMEOUT; + } + PR_Unlock(tp->ioq.lock); + + /* + * XXXX + * should retry if more jobs have been added to the queue? + * + */ + PR_ASSERT(pollfds_used <= pollfd_cnt); + rv = PR_Poll(tp->ioq.pollfds, pollfds_used, poll_timeout); + + if (tp->shutdown) { + break; + } + + if (rv > 0) { + /* + * at least one io event is set + */ + PRStatus rval_status; + PRInt32 index; + + PR_ASSERT(pollfds[0].fd == tp->ioq.notify_fd); + /* + * reset the pollable event, if notified + */ + if (pollfds[0].out_flags & PR_POLL_READ) { + rval_status = PR_WaitForPollableEvent(tp->ioq.notify_fd); + PR_ASSERT(PR_SUCCESS == rval_status); + } + + for(index = 1; index < (pollfds_used); index++) { + PRInt16 events = pollfds[index].in_flags; + PRInt16 revents = pollfds[index].out_flags; + jobp = polljobs[index]; + + if ((revents & PR_POLL_NVAL) || /* busted in all cases */ + (revents & PR_POLL_ERR) || + ((events & PR_POLL_WRITE) && + (revents & PR_POLL_HUP))) { /* write op & hup */ + PR_Lock(tp->ioq.lock); + if (jobp->cancel_io) { + CANCEL_IO_JOB(jobp); + PR_Unlock(tp->ioq.lock); + continue; + } + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->ioq.cnt--; + jobp->on_ioq = PR_FALSE; + PR_Unlock(tp->ioq.lock); + + /* set error */ + if (PR_POLL_NVAL & revents) + jobp->iod->error = PR_BAD_DESCRIPTOR_ERROR; + else if (PR_POLL_HUP & revents) + jobp->iod->error = PR_CONNECT_RESET_ERROR; + else + jobp->iod->error = PR_IO_ERROR; + + /* + * add to jobq + */ + add_to_jobq(tp, jobp); + } else if (revents) { + /* + * add to jobq + */ + PR_Lock(tp->ioq.lock); + if (jobp->cancel_io) { + CANCEL_IO_JOB(jobp); + PR_Unlock(tp->ioq.lock); + continue; + } + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->ioq.cnt--; + jobp->on_ioq = PR_FALSE; + PR_Unlock(tp->ioq.lock); + + if (jobp->io_op == JOB_IO_CONNECT) { + if (PR_GetConnectStatus(&pollfds[index]) == PR_SUCCESS) + jobp->iod->error = 0; + else + jobp->iod->error = PR_GetError(); + } else + jobp->iod->error = 0; + + add_to_jobq(tp, jobp); + } + } + } + /* + * timeout processing + */ + now = PR_IntervalNow(); + PR_Lock(tp->ioq.lock); + for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) { + nextqp = qp->next; + jobp = JOB_LINKS_PTR(qp); + if (jobp->cancel_io) { + CANCEL_IO_JOB(jobp); + continue; + } + if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout) + break; + if ((PR_INTERVAL_NO_WAIT != jobp->timeout) && + ((PRInt32)(jobp->absolute - now) > 0)) + break; + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->ioq.cnt--; + jobp->on_ioq = PR_FALSE; + jobp->iod->error = PR_IO_TIMEOUT_ERROR; + add_to_jobq(tp, jobp); + } + PR_Unlock(tp->ioq.lock); + } +} + +/* + * timer worker thread function + */ +static void timer_wstart(void *arg) +{ +PRThreadPool *tp = (PRThreadPool *) arg; +PRCList *qp; +PRIntervalTime timeout; +PRIntervalTime now; + + /* + * call PR_WaitCondVar with minimum value of all timeouts + */ + while (!tp->shutdown) { + PRJob *jobp; + + PR_Lock(tp->timerq.lock); + if (PR_CLIST_IS_EMPTY(&tp->timerq.list)) { + timeout = PR_INTERVAL_NO_TIMEOUT; + } else { + PRCList *qp; + + qp = tp->timerq.list.next; + jobp = JOB_LINKS_PTR(qp); + + timeout = jobp->absolute - PR_IntervalNow(); + if (timeout <= 0) + timeout = PR_INTERVAL_NO_WAIT; /* already timed out */ + } + if (PR_INTERVAL_NO_WAIT != timeout) + PR_WaitCondVar(tp->timerq.cv, timeout); + if (tp->shutdown) { + PR_Unlock(tp->timerq.lock); + break; + } + /* + * move expired-timer jobs to jobq + */ + now = PR_IntervalNow(); + while (!PR_CLIST_IS_EMPTY(&tp->timerq.list)) { + qp = tp->timerq.list.next; + jobp = JOB_LINKS_PTR(qp); + + if ((PRInt32)(jobp->absolute - now) > 0) { + break; + } + /* + * job timed out + */ + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->timerq.cnt--; + jobp->on_timerq = PR_FALSE; + add_to_jobq(tp, jobp); + } + PR_Unlock(tp->timerq.lock); + } +} + +static void +delete_threadpool(PRThreadPool *tp) +{ + if (NULL != tp) { + if (NULL != tp->shutdown_cv) + PR_DestroyCondVar(tp->shutdown_cv); + if (NULL != tp->jobq.cv) + PR_DestroyCondVar(tp->jobq.cv); + if (NULL != tp->jobq.lock) + PR_DestroyLock(tp->jobq.lock); + if (NULL != tp->join_lock) + PR_DestroyLock(tp->join_lock); +#ifdef OPT_WINNT + if (NULL != tp->jobq.nt_completion_port) + CloseHandle(tp->jobq.nt_completion_port); +#endif + /* Timer queue */ + if (NULL != tp->timerq.cv) + PR_DestroyCondVar(tp->timerq.cv); + if (NULL != tp->timerq.lock) + PR_DestroyLock(tp->timerq.lock); + + if (NULL != tp->ioq.lock) + PR_DestroyLock(tp->ioq.lock); + if (NULL != tp->ioq.pollfds) + PR_Free(tp->ioq.pollfds); + if (NULL != tp->ioq.notify_fd) + PR_DestroyPollableEvent(tp->ioq.notify_fd); + PR_Free(tp); + } + return; +} + +static PRThreadPool * +alloc_threadpool(void) +{ +PRThreadPool *tp; + + tp = (PRThreadPool *) PR_CALLOC(sizeof(*tp)); + if (NULL == tp) + goto failed; + tp->jobq.lock = PR_NewLock(); + if (NULL == tp->jobq.lock) + goto failed; + tp->jobq.cv = PR_NewCondVar(tp->jobq.lock); + if (NULL == tp->jobq.cv) + goto failed; + tp->join_lock = PR_NewLock(); + if (NULL == tp->join_lock) + goto failed; +#ifdef OPT_WINNT + tp->jobq.nt_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, + NULL, 0, 0); + if (NULL == tp->jobq.nt_completion_port) + goto failed; +#endif + + tp->ioq.lock = PR_NewLock(); + if (NULL == tp->ioq.lock) + goto failed; + + /* Timer queue */ + + tp->timerq.lock = PR_NewLock(); + if (NULL == tp->timerq.lock) + goto failed; + tp->timerq.cv = PR_NewCondVar(tp->timerq.lock); + if (NULL == tp->timerq.cv) + goto failed; + + tp->shutdown_cv = PR_NewCondVar(tp->jobq.lock); + if (NULL == tp->shutdown_cv) + goto failed; + tp->ioq.notify_fd = PR_NewPollableEvent(); + if (NULL == tp->ioq.notify_fd) + goto failed; + return tp; +failed: + delete_threadpool(tp); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; +} + +/* Create thread pool */ +PR_IMPLEMENT(PRThreadPool *) +PR_CreateThreadPool(PRInt32 initial_threads, PRInt32 max_threads, + PRUint32 stacksize) +{ +PRThreadPool *tp; +PRThread *thr; +int i; +wthread *wthrp; + + tp = alloc_threadpool(); + if (NULL == tp) + return NULL; + + tp->init_threads = initial_threads; + tp->max_threads = max_threads; + tp->stacksize = stacksize; + PR_INIT_CLIST(&tp->jobq.list); + PR_INIT_CLIST(&tp->ioq.list); + PR_INIT_CLIST(&tp->timerq.list); + PR_INIT_CLIST(&tp->jobq.wthreads); + PR_INIT_CLIST(&tp->ioq.wthreads); + PR_INIT_CLIST(&tp->timerq.wthreads); + tp->shutdown = PR_FALSE; + + PR_Lock(tp->jobq.lock); + for(i=0; i < initial_threads; ++i) { + + thr = PR_CreateThread(PR_USER_THREAD, wstart, + tp, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,stacksize); + PR_ASSERT(thr); + wthrp = PR_NEWZAP(wthread); + PR_ASSERT(wthrp); + wthrp->thread = thr; + PR_APPEND_LINK(&wthrp->links, &tp->jobq.wthreads); + } + tp->current_threads = initial_threads; + + thr = PR_CreateThread(PR_USER_THREAD, io_wstart, + tp, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,stacksize); + PR_ASSERT(thr); + wthrp = PR_NEWZAP(wthread); + PR_ASSERT(wthrp); + wthrp->thread = thr; + PR_APPEND_LINK(&wthrp->links, &tp->ioq.wthreads); + + thr = PR_CreateThread(PR_USER_THREAD, timer_wstart, + tp, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,stacksize); + PR_ASSERT(thr); + wthrp = PR_NEWZAP(wthread); + PR_ASSERT(wthrp); + wthrp->thread = thr; + PR_APPEND_LINK(&wthrp->links, &tp->timerq.wthreads); + + PR_Unlock(tp->jobq.lock); + return tp; +} + +static void +delete_job(PRJob *jobp) +{ + if (NULL != jobp) { + if (NULL != jobp->join_cv) { + PR_DestroyCondVar(jobp->join_cv); + jobp->join_cv = NULL; + } + if (NULL != jobp->cancel_cv) { + PR_DestroyCondVar(jobp->cancel_cv); + jobp->cancel_cv = NULL; + } + PR_DELETE(jobp); + } +} + +static PRJob * +alloc_job(PRBool joinable, PRThreadPool *tp) +{ + PRJob *jobp; + + jobp = PR_NEWZAP(PRJob); + if (NULL == jobp) + goto failed; + if (joinable) { + jobp->join_cv = PR_NewCondVar(tp->join_lock); + jobp->join_wait = PR_TRUE; + if (NULL == jobp->join_cv) + goto failed; + } else { + jobp->join_cv = NULL; + } +#ifdef OPT_WINNT + jobp->nt_notifier.jobp = jobp; +#endif + return jobp; +failed: + delete_job(jobp); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; +} + +/* queue a job */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob(PRThreadPool *tpool, PRJobFn fn, void *arg, PRBool joinable) +{ + PRJob *jobp; + + jobp = alloc_job(joinable, tpool); + if (NULL == jobp) + return NULL; + + jobp->job_func = fn; + jobp->job_arg = arg; + jobp->tpool = tpool; + + add_to_jobq(tpool, jobp); + return jobp; +} + +/* queue a job, when a socket is readable or writeable */ +static PRJob * +queue_io_job(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg, + PRBool joinable, io_op_type op) +{ + PRJob *jobp; + PRIntervalTime now; + + jobp = alloc_job(joinable, tpool); + if (NULL == jobp) { + return NULL; + } + + /* + * Add a new job to io_jobq + * wakeup io worker thread + */ + + jobp->job_func = fn; + jobp->job_arg = arg; + jobp->tpool = tpool; + jobp->iod = iod; + if (JOB_IO_READ == op) { + jobp->io_op = JOB_IO_READ; + jobp->io_poll_flags = PR_POLL_READ; + } else if (JOB_IO_WRITE == op) { + jobp->io_op = JOB_IO_WRITE; + jobp->io_poll_flags = PR_POLL_WRITE; + } else if (JOB_IO_ACCEPT == op) { + jobp->io_op = JOB_IO_ACCEPT; + jobp->io_poll_flags = PR_POLL_READ; + } else if (JOB_IO_CONNECT == op) { + jobp->io_op = JOB_IO_CONNECT; + jobp->io_poll_flags = PR_POLL_WRITE|PR_POLL_EXCEPT; + } else { + delete_job(jobp); + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + + jobp->timeout = iod->timeout; + if ((PR_INTERVAL_NO_TIMEOUT == iod->timeout) || + (PR_INTERVAL_NO_WAIT == iod->timeout)) { + jobp->absolute = iod->timeout; + } else { + now = PR_IntervalNow(); + jobp->absolute = now + iod->timeout; + } + + + PR_Lock(tpool->ioq.lock); + + if (PR_CLIST_IS_EMPTY(&tpool->ioq.list) || + (PR_INTERVAL_NO_TIMEOUT == iod->timeout)) { + PR_APPEND_LINK(&jobp->links,&tpool->ioq.list); + } else if (PR_INTERVAL_NO_WAIT == iod->timeout) { + PR_INSERT_LINK(&jobp->links,&tpool->ioq.list); + } else { + PRCList *qp; + PRJob *tmp_jobp; + /* + * insert into the timeout-sorted ioq + */ + for (qp = tpool->ioq.list.prev; qp != &tpool->ioq.list; + qp = qp->prev) { + tmp_jobp = JOB_LINKS_PTR(qp); + if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { + break; + } + } + PR_INSERT_AFTER(&jobp->links,qp); + } + + jobp->on_ioq = PR_TRUE; + tpool->ioq.cnt++; + /* + * notify io worker thread(s) + */ + PR_Unlock(tpool->ioq.lock); + notify_ioq(tpool); + return jobp; +} + +/* queue a job, when a socket is readable */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Read(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg, + PRBool joinable) +{ + return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_READ)); +} + +/* queue a job, when a socket is writeable */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Write(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn,void * arg, + PRBool joinable) +{ + return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_WRITE)); +} + + +/* queue a job, when a socket has a pending connection */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Accept(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, + void * arg, PRBool joinable) +{ + return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_ACCEPT)); +} + +/* queue a job, when a socket can be connected */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Connect(PRThreadPool *tpool, PRJobIoDesc *iod, + const PRNetAddr *addr, PRJobFn fn, void * arg, PRBool joinable) +{ + PRStatus rv; + PRErrorCode err; + + rv = PR_Connect(iod->socket, addr, PR_INTERVAL_NO_WAIT); + if ((rv == PR_FAILURE) && ((err = PR_GetError()) == PR_IN_PROGRESS_ERROR)){ + /* connection pending */ + return(queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_CONNECT)); + } else { + /* + * connection succeeded or failed; add to jobq right away + */ + if (rv == PR_FAILURE) + iod->error = err; + else + iod->error = 0; + return(PR_QueueJob(tpool, fn, arg, joinable)); + } +} + +/* queue a job, when a timer expires */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, + PRJobFn fn, void * arg, PRBool joinable) +{ + PRIntervalTime now; + PRJob *jobp; + + if (PR_INTERVAL_NO_TIMEOUT == timeout) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + if (PR_INTERVAL_NO_WAIT == timeout) { + /* + * no waiting; add to jobq right away + */ + return(PR_QueueJob(tpool, fn, arg, joinable)); + } + jobp = alloc_job(joinable, tpool); + if (NULL == jobp) { + return NULL; + } + + /* + * Add a new job to timer_jobq + * wakeup timer worker thread + */ + + jobp->job_func = fn; + jobp->job_arg = arg; + jobp->tpool = tpool; + jobp->timeout = timeout; + + now = PR_IntervalNow(); + jobp->absolute = now + timeout; + + + PR_Lock(tpool->timerq.lock); + jobp->on_timerq = PR_TRUE; + if (PR_CLIST_IS_EMPTY(&tpool->timerq.list)) + PR_APPEND_LINK(&jobp->links,&tpool->timerq.list); + else { + PRCList *qp; + PRJob *tmp_jobp; + /* + * insert into the sorted timer jobq + */ + for (qp = tpool->timerq.list.prev; qp != &tpool->timerq.list; + qp = qp->prev) { + tmp_jobp = JOB_LINKS_PTR(qp); + if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { + break; + } + } + PR_INSERT_AFTER(&jobp->links,qp); + } + tpool->timerq.cnt++; + /* + * notify timer worker thread(s) + */ + notify_timerq(tpool); + PR_Unlock(tpool->timerq.lock); + return jobp; +} + +static void +notify_timerq(PRThreadPool *tp) +{ + /* + * wakeup the timer thread(s) + */ + PR_NotifyCondVar(tp->timerq.cv); +} + +static void +notify_ioq(PRThreadPool *tp) +{ +PRStatus rval_status; + + /* + * wakeup the io thread(s) + */ + rval_status = PR_SetPollableEvent(tp->ioq.notify_fd); + PR_ASSERT(PR_SUCCESS == rval_status); +} + +/* + * cancel a job + * + * XXXX: is this needed? likely to be removed + */ +PR_IMPLEMENT(PRStatus) +PR_CancelJob(PRJob *jobp) { + + PRStatus rval = PR_FAILURE; + PRThreadPool *tp; + + if (jobp->on_timerq) { + /* + * now, check again while holding the timerq lock + */ + tp = jobp->tpool; + PR_Lock(tp->timerq.lock); + if (jobp->on_timerq) { + jobp->on_timerq = PR_FALSE; + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->timerq.cnt--; + PR_Unlock(tp->timerq.lock); + if (!JOINABLE_JOB(jobp)) { + delete_job(jobp); + } else { + JOIN_NOTIFY(jobp); + } + rval = PR_SUCCESS; + } else + PR_Unlock(tp->timerq.lock); + } else if (jobp->on_ioq) { + /* + * now, check again while holding the ioq lock + */ + tp = jobp->tpool; + PR_Lock(tp->ioq.lock); + if (jobp->on_ioq) { + jobp->cancel_cv = PR_NewCondVar(tp->ioq.lock); + if (NULL == jobp->cancel_cv) { + PR_Unlock(tp->ioq.lock); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return PR_FAILURE; + } + /* + * mark job 'cancelled' and notify io thread(s) + * XXXX: + * this assumes there is only one io thread; when there + * are multiple threads, the io thread processing this job + * must be notified. + */ + jobp->cancel_io = PR_TRUE; + PR_Unlock(tp->ioq.lock); /* release, reacquire ioq lock */ + notify_ioq(tp); + PR_Lock(tp->ioq.lock); + while (jobp->cancel_io) + PR_WaitCondVar(jobp->cancel_cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(tp->ioq.lock); + PR_ASSERT(!jobp->on_ioq); + if (!JOINABLE_JOB(jobp)) { + delete_job(jobp); + } else { + JOIN_NOTIFY(jobp); + } + rval = PR_SUCCESS; + } else + PR_Unlock(tp->ioq.lock); + } + if (PR_FAILURE == rval) + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return rval; +} + +/* join a job, wait until completion */ +PR_IMPLEMENT(PRStatus) +PR_JoinJob(PRJob *jobp) +{ + if (!JOINABLE_JOB(jobp)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + PR_Lock(jobp->tpool->join_lock); + while(jobp->join_wait) + PR_WaitCondVar(jobp->join_cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(jobp->tpool->join_lock); + delete_job(jobp); + return PR_SUCCESS; +} + +/* shutdown threadpool */ +PR_IMPLEMENT(PRStatus) +PR_ShutdownThreadPool(PRThreadPool *tpool) +{ +PRStatus rval = PR_SUCCESS; + + PR_Lock(tpool->jobq.lock); + tpool->shutdown = PR_TRUE; + PR_NotifyAllCondVar(tpool->shutdown_cv); + PR_Unlock(tpool->jobq.lock); + + return rval; +} + +/* + * join thread pool + * wait for termination of worker threads + * reclaim threadpool resources + */ +PR_IMPLEMENT(PRStatus) +PR_JoinThreadPool(PRThreadPool *tpool) +{ +PRStatus rval = PR_SUCCESS; +PRCList *head; +PRStatus rval_status; + + PR_Lock(tpool->jobq.lock); + while (!tpool->shutdown) + PR_WaitCondVar(tpool->shutdown_cv, PR_INTERVAL_NO_TIMEOUT); + + /* + * wakeup worker threads + */ +#ifdef OPT_WINNT + /* + * post shutdown notification for all threads + */ + { + int i; + for(i=0; i < tpool->current_threads; i++) { + PostQueuedCompletionStatus(tpool->jobq.nt_completion_port, 0, + TRUE, NULL); + } + } +#else + PR_NotifyAllCondVar(tpool->jobq.cv); +#endif + + /* + * wakeup io thread(s) + */ + notify_ioq(tpool); + + /* + * wakeup timer thread(s) + */ + PR_Lock(tpool->timerq.lock); + notify_timerq(tpool); + PR_Unlock(tpool->timerq.lock); + + while (!PR_CLIST_IS_EMPTY(&tpool->jobq.wthreads)) { + wthread *wthrp; + + head = PR_LIST_HEAD(&tpool->jobq.wthreads); + PR_REMOVE_AND_INIT_LINK(head); + PR_Unlock(tpool->jobq.lock); + wthrp = WTHREAD_LINKS_PTR(head); + rval_status = PR_JoinThread(wthrp->thread); + PR_ASSERT(PR_SUCCESS == rval_status); + PR_DELETE(wthrp); + PR_Lock(tpool->jobq.lock); + } + PR_Unlock(tpool->jobq.lock); + while (!PR_CLIST_IS_EMPTY(&tpool->ioq.wthreads)) { + wthread *wthrp; + + head = PR_LIST_HEAD(&tpool->ioq.wthreads); + PR_REMOVE_AND_INIT_LINK(head); + wthrp = WTHREAD_LINKS_PTR(head); + rval_status = PR_JoinThread(wthrp->thread); + PR_ASSERT(PR_SUCCESS == rval_status); + PR_DELETE(wthrp); + } + + while (!PR_CLIST_IS_EMPTY(&tpool->timerq.wthreads)) { + wthread *wthrp; + + head = PR_LIST_HEAD(&tpool->timerq.wthreads); + PR_REMOVE_AND_INIT_LINK(head); + wthrp = WTHREAD_LINKS_PTR(head); + rval_status = PR_JoinThread(wthrp->thread); + PR_ASSERT(PR_SUCCESS == rval_status); + PR_DELETE(wthrp); + } + + /* + * Delete queued jobs + */ + while (!PR_CLIST_IS_EMPTY(&tpool->jobq.list)) { + PRJob *jobp; + + head = PR_LIST_HEAD(&tpool->jobq.list); + PR_REMOVE_AND_INIT_LINK(head); + jobp = JOB_LINKS_PTR(head); + tpool->jobq.cnt--; + delete_job(jobp); + } + + /* delete io jobs */ + while (!PR_CLIST_IS_EMPTY(&tpool->ioq.list)) { + PRJob *jobp; + + head = PR_LIST_HEAD(&tpool->ioq.list); + PR_REMOVE_AND_INIT_LINK(head); + tpool->ioq.cnt--; + jobp = JOB_LINKS_PTR(head); + delete_job(jobp); + } + + /* delete timer jobs */ + while (!PR_CLIST_IS_EMPTY(&tpool->timerq.list)) { + PRJob *jobp; + + head = PR_LIST_HEAD(&tpool->timerq.list); + PR_REMOVE_AND_INIT_LINK(head); + tpool->timerq.cnt--; + jobp = JOB_LINKS_PTR(head); + delete_job(jobp); + } + + PR_ASSERT(0 == tpool->jobq.cnt); + PR_ASSERT(0 == tpool->ioq.cnt); + PR_ASSERT(0 == tpool->timerq.cnt); + + delete_threadpool(tpool); + return rval; +} diff --git a/nsprpub/pr/src/misc/prtrace.c b/nsprpub/pr/src/misc/prtrace.c new file mode 100644 index 00000000000..e7d4c55db7b --- /dev/null +++ b/nsprpub/pr/src/misc/prtrace.c @@ -0,0 +1,920 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** prtrace.c -- NSPR Trace Instrumentation +** +** Implement the API defined in prtrace.h +** +** +** +*/ + +#include +#include "primpl.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 = NULL; + 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; + +#ifdef XP_UNIX + if ((getuid() != geteuid()) || (getgid() != getegid())) { + return NULL; + } +#endif /* XP_UNIX */ + + /* 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() */ + +/* end prtrace.c */ diff --git a/nsprpub/pr/src/nspr.def b/nsprpub/pr/src/nspr.def new file mode 100644 index 00000000000..a91159aa1ad --- /dev/null +++ b/nsprpub/pr/src/nspr.def @@ -0,0 +1,471 @@ +;+# +;+# ***** BEGIN LICENSE BLOCK ***** +;+# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +;+# +;+# The contents of this file are subject to the Mozilla Public License Version +;+# 1.1 (the "License"); you may not use this file except in compliance with +;+# the License. You may obtain a copy of the License at +;+# http://www.mozilla.org/MPL/ +;+# +;+# Software distributed under the License is distributed on an "AS IS" basis, +;+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +;+# for the specific language governing rights and limitations under the +;+# License. +;+# +;+# The Original Code is the Netscape Portable Runtime (NSPR). +;+# +;+# The Initial Developer of the Original Code is +;+# Netscape Communications Corporation. +;+# Portions created by the Initial Developer are Copyright (C) 2002-2003 +;+# the Initial Developer. All Rights Reserved. +;+# +;+# Contributor(s): +;+# +;+# Alternatively, the contents of this file may be used under the terms of +;+# either the GNU General Public License Version 2 or later (the "GPL"), or +;+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +;+# in which case the provisions of the GPL or the LGPL are applicable instead +;+# of those above. If you wish to allow use of your version of this file only +;+# under the terms of either the GPL or the LGPL, and not to allow others to +;+# use your version of this file under the terms of the MPL, indicate your +;+# decision by deleting the provisions above and replace them with the notice +;+# and other provisions required by the GPL or the LGPL. If you do not delete +;+# the provisions above, a recipient may use your version of this file under +;+# the terms of any one of the MPL, the GPL or the LGPL. +;+# +;+# ***** END LICENSE BLOCK ***** +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+# +;+NSPR_4.0 { +;+ global: +LIBRARY nspr4 ;- +EXPORTS ;- + LL_MaxInt; + LL_MinInt; + LL_Zero; + PR_Abort; + PR_AddToCounter; + PR_Accept; + PR_AcceptRead; + PR_Access; + PR_AddWaitFileDesc; + PR_AllocFileDesc; + PR_Assert; + PR_AtomicAdd; + PR_AtomicDecrement; + PR_AtomicIncrement; + PR_AtomicSet; + PR_AttachSharedMemory; + PR_AttachThread; + PR_Available; + PR_Available64; + PR_Bind; + PR_BlockClockInterrupts; + PR_BlockInterrupt; + PR_CEnterMonitor; + PR_CExitMonitor; + PR_CNotify; + PR_CNotifyAll; + PR_CSetOnMonitorRecycle; + PR_CWait; + PR_CallOnce; + PR_Calloc; + PR_CancelJob; + PR_CancelWaitFileDesc; + PR_CancelWaitGroup; + PR_CeilingLog2; + PR_ChangeFileDescNativeHandle; + PR_Cleanup; + PR_ClearInterrupt; + PR_ClearThreadGCAble; + PR_Close; + PR_CloseDir; + PR_CloseFileMap; + PR_CloseSemaphore; + PR_CloseSharedMemory; + PR_Connect; + PR_CreateCounter; + PR_ConvertIPv4AddrToIPv6; + PR_CreateAlarm; + PR_CreateFileMap; + PR_CreateIOLayerStub; + PR_CreateOrderedLock; + PR_CreateMWaitEnumerator; + PR_CreatePipe; + PR_CreateProcess; + PR_CreateProcessDetached; + PR_CreateSocketPollFd; + PR_CreateStack; + PR_CreateThread; + PR_CreateThreadGCAble; + PR_CreateTrace; + PR_CreateThreadPool; + PR_DecrementCounter; + PR_CreateWaitGroup; + PR_Delete; + PR_DeleteSemaphore; + PR_DeleteSharedMemory; + PR_DestroyAlarm; + PR_DestroyCounter; + PR_DestroyCondVar; + PR_DestroyLock; + PR_DestroyMWaitEnumerator; + PR_DestroyOrderedLock; + PR_DestroyMonitor; + PR_DestroyPollableEvent; + PR_DestroyProcessAttr; + PR_DestroyRWLock; + PR_DestroySem; + PR_DestroySocketPollFd; + PR_DestroyTrace; + PR_DestroyStack; + PR_DestroyWaitGroup; + PR_DetachProcess; + PR_DetachSharedMemory; + PR_DetachThread; + PR_DisableClockInterrupts; + PR_EnableClockInterrupts; + PR_EnterMonitor; + PR_EnumerateHostEnt; + PR_EnumerateThreads; + PR_EnumerateWaitGroup; + PR_ErrorInstallCallback; + PR_ErrorInstallTable; + PR_ErrorLanguages; + PR_ErrorToName; + PR_ErrorToString; + PR_ExitMonitor; + PR_ExplodeTime; + PR_ExportFileMapAsString; + PR_FD_CLR; + PR_FD_ISSET; + PR_FD_NCLR; + PR_FD_NISSET; + PR_FD_NSET; + PR_FD_SET; + PR_FD_ZERO; + PR_FileDesc2NativeHandle; + PR_FindSymbol; + PR_FindSymbolAndLibrary; + PR_FloorLog2; + PR_FormatTime; + PR_FindNextCounterQname; + PR_FindNextCounterRname; + PR_FindNextTraceQname; + PR_FindNextTraceRname; + PR_FormatTimeUSEnglish; + PR_Free; + PR_FreeLibraryName; + PR_GMTParameters; + PR_GetConnectStatus; + PR_GetCurrentThread; + PR_GetDefaultIOMethods; + PR_GetDescType; + PR_GetDirectorySeparator; + PR_GetCounter; + PR_GetCounterHandleFromName; + PR_GetCounterNameFromHandle; + PR_GetDirectorySepartor; + PR_GetEnv; + PR_GetError; + PR_GetErrorText; + PR_GetErrorTextLength; + PR_GetFileInfo; + PR_GetFileInfo64; + PR_GetFileMethods; + PR_GetGCRegisters; + PR_GetHostByAddr; + PR_GetHostByName; + PR_GetIPNodeByName; + PR_GetIdentitiesLayer; + PR_GetInheritedFD; + PR_GetInheritedFileMap; + PR_GetLayersIdentity; + PR_GetLibraryName; + PR_GetLibraryPath; + PR_GetMonitorEntryCount; + PR_GetNameForIdentity; + PR_GetOSError; + PR_GetOpenFileInfo; + PR_GetOpenFileInfo64; + PR_GetPageShift; + PR_GetPageSize; + PR_GetPeerName; + PR_GetPipeMethods; + PR_GetProtoByName; + PR_GetProtoByNumber; + PR_GetRandomNoise; + PR_GetSP; + PR_GetSockName; + PR_GetSocketOption; + PR_GetSpecialFD; + PR_GetStackSpaceLeft; + PR_GetSysfdTableMax; + PR_GetSystemInfo; + PR_GetTCPMethods; + PR_GetThreadAffinityMask; + PR_GetThreadID; + PR_GetThreadPriority; + PR_GetThreadPrivate; + PR_GetThreadScope; + PR_GetThreadState; + PR_GetThreadType; + PR_GetUDPMethods; + PR_GetUniqueIdentity; + PR_ImplodeTime; + PR_ImportFile; + PR_ImportFileMapFromString; + PR_ImportTCPSocket; + PR_ImportUDPSocket; + PR_GetTraceEntries; + PR_GetTraceHandleFromName; + PR_GetTraceNameFromHandle; + PR_GetTraceOption; + PR_Init; + PR_Initialize; + PR_InitializeNetAddr; + PR_Initialized; + PR_Interrupt; + PR_IntervalNow; + PR_IntervalToMicroseconds; + PR_IntervalToMilliseconds; + PR_IncrementCounter; + PR_IntervalToSeconds; + PR_IsNetAddrType; + PR_JoinJob; + PR_JoinThread; + PR_JoinThreadPool; + PR_KillProcess; + PR_Listen; + PR_LoadLibrary; + PR_LoadLibraryWithFlags; + PR_LoadStaticLibrary; + PR_LocalTimeParameters; + PR_Lock; + PR_LockFile; + PR_LogFlush; + PR_LogPrint; + PR_MakeDir; + PR_Malloc; + PR_MemMap; + PR_MemUnmap; + PR_MicrosecondsToInterval; + PR_MillisecondsToInterval; + PR_LockOrderedLock; + PR_MkDir; + PR_NetAddrToString; + PR_NewCondVar; + PR_NewLock; + PR_NewLogModule; + PR_NewMonitor; + PR_NewNamedMonitor; + PR_NewPollableEvent; + PR_NewProcessAttr; + PR_NewRWLock; + PR_NewSem; + PR_NewTCPSocket; + PR_NewTCPSocketPair; + PR_NewThreadPrivateIndex; + PR_NewUDPSocket; + PR_NormalizeTime; + PR_Notify; + PR_NotifyAll; + PR_NotifyAllCondVar; + PR_NotifyCondVar; + PR_Now; + PR_Open; + PR_OpenAnonFileMap; + PR_OpenDir; + PR_OpenFile; + PR_OpenSemaphore; + PR_OpenSharedMemory; + PR_OpenTCPSocket; + PR_OpenUDPSocket; + PR_ParseTimeString; + PR_Poll; + PR_PopIOLayer; + PR_PostSem; + PR_PostSemaphore; + PR_ProcessAttrSetCurrentDirectory; + PR_ProcessAttrSetInheritableFD; + PR_ProcessAttrSetInheritableFileMap; + PR_ProcessAttrSetStdioRedirect; + PR_ProcessExit; + PR_PushIOLayer; + PR_QueueJob; + PR_QueueJob_Accept; + PR_QueueJob_Connect; + PR_QueueJob_Read; + PR_QueueJob_Timer; + PR_QueueJob_Write; + PR_RWLock_Rlock; + PR_RWLock_Unlock; + PR_RWLock_Wlock; + PR_Read; + PR_ReadDir; + PR_Realloc; + PR_Recv; + PR_RecvFrom; + PR_Rename; + PR_ResetAlarm; + PR_ResetProcessAttr; + PR_ResumeAll; + PR_RmDir; + PR_ScanStackPointers; + PR_RecordTraceEntries; + PR_SecondsToInterval; + PR_Seek; + PR_Seek64; + PR_Select; + PR_Send; + PR_SendFile; + PR_SendTo; + PR_SetAlarm; + PR_SetConcurrency; + PR_SetError; + PR_SetErrorText; + PR_SetFDCacheSize; + PR_SetFDInheritable; + PR_SetLibraryPath; + PR_SetLogBuffering; + PR_SetLogFile; + PR_SetNetAddr; + PR_SetPollableEvent; + PR_SetSocketOption; + PR_SetCounter; + PR_SetStdioRedirect; + PR_SetSysfdTableSize; + PR_SetThreadAffinityMask; + PR_SetThreadDumpProc; + PR_SetThreadGCAble; + PR_SetThreadPriority; + PR_SetThreadPrivate; + PR_SetThreadRecycleMode; + PR_Shutdown; + PR_ShutdownThreadPool; + PR_Sleep; + PR_Socket; + PR_StackPop; + PR_StackPush; + PR_Stat; + PR_StringToNetAddr; + PR_SuspendAll; + PR_Sync; + PR_TLockFile; + PR_ThreadScanStackPointers; + PR_SetTraceOption; + PR_TicksPerSecond; + PR_TransmitFile; + PR_USPacificTimeParameters; + PR_UnblockClockInterrupts; + PR_UnblockInterrupt; + PR_UnloadLibrary; + PR_SubtractFromCounter; + PR_Unlock; + PR_UnlockFile; + PR_VersionCheck; + PR_Wait; + PR_WaitCondVar; + PR_WaitForPollableEvent; + PR_Trace; + PR_WaitProcess; + PR_WaitRecvReady; + PR_WaitSem; + PR_WaitSemaphore; + PR_Write; + PR_Writev; + PR_Yield; + PR_UnlockOrderedLock; + PR_cnvtf; + PR_dtoa; + PR_fprintf; + PR_htonl; + PR_htonll; + PR_htons; + PR_ntohl; + PR_ntohll; + PR_ntohs; + PR_smprintf; + PR_smprintf_free; + PR_snprintf; + PR_sprintf_append; + PR_sscanf; + PR_strtod; + PR_sxprintf; + PR_vfprintf; + PR_vsmprintf; + PR_vsnprintf; + PR_vsprintf_append; + PR_vsxprintf; + PRP_DestroyNakedCondVar; + PRP_NakedBroadcast; + PRP_NakedNotify; + PRP_NakedWait; + PRP_NewNakedCondVar; + PRP_TryLock; + libVersionPoint; +;+ local: *; +;+}; +;+ +;+NSPRprivate { +;+ global: + GetExecutionEnvironment; + PT_FPrintStats; + SetExecutionEnvironment; +;+ local: *; +;+}; +;+ +;+NSPR_4.1 { +;+ global: + PR_ConnectContinue; + PR_CreateIOLayer; + PR_EmulateAcceptRead; + PR_EmulateSendFile; + PR_FindFunctionSymbol; + PR_FindFunctionSymbolAndLibrary; + PR_GetMemMapAlignment; + PR_GetNumberOfProcessors; + PR_ImportPipe; + PR_SetEnv; +;+} NSPR_4.0; +;+ +;+NSPR_4.3 { +;+ global: + LL_MaxUint; + PR_CallOnceWithArg; + PR_GetLibraryFilePathname; +;+} NSPR_4.1; +;+ +;+NSPR_4.4 { +;+ global: + PR_GetPathSeparator; +;+} NSPR_4.3; +;+ +;+NSPR_4.5 { +;+ global: + PR_EnumerateAddrInfo; + PR_FreeAddrInfo; + PR_GetAddrInfoByName; + PR_GetCanonNameFromAddrInfo; +;+} NSPR_4.4; +;+ +;+NSPR_4.6 { +;+ global: + PR_GetPhysicalMemorySize; +;+} NSPR_4.5; +;+NSPR_4.7 { +;+ global: + PR_ParseTimeStringToExplodedTime; +;+} NSPR_4.6; diff --git a/nsprpub/pr/src/nspr.rc b/nsprpub/pr/src/nspr.rc new file mode 100644 index 00000000000..da223135af7 --- /dev/null +++ b/nsprpub/pr/src/nspr.rc @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include + +#define MY_LIBNAME "nspr" +#define MY_FILEDESCRIPTION "NSPR Library" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define PR_VMAJOR_STR STRINGIZE2(PR_VMAJOR) + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if PR_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#define MY_INTERNAL_NAME "lib" MY_LIBNAME PR_VMAJOR_STR +#else +#define MY_FILEOS VOS__WINDOWS32 +#define MY_INTERNAL_NAME MY_LIBNAME PR_VMAJOR_STR +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + PRODUCTVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Mozilla Foundation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", PR_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Netscape Portable Runtime\0" + VALUE "ProductVersion", PR_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/nsprpub/pr/src/nspr_symvec.opt b/nsprpub/pr/src/nspr_symvec.opt new file mode 100644 index 00000000000..d9ca566ecff --- /dev/null +++ b/nsprpub/pr/src/nspr_symvec.opt @@ -0,0 +1,503 @@ +! Fixed section of symbol vector for LIBNSPR4 (non-debug) +! +GSMATCH=LEQUAL,2,8 +case_sensitive=YES +! +! -------------------------------------------------------------------------- +! Ident 2,1 introduced for Mozilla 0.9.4 +! Based on NSPR 4.1.2 +! -------------------------------------------------------------------------- +! Ident 2,2 introduced for Mozilla 1.2 +! Based on NSPR 4.2.2? +! PR_ResumeSet, PR_ResumeTest, and PR_SuspendAllSuspended has been "removed". +! Only we can't remove the entry points because OJI is linked against NSPR so +! we have to make an upwardly compatible change: +! PR_ResumeSet is now PR_VMS_Stub1 +! PR_ResumeTest is now PR_VMS_Stub2 +! PR_SuspendAllSuspended is PR_VMS_Stub3 +! These are stub functions (defined in openvms.c) solely for the purpose of +! occupying the slots in our fixed section of the symbol table. +! -------------------------------------------------------------------------- +! Ident 2,3 introduced for Mozilla 1.3 +! Previously we were missing some symbols from NSPR 4.0 and 4.1, so now we +! include everything that's specified in nspr.def. +! -------------------------------------------------------------------------- +! Ident 2,4 introduced for Mozilla 1.3 final. +! 2,3 was still missing some symbols, in particular PR_CreateThread, which +! is used by OJI. So insert stubs to force the PR_CreateThread entry down +! to its Mozilla 1.1 (and Java 1.4-0) location so that everyone can play +! together and be happy. +! -------------------------------------------------------------------------- +! Ident 2,5 introduced for post Mozilla 1.3. +! LL_MaxUint introduced. Replaces Stub54. +! -------------------------------------------------------------------------- +! Ident 2,6 introduced for post Mozilla 1.4. +! PR_GetPathSeparator introduced in NSPR 4.4. +! This replaces stub 53 +! -------------------------------------------------------------------------- +! Ident 2,7 introduced for post Mozilla 1.4. +! PR_GetAddrInfoByName, PR_FreeAddrInfo, PR_EnumerateAddrInfo and +! PR_GetCanonNameFromAddrInfo introduced in NSPR 4.5. +! These replace stubs 49-52 +! -------------------------------------------------------------------------- +! Ident 2,8 introduced for NSPR 4.6. +! PR_FindLibrary removed. Replaced by PR_GetPhysicalMemorySize. +! -------------------------------------------------------------------------- +! +SYMBOL_VECTOR=(PR_Accept=PROCEDURE) +SYMBOL_VECTOR=(PR_AcceptRead=PROCEDURE) +SYMBOL_VECTOR=(PR_Access=PROCEDURE) +SYMBOL_VECTOR=(PR_AllocFileDesc=PROCEDURE) +SYMBOL_VECTOR=(PR_Assert=PROCEDURE) +SYMBOL_VECTOR=(PR_AtomicAdd=PROCEDURE) +SYMBOL_VECTOR=(PR_AtomicDecrement=PROCEDURE) +SYMBOL_VECTOR=(PR_AtomicSet=PROCEDURE) +SYMBOL_VECTOR=(PR_AttachSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_AttachThread=PROCEDURE) +SYMBOL_VECTOR=(PR_Available64=PROCEDURE) +SYMBOL_VECTOR=(PR_Available=PROCEDURE) +SYMBOL_VECTOR=(PR_Bind=PROCEDURE) +SYMBOL_VECTOR=(PR_BlockClockInterrupts=PROCEDURE) +SYMBOL_VECTOR=(PR_BlockInterrupt=PROCEDURE) +SYMBOL_VECTOR=(PR_CExitMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_CNotify=PROCEDURE) +SYMBOL_VECTOR=(PR_CNotifyAll=PROCEDURE) +SYMBOL_VECTOR=(PR_CSetOnMonitorRecycle=PROCEDURE) +SYMBOL_VECTOR=(PR_CWait=PROCEDURE) +SYMBOL_VECTOR=(PR_CallOnce=PROCEDURE) +SYMBOL_VECTOR=(PR_Calloc=PROCEDURE) +SYMBOL_VECTOR=(PR_CancelJob=PROCEDURE) +SYMBOL_VECTOR=(PR_CancelWaitFileDesc=PROCEDURE) +SYMBOL_VECTOR=(PR_CancelWaitGroup=PROCEDURE) +SYMBOL_VECTOR=(PR_ChangeFileDescNativeHandle=PROCEDURE) +SYMBOL_VECTOR=(PR_Cleanup=PROCEDURE) +SYMBOL_VECTOR=(PR_ClearInterrupt=PROCEDURE) +SYMBOL_VECTOR=(PR_ClearThreadGCAble=PROCEDURE) +SYMBOL_VECTOR=(PR_Close=PROCEDURE) +SYMBOL_VECTOR=(PR_CloseDir=PROCEDURE) +SYMBOL_VECTOR=(PR_CloseFileMap=PROCEDURE) +SYMBOL_VECTOR=(PR_CloseSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_CloseSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_Connect=PROCEDURE) +SYMBOL_VECTOR=(PR_ConnectContinue=PROCEDURE) +SYMBOL_VECTOR=(PR_ConvertIPv4AddrToIPv6=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateIOLayer=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateIOLayerStub=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateMWaitEnumerator=PROCEDURE) +SYMBOL_VECTOR=(PR_CreatePipe=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateProcess=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateProcessDetached=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateSocketPollFd=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateStack=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateThreadGCAble=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateWaitGroup=PROCEDURE) +SYMBOL_VECTOR=(PR_Delete=PROCEDURE) +SYMBOL_VECTOR=(PR_DeleteSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_DeleteSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyAlarm=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyLock=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyMWaitEnumerator=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyPollableEvent=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyProcessAttr=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyRWLock=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroySem=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroySocketPollFd=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyStack=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyWaitGroup=PROCEDURE) +SYMBOL_VECTOR=(PR_DetachProcess=PROCEDURE) +SYMBOL_VECTOR=(PR_DetachSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_DetachThread=PROCEDURE) +SYMBOL_VECTOR=(PR_DisableClockInterrupts=PROCEDURE) +SYMBOL_VECTOR=(PR_EmulateAcceptRead=PROCEDURE) +SYMBOL_VECTOR=(PR_EmulateSendFile=PROCEDURE) +SYMBOL_VECTOR=(PR_EnableClockInterrupts=PROCEDURE) +SYMBOL_VECTOR=(PR_EnterMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_EnumerateHostEnt=PROCEDURE) +SYMBOL_VECTOR=(PR_EnumerateThreads=PROCEDURE) +SYMBOL_VECTOR=(PR_EnumerateWaitGroup=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorInstallCallback=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorInstallTable=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorLanguages=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorToName=PROCEDURE) +SYMBOL_VECTOR=(PR_ExitMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_ExportFileMapAsString=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_CLR=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_ISSET=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_NCLR=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_NISSET=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_NSET=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_SET=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_ZERO=PROCEDURE) +SYMBOL_VECTOR=(PR_FileDesc2NativeHandle=PROCEDURE) +SYMBOL_VECTOR=(PR_FindFunctionSymbol=PROCEDURE) +SYMBOL_VECTOR=(PR_FindFunctionSymbolAndLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPhysicalMemorySize=PROCEDURE) +SYMBOL_VECTOR=(PR_FindSymbol=PROCEDURE) +SYMBOL_VECTOR=(PR_FindSymbolAndLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_FloorLog2=PROCEDURE) +SYMBOL_VECTOR=(PR_FormatTime=PROCEDURE) +SYMBOL_VECTOR=(PR_FormatTimeUSEnglish=PROCEDURE) +SYMBOL_VECTOR=(PR_Free=PROCEDURE) +SYMBOL_VECTOR=(PR_FreeLibraryName=PROCEDURE) +SYMBOL_VECTOR=(PR_GMTParameters=PROCEDURE) +SYMBOL_VECTOR=(PR_GetConnectStatus=PROCEDURE) +SYMBOL_VECTOR=(PR_GetCurrentThread=PROCEDURE) +SYMBOL_VECTOR=(PR_GetDefaultIOMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_GetDirectorySepartor=PROCEDURE) +SYMBOL_VECTOR=(PR_GetError=PROCEDURE) +SYMBOL_VECTOR=(PR_GetErrorText=PROCEDURE) +SYMBOL_VECTOR=(PR_GetErrorTextLength=PROCEDURE) +SYMBOL_VECTOR=(PR_GetFileInfo64=PROCEDURE) +SYMBOL_VECTOR=(PR_GetFileInfo=PROCEDURE) +SYMBOL_VECTOR=(PR_GetFileMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_GetHostByAddr=PROCEDURE) +SYMBOL_VECTOR=(PR_GetHostByName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetIPNodeByName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetIdentitiesLayer=PROCEDURE) +SYMBOL_VECTOR=(PR_GetInheritedFD=PROCEDURE) +SYMBOL_VECTOR=(PR_GetInheritedFileMap=PROCEDURE) +SYMBOL_VECTOR=(PR_GetLayersIdentity=PROCEDURE) +SYMBOL_VECTOR=(PR_GetLibraryName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetLibraryPath=PROCEDURE) +SYMBOL_VECTOR=(PR_GetMemMapAlignment=PROCEDURE) +SYMBOL_VECTOR=(PR_GetMonitorEntryCount=PROCEDURE) +SYMBOL_VECTOR=(PR_GetNameForIdentity=PROCEDURE) +SYMBOL_VECTOR=(PR_GetNumberOfProcessors=PROCEDURE) +SYMBOL_VECTOR=(PR_GetOSError=PROCEDURE) +SYMBOL_VECTOR=(PR_GetOpenFileInfo64=PROCEDURE) +SYMBOL_VECTOR=(PR_GetOpenFileInfo=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPageShift=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPeerName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPipeMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_GetProtoByName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetProtoByNumber=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSP=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSockName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSocketOption=PROCEDURE) +SYMBOL_VECTOR=(PR_GetStackSpaceLeft=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSysfdTableMax=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSystemInfo=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTCPMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadAffinityMask=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadID=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadPriority=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadPrivate=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadScope=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadState=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadType=PROCEDURE) +SYMBOL_VECTOR=(PR_GetUDPMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_ImplodeTime=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportFile=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportFileMapFromString=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportPipe=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportTCPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportUDPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_Init=PROCEDURE) +SYMBOL_VECTOR=(PR_Initialize=PROCEDURE) +SYMBOL_VECTOR=(PR_InitializeNetAddr=PROCEDURE) +SYMBOL_VECTOR=(PR_Initialized=PROCEDURE) +SYMBOL_VECTOR=(PR_Interrupt=PROCEDURE) +SYMBOL_VECTOR=(PR_IntervalToMicroseconds=PROCEDURE) +SYMBOL_VECTOR=(PR_IntervalToMilliseconds=PROCEDURE) +SYMBOL_VECTOR=(PR_IntervalToSeconds=PROCEDURE) +SYMBOL_VECTOR=(PR_IsNetAddrType=PROCEDURE) +SYMBOL_VECTOR=(PR_JoinJob=PROCEDURE) +SYMBOL_VECTOR=(PR_JoinThread=PROCEDURE) +SYMBOL_VECTOR=(PR_JoinThreadPool=PROCEDURE) +SYMBOL_VECTOR=(PR_KillProcess=PROCEDURE) +SYMBOL_VECTOR=(PR_Listen=PROCEDURE) +SYMBOL_VECTOR=(PR_LoadLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_LoadLibraryWithFlags=PROCEDURE) +SYMBOL_VECTOR=(PR_LoadStaticLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_LocalTimeParameters=PROCEDURE) +SYMBOL_VECTOR=(PR_Lock=PROCEDURE) +SYMBOL_VECTOR=(PR_LockFile=PROCEDURE) +SYMBOL_VECTOR=(PR_LogFlush=PROCEDURE) +SYMBOL_VECTOR=(PR_LogPrint=PROCEDURE) +SYMBOL_VECTOR=(PR_MakeDir=PROCEDURE) +SYMBOL_VECTOR=(PR_MemMap=PROCEDURE) +SYMBOL_VECTOR=(PR_MemUnmap=PROCEDURE) +SYMBOL_VECTOR=(PR_MicrosecondsToInterval=PROCEDURE) +SYMBOL_VECTOR=(PR_MillisecondsToInterval=PROCEDURE) +SYMBOL_VECTOR=(PR_MkDir=PROCEDURE) +SYMBOL_VECTOR=(PR_NetAddrToString=PROCEDURE) +SYMBOL_VECTOR=(PR_NewCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_NewLogModule=PROCEDURE) +SYMBOL_VECTOR=(PR_NewMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_NewNamedMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_NewProcessAttr=PROCEDURE) +SYMBOL_VECTOR=(PR_NewSem=PROCEDURE) +SYMBOL_VECTOR=(PR_NewTCPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_NewTCPSocketPair=PROCEDURE) +SYMBOL_VECTOR=(PR_NewUDPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_NormalizeTime=PROCEDURE) +SYMBOL_VECTOR=(PR_Notify=PROCEDURE) +SYMBOL_VECTOR=(PR_NotifyAll=PROCEDURE) +SYMBOL_VECTOR=(PR_NotifyAllCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_NotifyCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_Open=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenDir=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenFile=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenTCPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenUDPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_ParseTimeString=PROCEDURE) +SYMBOL_VECTOR=(PR_Poll=PROCEDURE) +SYMBOL_VECTOR=(PR_PopIOLayer=PROCEDURE) +SYMBOL_VECTOR=(PR_PostSem=PROCEDURE) +SYMBOL_VECTOR=(PR_PostSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_ProcessAttrSetCurren1sb1r7b$=PROCEDURE) ! PR_ProcessAttrSetCurrentDirectory +SYMBOL_VECTOR=(PR_ProcessAttrSetInheri3dpg1d0$=PROCEDURE) ! PR_ProcessAttrSetInheritableFileMap +SYMBOL_VECTOR=(PR_ProcessAttrSetInheritableFD=PROCEDURE) +SYMBOL_VECTOR=(PR_ProcessAttrSetStdioRedirect=PROCEDURE) +SYMBOL_VECTOR=(PR_ProcessExit=PROCEDURE) +SYMBOL_VECTOR=(PR_PushIOLayer=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Accept=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Connect=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Read=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Timer=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Write=PROCEDURE) +SYMBOL_VECTOR=(PR_RWLock_Rlock=PROCEDURE) +SYMBOL_VECTOR=(PR_RWLock_Unlock=PROCEDURE) +SYMBOL_VECTOR=(PR_RWLock_Wlock=PROCEDURE) +SYMBOL_VECTOR=(PR_Read=PROCEDURE) +SYMBOL_VECTOR=(PR_ReadDir=PROCEDURE) +SYMBOL_VECTOR=(PR_Realloc=PROCEDURE) +SYMBOL_VECTOR=(PR_Recv=PROCEDURE) +SYMBOL_VECTOR=(PR_RecvFrom=PROCEDURE) +SYMBOL_VECTOR=(PR_Rename=PROCEDURE) +SYMBOL_VECTOR=(PR_ResetAlarm=PROCEDURE) +SYMBOL_VECTOR=(PR_ResetProcessAttr=PROCEDURE) +SYMBOL_VECTOR=(PR_ResumeAll=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub1=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub2=PROCEDURE) +SYMBOL_VECTOR=(PR_RmDir=PROCEDURE) +SYMBOL_VECTOR=(PR_ScanStackPointers=PROCEDURE) +SYMBOL_VECTOR=(PR_SecondsToInterval=PROCEDURE) +SYMBOL_VECTOR=(PR_Seek64=PROCEDURE) +SYMBOL_VECTOR=(PR_Seek=PROCEDURE) +SYMBOL_VECTOR=(PR_Select=PROCEDURE) +SYMBOL_VECTOR=(PR_Send=PROCEDURE) +SYMBOL_VECTOR=(PR_SendFile=PROCEDURE) +SYMBOL_VECTOR=(PR_SendTo=PROCEDURE) +SYMBOL_VECTOR=(PR_SetAlarm=PROCEDURE) +SYMBOL_VECTOR=(PR_SetEnv=PROCEDURE) +SYMBOL_VECTOR=(PR_SetErrorText=PROCEDURE) +SYMBOL_VECTOR=(PR_SetFDInheritable=PROCEDURE) +SYMBOL_VECTOR=(PR_SetLogBuffering=PROCEDURE) +SYMBOL_VECTOR=(PR_SetLogFile=PROCEDURE) +SYMBOL_VECTOR=(PR_SetNetAddr=PROCEDURE) +SYMBOL_VECTOR=(PR_SetPollableEvent=PROCEDURE) +SYMBOL_VECTOR=(PR_SetSocketOption=PROCEDURE) +SYMBOL_VECTOR=(PR_SetStdioRedirect=PROCEDURE) +SYMBOL_VECTOR=(PR_SetSysfdTableSize=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadAffinityMask=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadDumpProc=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadGCAble=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadPriority=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadPrivate=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadRecycleMode=PROCEDURE) +SYMBOL_VECTOR=(PR_Shutdown=PROCEDURE) +SYMBOL_VECTOR=(PR_ShutdownThreadPool=PROCEDURE) +SYMBOL_VECTOR=(PR_Sleep=PROCEDURE) +SYMBOL_VECTOR=(PR_Socket=PROCEDURE) +SYMBOL_VECTOR=(PR_StackPop=PROCEDURE) +SYMBOL_VECTOR=(PR_StackPush=PROCEDURE) +SYMBOL_VECTOR=(PR_Stat=PROCEDURE) +SYMBOL_VECTOR=(PR_SuspendAll=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub3=PROCEDURE) +SYMBOL_VECTOR=(PR_Sync=PROCEDURE) +SYMBOL_VECTOR=(PR_TLockFile=PROCEDURE) +SYMBOL_VECTOR=(PR_ThreadScanStackPointers=PROCEDURE) +SYMBOL_VECTOR=(PR_TicksPerSecond=PROCEDURE) +SYMBOL_VECTOR=(PR_TransmitFile=PROCEDURE) +SYMBOL_VECTOR=(PR_USPacificTimeParameters=PROCEDURE) +SYMBOL_VECTOR=(PR_UnblockClockInterrupts=PROCEDURE) +SYMBOL_VECTOR=(PR_UnblockInterrupt=PROCEDURE) +SYMBOL_VECTOR=(PR_UnloadLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_Unlock=PROCEDURE) +SYMBOL_VECTOR=(PR_UnlockFile=PROCEDURE) +SYMBOL_VECTOR=(PR_Wait=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitForPollableEvent=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitProcess=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitRecvReady=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitSem=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_Write=PROCEDURE) +SYMBOL_VECTOR=(PR_Writev=PROCEDURE) +SYMBOL_VECTOR=(PR_XIsLocked=PROCEDURE) +SYMBOL_VECTOR=(PR_XLock=PROCEDURE) +SYMBOL_VECTOR=(PR_XNotify=PROCEDURE) +SYMBOL_VECTOR=(PR_XNotifyAll=PROCEDURE) +SYMBOL_VECTOR=(PR_XUnlock=PROCEDURE) +SYMBOL_VECTOR=(PR_XWait=PROCEDURE) +SYMBOL_VECTOR=(PR_Yield=PROCEDURE) +SYMBOL_VECTOR=(PR_cnvtf=PROCEDURE) +SYMBOL_VECTOR=(PR_dtoa=PROCEDURE) +SYMBOL_VECTOR=(PR_htonl=PROCEDURE) +SYMBOL_VECTOR=(PR_htonll=PROCEDURE) +SYMBOL_VECTOR=(PR_htons=PROCEDURE) +SYMBOL_VECTOR=(PR_ntohl=PROCEDURE) +SYMBOL_VECTOR=(PR_ntohll=PROCEDURE) +SYMBOL_VECTOR=(PR_ntohs=PROCEDURE) +SYMBOL_VECTOR=(PR_smprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_smprintf_free=PROCEDURE) +SYMBOL_VECTOR=(PR_sprintf_append=PROCEDURE) +SYMBOL_VECTOR=(PR_sxprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_vfprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_vsmprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_vsnprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_vsprintf_append=PROCEDURE) +SYMBOL_VECTOR=(PR_vsxprintf=PROCEDURE) +! +! Start of 2,3 additions +! +SYMBOL_VECTOR=(LL_MaxInt=PROCEDURE) +SYMBOL_VECTOR=(LL_MinInt=PROCEDURE) +SYMBOL_VECTOR=(LL_Zero=PROCEDURE) +SYMBOL_VECTOR=(PR_Abort=PROCEDURE) +SYMBOL_VECTOR=(PR_AddToCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_AddWaitFileDesc=PROCEDURE) +SYMBOL_VECTOR=(PR_AtomicIncrement=PROCEDURE) +SYMBOL_VECTOR=(PR_CEnterMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_CeilingLog2=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateAlarm=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateFileMap=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateOrderedLock=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateTrace=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateThreadPool=PROCEDURE) +SYMBOL_VECTOR=(PR_DecrementCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyOrderedLock=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyTrace=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorToString=PROCEDURE) +SYMBOL_VECTOR=(PR_ExplodeTime=PROCEDURE) +SYMBOL_VECTOR=(PR_FindNextCounterQname=PROCEDURE) +SYMBOL_VECTOR=(PR_FindNextCounterRname=PROCEDURE) +SYMBOL_VECTOR=(PR_FindNextTraceQname=PROCEDURE) +SYMBOL_VECTOR=(PR_FindNextTraceRname=PROCEDURE) +SYMBOL_VECTOR=(PR_GetDescType=PROCEDURE) +SYMBOL_VECTOR=(PR_GetDirectorySeparator=PROCEDURE) +SYMBOL_VECTOR=(PR_GetCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_GetCounterHandleFromName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetCounterNameFromHandle=PROCEDURE) +SYMBOL_VECTOR=(PR_GetEnv=PROCEDURE) +SYMBOL_VECTOR=(PR_GetGCRegisters=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPageSize=PROCEDURE) +SYMBOL_VECTOR=(PR_GetRandomNoise=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSpecialFD=PROCEDURE) +SYMBOL_VECTOR=(PR_GetUniqueIdentity=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTraceEntries=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTraceHandleFromName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTraceNameFromHandle=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTraceOption=PROCEDURE) +SYMBOL_VECTOR=(PR_IntervalNow=PROCEDURE) +SYMBOL_VECTOR=(PR_IncrementCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_Malloc=PROCEDURE) +SYMBOL_VECTOR=(PR_LockOrderedLock=PROCEDURE) +SYMBOL_VECTOR=(PR_NewLock=PROCEDURE) +SYMBOL_VECTOR=(PR_NewPollableEvent=PROCEDURE) +SYMBOL_VECTOR=(PR_NewRWLock=PROCEDURE) +SYMBOL_VECTOR=(PR_NewThreadPrivateIndex=PROCEDURE) +SYMBOL_VECTOR=(PR_Now=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenAnonFileMap=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_RecordTraceEntries=PROCEDURE) +SYMBOL_VECTOR=(PR_SetConcurrency=PROCEDURE) +SYMBOL_VECTOR=(PR_SetFDCacheSize=PROCEDURE) +SYMBOL_VECTOR=(PR_SetLibraryPath=PROCEDURE) +SYMBOL_VECTOR=(PR_SetCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_StringToNetAddr=PROCEDURE) +SYMBOL_VECTOR=(PR_SetTraceOption=PROCEDURE) +SYMBOL_VECTOR=(PR_SubtractFromCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_VersionCheck=PROCEDURE) +SYMBOL_VECTOR=(PR_Trace=PROCEDURE) +SYMBOL_VECTOR=(PR_UnlockOrderedLock=PROCEDURE) +SYMBOL_VECTOR=(PR_fprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_snprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_sscanf=PROCEDURE) +SYMBOL_VECTOR=(PR_strtod=PROCEDURE) +SYMBOL_VECTOR=(PRP_DestroyNakedCondVar=PROCEDURE) +SYMBOL_VECTOR=(PRP_NakedBroadcast=PROCEDURE) +SYMBOL_VECTOR=(PRP_NakedNotify=PROCEDURE) +SYMBOL_VECTOR=(PRP_NakedWait=PROCEDURE) +SYMBOL_VECTOR=(PRP_NewNakedCondVar=PROCEDURE) +SYMBOL_VECTOR=(PRP_TryLock=PROCEDURE) +SYMBOL_VECTOR=(libVersionPoint=PROCEDURE) +! +! NSPR private +! +SYMBOL_VECTOR=(GetExecutionEnvironment=PROCEDURE) +SYMBOL_VECTOR=(PT_FPrintStats=PROCEDURE) +SYMBOL_VECTOR=(SetExecutionEnvironment=PROCEDURE) +! +! Start of 2,4 additions +! 51 stubs (4 thru 54) so that PR_CreateThread ends up at 1B70. +! Over time some of these stubs will get replaced by new symbols. +! +SYMBOL_VECTOR=(PR_VMS_Stub4=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub5=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub6=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub7=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub8=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub9=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub10=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub11=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub12=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub13=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub14=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub15=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub16=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub17=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub18=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub19=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub20=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub21=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub22=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub23=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub24=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub25=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub26=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub27=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub28=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub29=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub30=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub31=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub32=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub33=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub34=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub35=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub36=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub37=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub38=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub39=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub40=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub41=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub42=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub43=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub44=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub45=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub46=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub47=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub48=PROCEDURE) +SYMBOL_VECTOR=(PR_GetAddrInfoByName=PROCEDURE) ! was Stub49 +SYMBOL_VECTOR=(PR_FreeAddrInfo=PROCEDURE) ! was Stub50 +SYMBOL_VECTOR=(PR_EnumerateAddrInfo=PROCEDURE) ! was Stub51 +SYMBOL_VECTOR=(PR_GetCanonNameFromAddrInfo=PROCEDURE) ! was Stub52 +SYMBOL_VECTOR=(PR_GetPathSeparator=PROCEDURE) ! was Stub53 +SYMBOL_VECTOR=(LL_MaxUint=PROCEDURE) ! was Stub54 +! +SYMBOL_VECTOR=(PR_CallOnceWithArg=PROCEDURE) +SYMBOL_VECTOR=(PR_GetLibraryFilePathname=PROCEDURE) +SYMBOL_VECTOR=(PR_SetError=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateThread=PROCEDURE) +! +! -------------------------------------------------------------------------- +! End of fixed section +! -------------------------------------------------------------------------- +! diff --git a/nsprpub/pr/src/os2extra.def b/nsprpub/pr/src/os2extra.def new file mode 100644 index 00000000000..8dbb34dad55 --- /dev/null +++ b/nsprpub/pr/src/os2extra.def @@ -0,0 +1,16 @@ + ; + ; Support plugins that were explicitly linked to the Visual Age + ; version of nspr4.dll. + ; + PR_NewMonitor + PR_EnterMonitor + PR_ExitMonitor + PR_GetCurrentThread + PR_AttachThread + PR_DetachThread + ; + ; Exception handler functions that are used by nsAppRunner.cpp + ; + _PR_OS2_SetFloatExcpHandler + _PR_OS2_UnsetFloatExcpHandler + diff --git a/nsprpub/pr/src/prvrsion.c b/nsprpub/pr/src/prvrsion.c new file mode 100644 index 00000000000..b8f4916dbcd --- /dev/null +++ b/nsprpub/pr/src/prvrsion.c @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#ifndef XP_MAC +#include "_pr_bld.h" +#endif +#if !defined(_BUILD_TIME) +#ifdef HAVE_LONG_LONG +#define _BUILD_TIME 0 +#else +#define _BUILD_TIME {0, 0} +#endif +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * A trick to expand the PR_VMAJOR macro before concatenation. + */ +#define CONCAT(x, y) x ## y +#define CONCAT2(x, y) CONCAT(x, y) +#define VERSION_DESC_NAME CONCAT2(prVersionDescription_libnspr, PR_VMAJOR) + +PRVersionDescription VERSION_DESC_NAME = +{ + /* 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/MPL/", + /* specialString */ "" +}; + +#ifdef XP_UNIX + +/* + * Version information for the 'ident' and 'what commands + * + * NOTE: the first component of the concatenated rcsid string + * must not end in a '$' to prevent rcs keyword substitution. + */ +static char rcsid[] = "$Header: NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING " $"; +static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING; + +#endif /* XP_UNIX */ + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void) +{ +#ifdef XP_UNIX + /* + * Add dummy references to rcsid and sccsid to prevent them + * from being optimized away as unused variables. + */ + const char *dummy; + + dummy = rcsid; + dummy = sccsid; +#endif + return &VERSION_DESC_NAME; +} /* versionEntryPointType */ + +/* prvrsion.c */ + diff --git a/nsprpub/pr/src/pthreads/.cvsignore b/nsprpub/pr/src/pthreads/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/pthreads/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/pthreads/Makefile.in b/nsprpub/pr/src/pthreads/Makefile.in new file mode 100644 index 00000000000..006a3e8cbcc --- /dev/null +++ b/nsprpub/pr/src/pthreads/Makefile.in @@ -0,0 +1,74 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +CSRCS = \ + ptio.c \ + ptsynch.c \ + ptthread.c \ + ptmisc.c \ + $(NULL) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + + diff --git a/nsprpub/pr/src/pthreads/ptio.c b/nsprpub/pr/src/pthreads/ptio.c new file mode 100644 index 00000000000..62febde289d --- /dev/null +++ b/nsprpub/pr/src/pthreads/ptio.c @@ -0,0 +1,4905 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: ptio.c +** Descritpion: Implemenation of I/O methods for pthreads +*/ + +#if defined(_PR_PTHREADS) + +#if defined(_PR_POLL_WITH_SELECT) +#if !(defined(HPUX) && defined(_USE_BIG_FDS)) +/* set fd limit for select(), before including system header files */ +#define FD_SETSIZE (16 * 1024) +#endif +#endif + +#include +#include /* for memset() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(DARWIN) +#include /* for uname */ +#endif +#if defined(SOLARIS) || defined(UNIXWARE) +#include /* to pick up FIONREAD */ +#endif +#ifdef _PR_POLL_AVAILABLE +#include +#endif +#ifdef AIX +/* To pick up sysconf() */ +#include +#include /* for dlopen */ +#else +/* To pick up getrlimit() etc. */ +#include +#include +#endif + +#ifdef SOLARIS +/* + * Define HAVE_SENDFILEV if the system has the sendfilev() system call. + * Code built this way won't run on a system without sendfilev(). + * We can define HAVE_SENDFILEV by default when the minimum release + * of Solaris that NSPR supports has sendfilev(). + */ +#ifdef HAVE_SENDFILEV + +#include + +#define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d)) + +#else + +#include /* for dlopen */ + +/* + * Match the definitions in . + */ +typedef struct sendfilevec { + int sfv_fd; /* input fd */ + uint_t sfv_flag; /* flags */ + off_t sfv_off; /* offset to start reading from */ + size_t sfv_len; /* amount of data */ +} sendfilevec_t; + +#define SFV_FD_SELF (-2) + +/* + * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *); + */ +static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL; + +#define SOLARIS_SENDFILEV(a, b, c, d) \ + (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d)) + +#endif /* HAVE_SENDFILEV */ +#endif /* SOLARIS */ + +/* + * The send_file() system call is available in AIX 4.3.2 or later. + * If this file is compiled on an older AIX system, it attempts to + * look up the send_file symbol at run time to determine whether + * we can use the faster PR_SendFile/PR_TransmitFile implementation based on + * send_file(). On AIX 4.3.2 or later, we can safely skip this + * runtime function dispatching and just use the send_file based + * implementation. + */ +#ifdef AIX +#ifdef SF_CLOSE +#define HAVE_SEND_FILE +#endif + +#ifdef HAVE_SEND_FILE + +#define AIX_SEND_FILE(a, b, c) send_file(a, b, c) + +#else /* HAVE_SEND_FILE */ + +/* + * The following definitions match those in + * on AIX 4.3.2. + */ + +/* + * Structure for the send_file() system call + */ +struct sf_parms { + /* --------- header parms ---------- */ + void *header_data; /* Input/Output. Points to header buf */ + uint_t header_length; /* Input/Output. Length of the header */ + /* --------- file parms ------------ */ + int file_descriptor; /* Input. File descriptor of the file */ + unsigned long long file_size; /* Output. Size of the file */ + unsigned long long file_offset; /* Input/Output. Starting offset */ + long long file_bytes; /* Input/Output. no. of bytes to send */ + /* --------- trailer parms --------- */ + void *trailer_data; /* Input/Output. Points to trailer buf */ + uint_t trailer_length; /* Input/Output. Length of the trailer */ + /* --------- return info ----------- */ + unsigned long long bytes_sent; /* Output. no. of bytes sent */ +}; + +/* + * Flags for the send_file() system call + */ +#define SF_CLOSE 0x00000001 /* close the socket after completion */ +#define SF_REUSE 0x00000002 /* reuse socket. not supported */ +#define SF_DONT_CACHE 0x00000004 /* don't apply network buffer cache */ +#define SF_SYNC_CACHE 0x00000008 /* sync/update network buffer cache */ + +/* + * prototype: size_t send_file(int *, struct sf_parms *, uint_t); + */ +static ssize_t (*pt_aix_sendfile_fptr)() = NULL; + +#define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c) + +#endif /* HAVE_SEND_FILE */ +#endif /* AIX */ + +#ifdef LINUX +#include +#endif + +#include "primpl.h" + +#include /* TCP_NODELAY, TCP_MAXSEG */ +#ifdef LINUX +/* TCP_CORK is not defined in on Red Hat Linux 6.0 */ +#ifndef TCP_CORK +#define TCP_CORK 3 +#endif +#endif + +#ifdef _PR_IPV6_V6ONLY_PROBE +static PRBool _pr_ipv6_v6only_on_by_default; +#endif + +#if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11)) +#define _PRSelectFdSetArg_t int * +#elif defined(AIX4_1) +#define _PRSelectFdSetArg_t void * +#elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \ + || defined(OSF1) || defined(SOLARIS) \ + || defined(HPUX10_30) || defined(HPUX11) \ + || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \ + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ + || defined(BSDI) || defined(VMS) || defined(NTO) || defined(DARWIN) \ + || defined(UNIXWARE) || defined(RISCOS) +#define _PRSelectFdSetArg_t fd_set * +#else +#error "Cannot determine architecture" +#endif + +static PRFileDesc *pt_SetMethods( + PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported); + +static PRLock *_pr_flock_lock; /* For PR_LockFile() etc. */ +static PRCondVar *_pr_flock_cv; /* For PR_LockFile() etc. */ +static PRLock *_pr_rename_lock; /* For PR_Rename() */ + +/**************************************************************************/ + +/* These two functions are only used in assertions. */ +#if defined(DEBUG) + +PRBool IsValidNetAddr(const PRNetAddr *addr) +{ + if ((addr != NULL) + && (addr->raw.family != AF_UNIX) + && (addr->raw.family != PR_AF_INET6) + && (addr->raw.family != AF_INET)) { + return PR_FALSE; + } + return PR_TRUE; +} + +static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len) +{ + /* + * The definition of the length of a Unix domain socket address + * is not uniform, so we don't check it. + */ + if ((addr != NULL) + && (addr->raw.family != AF_UNIX) + && (PR_NETADDR_SIZE(addr) != addr_len)) { +#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 + /* + * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 + * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id + * field and is 28 bytes. It is possible for socket functions + * to return an addr_len greater than sizeof(struct sockaddr_in6). + * We need to allow that. (Bugzilla bug #77264) + */ + if ((PR_AF_INET6 == addr->raw.family) + && (sizeof(addr->ipv6) == addr_len)) { + return PR_TRUE; + } +#endif + return PR_FALSE; + } + return PR_TRUE; +} + +#endif /* DEBUG */ + +/*****************************************************************************/ +/************************* I/O Continuation machinery ************************/ +/*****************************************************************************/ + +/* + * The polling interval defines the maximum amount of time that a thread + * might hang up before an interrupt is noticed. + */ +#define PT_DEFAULT_POLL_MSEC 5000 +#if defined(_PR_POLL_WITH_SELECT) +#define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC) +#define PT_DEFAULT_SELECT_USEC \ + ((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC) +#endif + +/* + * pt_SockLen is the type for the length of a socket address + * structure, used in the address length argument to bind, + * connect, accept, getsockname, getpeername, etc. Posix.1g + * defines this type as socklen_t. It is size_t or int on + * most current systems. + */ +#if defined(HAVE_SOCKLEN_T) \ + || (defined(__GLIBC__) && __GLIBC__ >= 2) +typedef socklen_t pt_SockLen; +#elif (defined(AIX) && !defined(AIX4_1)) \ + || defined(VMS) +typedef PRSize pt_SockLen; +#else +typedef PRIntn pt_SockLen; +#endif + +typedef struct pt_Continuation pt_Continuation; +typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents); + +typedef enum pr_ContuationStatus +{ + pt_continuation_pending, + pt_continuation_done +} pr_ContuationStatus; + +struct pt_Continuation +{ + /* The building of the continuation operation */ + ContinuationFn function; /* what function to continue */ + union { PRIntn osfd; } arg1; /* #1 - the op's fd */ + union { void* buffer; } arg2; /* #2 - primary transfer buffer */ + union { + PRSize amount; /* #3 - size of 'buffer', or */ + pt_SockLen *addr_len; /* - length of address */ +#ifdef HPUX11 + /* + * For sendfile() + */ + struct file_spec { + off_t offset; /* offset in file to send */ + size_t nbytes; /* length of file data to send */ + size_t st_size; /* file size */ + } file_spec; +#endif + } arg3; + union { PRIntn flags; } arg4; /* #4 - read/write flags */ + union { PRNetAddr *addr; } arg5; /* #5 - send/recv address */ + +#ifdef HPUX11 + /* + * For sendfile() + */ + int filedesc; /* descriptor of file to send */ + int nbytes_to_send; /* size of header and file */ +#endif /* HPUX11 */ + +#ifdef SOLARIS + /* + * For sendfilev() + */ + int nbytes_to_send; /* size of header and file */ +#endif /* SOLARIS */ + +#ifdef LINUX + /* + * For sendfile() + */ + int in_fd; /* descriptor of file to send */ + off_t offset; + size_t count; +#endif /* LINUX */ + + PRIntervalTime timeout; /* client (relative) timeout */ + + PRInt16 event; /* flags for poll()'s events */ + + /* + ** The representation and notification of the results of the operation. + ** These function can either return an int return code or a pointer to + ** some object. + */ + union { PRSize code; void *object; } result; + + PRIntn syserrno; /* in case it failed, why (errno) */ + pr_ContuationStatus status; /* the status of the operation */ +}; + +#if defined(DEBUG) + +PTDebug pt_debug; /* this is shared between several modules */ + +PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg) +{ + PTDebug stats; + char buffer[100]; + PRExplodedTime tod; + PRInt64 elapsed, aMil; + stats = pt_debug; /* a copy */ + PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod); + (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); + + LL_SUB(elapsed, PR_Now(), stats.timeStarted); + LL_I2L(aMil, 1000000); + LL_DIV(elapsed, elapsed, aMil); + + if (NULL != msg) PR_fprintf(debug_out, "%s", msg); + PR_fprintf( + debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed); + PR_fprintf( + debug_out, "\tlocks [created: %u, destroyed: %u]\n", + stats.locks_created, stats.locks_destroyed); + PR_fprintf( + debug_out, "\tlocks [acquired: %u, released: %u]\n", + stats.locks_acquired, stats.locks_released); + PR_fprintf( + debug_out, "\tcvars [created: %u, destroyed: %u]\n", + stats.cvars_created, stats.cvars_destroyed); + PR_fprintf( + debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n", + stats.cvars_notified, stats.delayed_cv_deletes); +} /* PT_FPrintStats */ + +#else + +PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg) +{ + /* do nothing */ +} /* PT_FPrintStats */ + +#endif /* DEBUG */ + +#if defined(_PR_POLL_WITH_SELECT) +/* + * OSF1 and HPUX report the POLLHUP event for a socket when the + * shutdown(SHUT_WR) operation is called for the remote end, even though + * the socket is still writeable. Use select(), instead of poll(), to + * workaround this problem. + */ +static void pt_poll_now_with_select(pt_Continuation *op) +{ + PRInt32 msecs; + fd_set rd, wr, *rdp, *wrp; + struct timeval tv; + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRThread *self = PR_GetCurrentThread(); + + PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout); + PR_ASSERT(op->arg1.osfd < FD_SETSIZE); + + switch (op->timeout) { + case PR_INTERVAL_NO_TIMEOUT: + tv.tv_sec = PT_DEFAULT_SELECT_SEC; + tv.tv_usec = PT_DEFAULT_SELECT_USEC; + do + { + PRIntn rv; + + if (op->event & POLLIN) { + FD_ZERO(&rd); + FD_SET(op->arg1.osfd, &rd); + rdp = &rd; + } else + rdp = NULL; + if (op->event & POLLOUT) { + FD_ZERO(&wr); + FD_SET(op->arg1.osfd, &wr); + wrp = ≀ + } else + wrp = NULL; + + rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv); + + if (self->state & PT_THREAD_ABORTED) + { + self->state &= ~PT_THREAD_ABORTED; + op->result.code = -1; + op->syserrno = EINTR; + op->status = pt_continuation_done; + return; + } + + if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) + continue; /* go around the loop again */ + + if (rv > 0) + { + PRInt16 revents = 0; + + if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd)) + revents |= POLLIN; + if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr)) + revents |= POLLOUT; + + if (op->function(op, revents)) + op->status = pt_continuation_done; + } else if (rv == -1) { + op->result.code = -1; + op->syserrno = errno; + op->status = pt_continuation_done; + } + /* else, select timed out */ + } while (pt_continuation_done != op->status); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = op->timeout; + do + { + PRIntn rv; + + if (op->event & POLLIN) { + FD_ZERO(&rd); + FD_SET(op->arg1.osfd, &rd); + rdp = &rd; + } else + rdp = NULL; + if (op->event & POLLOUT) { + FD_ZERO(&wr); + FD_SET(op->arg1.osfd, &wr); + wrp = ≀ + } else + wrp = NULL; + + wait_for_remaining = PR_TRUE; + msecs = (PRInt32)PR_IntervalToMilliseconds(remaining); + if (msecs > PT_DEFAULT_POLL_MSEC) { + wait_for_remaining = PR_FALSE; + msecs = PT_DEFAULT_POLL_MSEC; + } + tv.tv_sec = msecs/PR_MSEC_PER_SEC; + tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC; + rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv); + + if (self->state & PT_THREAD_ABORTED) + { + self->state &= ~PT_THREAD_ABORTED; + op->result.code = -1; + op->syserrno = EINTR; + op->status = pt_continuation_done; + return; + } + + if (rv > 0) { + PRInt16 revents = 0; + + if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd)) + revents |= POLLIN; + if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr)) + revents |= POLLOUT; + + if (op->function(op, revents)) + op->status = pt_continuation_done; + + } else if ((rv == 0) || + ((errno == EINTR) || (errno == EAGAIN))) { + if (rv == 0) { /* select timed out */ + if (wait_for_remaining) + now += remaining; + else + now += PR_MillisecondsToInterval(msecs); + } else + now = PR_IntervalNow(); + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= op->timeout) { + op->result.code = -1; + op->syserrno = ETIMEDOUT; + op->status = pt_continuation_done; + } else + remaining = op->timeout - elapsed; + } else { + op->result.code = -1; + op->syserrno = errno; + op->status = pt_continuation_done; + } + } while (pt_continuation_done != op->status); + break; + } + +} /* pt_poll_now_with_select */ + +#endif /* _PR_POLL_WITH_SELECT */ + +static void pt_poll_now(pt_Continuation *op) +{ + PRInt32 msecs; + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRThread *self = PR_GetCurrentThread(); + + PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout); +#if defined (_PR_POLL_WITH_SELECT) + /* + * If the fd is small enough call the select-based poll operation + */ + if (op->arg1.osfd < FD_SETSIZE) { + pt_poll_now_with_select(op); + return; + } +#endif + + switch (op->timeout) { + case PR_INTERVAL_NO_TIMEOUT: + msecs = PT_DEFAULT_POLL_MSEC; + do + { + PRIntn rv; + struct pollfd tmp_pfd; + + tmp_pfd.revents = 0; + tmp_pfd.fd = op->arg1.osfd; + tmp_pfd.events = op->event; + + rv = poll(&tmp_pfd, 1, msecs); + + if (self->state & PT_THREAD_ABORTED) + { + self->state &= ~PT_THREAD_ABORTED; + op->result.code = -1; + op->syserrno = EINTR; + op->status = pt_continuation_done; + return; + } + + if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) + continue; /* go around the loop again */ + + if (rv > 0) + { + PRInt16 events = tmp_pfd.events; + PRInt16 revents = tmp_pfd.revents; + + if ((revents & POLLNVAL) /* busted in all cases */ + || ((events & POLLOUT) && (revents & POLLHUP))) + /* write op & hup */ + { + op->result.code = -1; + if (POLLNVAL & revents) op->syserrno = EBADF; + else if (POLLHUP & revents) op->syserrno = EPIPE; + op->status = pt_continuation_done; + } else { + if (op->function(op, revents)) + op->status = pt_continuation_done; + } + } else if (rv == -1) { + op->result.code = -1; + op->syserrno = errno; + op->status = pt_continuation_done; + } + /* else, poll timed out */ + } while (pt_continuation_done != op->status); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = op->timeout; + do + { + PRIntn rv; + struct pollfd tmp_pfd; + + tmp_pfd.revents = 0; + tmp_pfd.fd = op->arg1.osfd; + tmp_pfd.events = op->event; + + wait_for_remaining = PR_TRUE; + msecs = (PRInt32)PR_IntervalToMilliseconds(remaining); + if (msecs > PT_DEFAULT_POLL_MSEC) + { + wait_for_remaining = PR_FALSE; + msecs = PT_DEFAULT_POLL_MSEC; + } + rv = poll(&tmp_pfd, 1, msecs); + + if (self->state & PT_THREAD_ABORTED) + { + self->state &= ~PT_THREAD_ABORTED; + op->result.code = -1; + op->syserrno = EINTR; + op->status = pt_continuation_done; + return; + } + + if (rv > 0) + { + PRInt16 events = tmp_pfd.events; + PRInt16 revents = tmp_pfd.revents; + + if ((revents & POLLNVAL) /* busted in all cases */ + || ((events & POLLOUT) && (revents & POLLHUP))) + /* write op & hup */ + { + op->result.code = -1; + if (POLLNVAL & revents) op->syserrno = EBADF; + else if (POLLHUP & revents) op->syserrno = EPIPE; + op->status = pt_continuation_done; + } else { + if (op->function(op, revents)) + { + op->status = pt_continuation_done; + } + } + } else if ((rv == 0) || + ((errno == EINTR) || (errno == EAGAIN))) { + if (rv == 0) /* poll timed out */ + { + if (wait_for_remaining) + now += remaining; + else + now += PR_MillisecondsToInterval(msecs); + } + else + now = PR_IntervalNow(); + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= op->timeout) { + op->result.code = -1; + op->syserrno = ETIMEDOUT; + op->status = pt_continuation_done; + } else + remaining = op->timeout - elapsed; + } else { + op->result.code = -1; + op->syserrno = errno; + op->status = pt_continuation_done; + } + } while (pt_continuation_done != op->status); + break; + } + +} /* pt_poll_now */ + +static PRIntn pt_Continue(pt_Continuation *op) +{ + op->status = pt_continuation_pending; /* set default value */ + /* + * let each thread call poll directly + */ + pt_poll_now(op); + PR_ASSERT(pt_continuation_done == op->status); + return op->result.code; +} /* pt_Continue */ + +/*****************************************************************************/ +/*********************** specific continuation functions *********************/ +/*****************************************************************************/ +static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents) +{ + op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd); + if (op->syserrno != 0) { + op->result.code = -1; + } else { + op->result.code = 0; + } + return PR_TRUE; /* this one is cooked */ +} /* pt_connect_cont */ + +static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents) +{ + op->syserrno = 0; + op->result.code = accept( + op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len); + if (-1 == op->result.code) + { + op->syserrno = errno; + if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno) + return PR_FALSE; /* do nothing - this one ain't finished */ + } + return PR_TRUE; +} /* pt_accept_cont */ + +static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents) +{ + /* + * Any number of bytes will complete the operation. It need + * not (and probably will not) satisfy the request. The only + * error we continue is EWOULDBLOCK|EAGAIN. + */ + op->result.code = read( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount); + op->syserrno = errno; + return ((-1 == op->result.code) && + (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_read_cont */ + +static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents) +{ + /* + * Any number of bytes will complete the operation. It need + * not (and probably will not) satisfy the request. The only + * error we continue is EWOULDBLOCK|EAGAIN. + */ +#if defined(SOLARIS) + if (0 == op->arg4.flags) + 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); +#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)) ? + PR_FALSE : PR_TRUE; +} /* pt_recv_cont */ + +static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn bytes; +#if defined(SOLARIS) + PRInt32 tmp_amount = op->arg3.amount; +#endif + /* + * We want to write the entire amount out, no matter how many + * tries it takes. Keep advancing the buffer and the decrementing + * the amount until the amount goes away. Return the total bytes + * (which should be the original amount) when finished (or an + * error). + */ +#if defined(SOLARIS) +retry: + bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount); +#else + bytes = send( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); +#endif + op->syserrno = errno; + +#if defined(SOLARIS) + /* + * The write system call has been reported to return the ERANGE error + * on occasion. Try to write in smaller chunks to workaround this bug. + */ + if ((bytes == -1) && (op->syserrno == ERANGE)) + { + if (tmp_amount > 1) + { + tmp_amount = tmp_amount/2; /* half the bytes */ + goto retry; + } + } +#endif + + if (bytes >= 0) /* this is progress */ + { + char *bp = (char*)op->arg2.buffer; + bp += bytes; /* adjust the buffer pointer */ + op->arg2.buffer = bp; + op->result.code += bytes; /* accumulate the number sent */ + op->arg3.amount -= bytes; /* and reduce the required count */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) + { + op->result.code = -1; + return PR_TRUE; + } + else return PR_FALSE; +} /* pt_send_cont */ + +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 + * the amount until the amount goes away. Return the total bytes + * (which should be the original amount) when finished (or an + * error). + */ + bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount); + op->syserrno = errno; + if (bytes >= 0) /* this is progress */ + { + char *bp = (char*)op->arg2.buffer; + bp += bytes; /* adjust the buffer pointer */ + op->arg2.buffer = bp; + op->result.code += bytes; /* accumulate the number sent */ + op->arg3.amount -= bytes; /* and reduce the required count */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) + { + op->result.code = -1; + return PR_TRUE; + } + else return PR_FALSE; +} /* pt_write_cont */ + +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 + * redefine the vector we're pointing at. We might have to + * modify an individual vector parms or we might have to eliminate + * a pair altogether. + */ + bytes = writev(op->arg1.osfd, iov, op->arg3.amount); + op->syserrno = errno; + if (bytes >= 0) /* this is progress */ + { + PRIntn iov_index; + op->result.code += bytes; /* accumulate the number sent */ + for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index) + { + /* how much progress did we make in the i/o vector? */ + if (bytes < iov[iov_index].iov_len) + { + /* this element's not done yet */ + char **bp = (char**)&(iov[iov_index].iov_base); + iov[iov_index].iov_len -= bytes; /* there's that much left */ + *bp += bytes; /* starting there */ + break; /* go off and do that */ + } + bytes -= iov[iov_index].iov_len; /* that element's consumed */ + } + op->arg2.buffer = &iov[iov_index]; /* new start of array */ + op->arg3.amount -= iov_index; /* and array length */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) + { + op->result.code = -1; + return PR_TRUE; + } + else return PR_FALSE; +} /* pt_writev_cont */ + +static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn bytes = sendto( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags, + (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr)); + op->syserrno = errno; + if (bytes >= 0) /* this is progress */ + { + char *bp = (char*)op->arg2.buffer; + bp += bytes; /* adjust the buffer pointer */ + op->arg2.buffer = bp; + op->result.code += bytes; /* accumulate the number sent */ + op->arg3.amount -= bytes; /* and reduce the required count */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) + { + op->result.code = -1; + return PR_TRUE; + } + else return PR_FALSE; +} /* pt_sendto_cont */ + +static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents) +{ + pt_SockLen addr_len = sizeof(PRNetAddr); + op->result.code = recvfrom( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, + op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len); + op->syserrno = errno; + return ((-1 == op->result.code) && + (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_recvfrom_cont */ + +#ifdef AIX +static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents) +{ + struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer; + ssize_t rv; + unsigned long long saved_file_offset; + long long saved_file_bytes; + + saved_file_offset = sf_struct->file_offset; + saved_file_bytes = sf_struct->file_bytes; + sf_struct->bytes_sent = 0; + + if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0)) + PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <= + sf_struct->file_size); + rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags); + op->syserrno = errno; + + if (rv != -1) { + op->result.code += sf_struct->bytes_sent; + /* + * A bug in AIX 4.3.2 prevents the 'file_bytes' field from + * being updated. So, 'file_bytes' is maintained by NSPR to + * avoid conflict when this bug is fixed in AIX, in the future. + */ + if (saved_file_bytes != -1) + saved_file_bytes -= (sf_struct->file_offset - saved_file_offset); + sf_struct->file_bytes = saved_file_bytes; + } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { + op->result.code = -1; + } else { + return PR_FALSE; + } + + if (rv == 1) { /* more data to send */ + return PR_FALSE; + } + + return PR_TRUE; +} +#endif /* AIX */ + +#ifdef HPUX11 +static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents) +{ + struct iovec *hdtrl = (struct iovec *) op->arg2.buffer; + int count; + + count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset, + op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags); + PR_ASSERT(count <= op->nbytes_to_send); + op->syserrno = errno; + + if (count != -1) { + op->result.code += count; + } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { + op->result.code = -1; + } else { + return PR_FALSE; + } + if (count != -1 && count < op->nbytes_to_send) { + if (count < hdtrl[0].iov_len) { + /* header not sent */ + + hdtrl[0].iov_base = ((char *) hdtrl[0].iov_len) + count; + hdtrl[0].iov_len -= count; + + } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) { + /* header sent, file not sent */ + PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len; + + hdtrl[0].iov_base = NULL; + hdtrl[0].iov_len = 0; + + op->arg3.file_spec.offset += file_nbytes_sent; + op->arg3.file_spec.nbytes -= file_nbytes_sent; + } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes + + hdtrl[1].iov_len)) { + PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len + + op->arg3.file_spec.nbytes); + + /* header sent, file sent, trailer not sent */ + + hdtrl[0].iov_base = NULL; + hdtrl[0].iov_len = 0; + /* + * set file offset and len so that no more file data is + * sent + */ + op->arg3.file_spec.offset = op->arg3.file_spec.st_size; + op->arg3.file_spec.nbytes = 0; + + hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent; + hdtrl[1].iov_len -= trailer_nbytes_sent; + } + op->nbytes_to_send -= count; + return PR_FALSE; + } + + return PR_TRUE; +} +#endif /* HPUX11 */ + +#ifdef SOLARIS +static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents) +{ + struct sendfilevec *vec = (struct sendfilevec *) op->arg2.buffer; + size_t xferred; + ssize_t count; + + count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred); + op->syserrno = errno; + PR_ASSERT((count == -1) || (count == xferred)); + + if (count == -1) { + if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN + && op->syserrno != EINTR) { + op->result.code = -1; + return PR_TRUE; + } + count = xferred; + } else if (count == 0) { + /* + * We are now at EOF. The file was truncated. Solaris sendfile is + * supposed to return 0 and no error in this case, though some versions + * may return -1 and EINVAL . + */ + op->result.code = -1; + op->syserrno = 0; /* will be treated as EOF */ + return PR_TRUE; + } + PR_ASSERT(count <= op->nbytes_to_send); + + op->result.code += count; + if (count < op->nbytes_to_send) { + op->nbytes_to_send -= count; + + while (count >= vec->sfv_len) { + count -= vec->sfv_len; + vec++; + op->arg3.amount--; + } + PR_ASSERT(op->arg3.amount > 0); + + vec->sfv_off += count; + vec->sfv_len -= count; + PR_ASSERT(vec->sfv_len > 0); + op->arg2.buffer = vec; + + return PR_FALSE; + } + + return PR_TRUE; +} +#endif /* SOLARIS */ + +#ifdef LINUX +static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents) +{ + ssize_t rv; + off_t oldoffset; + + oldoffset = op->offset; + rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count); + op->syserrno = errno; + + if (rv == -1) { + if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { + op->result.code = -1; + return PR_TRUE; + } + rv = 0; + } + PR_ASSERT(rv == op->offset - oldoffset); + op->result.code += rv; + if (rv < op->count) { + op->count -= rv; + return PR_FALSE; + } + return PR_TRUE; +} +#endif /* LINUX */ + +void _PR_InitIO(void) +{ +#if defined(DEBUG) + memset(&pt_debug, 0, sizeof(PTDebug)); + pt_debug.timeStarted = PR_Now(); +#endif + + _pr_flock_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_flock_lock); + _pr_flock_cv = PR_NewCondVar(_pr_flock_lock); + PR_ASSERT(NULL != _pr_flock_cv); + _pr_rename_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_rename_lock); + + _PR_InitFdCache(); /* do that */ + + _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE); + _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE); + _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE); + PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr); + +#ifdef _PR_IPV6_V6ONLY_PROBE + /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option + * is turned on by default, contrary to what RFC 3493, Section + * 5.3 says. So we have to turn it off. Find out whether we + * are running on such a system. + */ + { + int osfd; + osfd = socket(AF_INET6, SOCK_STREAM, 0); + if (osfd != -1) { + int on; + int optlen = sizeof(on); + if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, + &on, &optlen) == 0) { + _pr_ipv6_v6only_on_by_default = on; + } + close(osfd); + } + } +#endif +} /* _PR_InitIO */ + +void _PR_CleanupIO(void) +{ + _PR_Putfd(_pr_stdin); + _pr_stdin = NULL; + _PR_Putfd(_pr_stdout); + _pr_stdout = NULL; + _PR_Putfd(_pr_stderr); + _pr_stderr = NULL; + + _PR_CleanupFdCache(); + + if (_pr_flock_cv) + { + PR_DestroyCondVar(_pr_flock_cv); + _pr_flock_cv = NULL; + } + if (_pr_flock_lock) + { + PR_DestroyLock(_pr_flock_lock); + _pr_flock_lock = NULL; + } + if (_pr_rename_lock) + { + PR_DestroyLock(_pr_rename_lock); + _pr_rename_lock = NULL; + } +} /* _PR_CleanupIO */ + +PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd) +{ + PRFileDesc *result = NULL; + PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError); + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + switch (osfd) + { + case PR_StandardInput: result = _pr_stdin; break; + case PR_StandardOutput: result = _pr_stdout; break; + case PR_StandardError: result = _pr_stderr; break; + default: + (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + } + return result; +} /* PR_GetSpecialFD */ + +/*****************************************************************************/ +/***************************** I/O private methods ***************************/ +/*****************************************************************************/ + +static PRBool pt_TestAbort(void) +{ + PRThread *me = PR_GetCurrentThread(); + if(_PT_THREAD_INTERRUPTED(me)) + { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + me->state &= ~PT_THREAD_ABORTED; + return PR_TRUE; + } + return PR_FALSE; +} /* pt_TestAbort */ + +static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno) +{ + switch (syserrno) + { + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break; + case ETIMEDOUT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break; + default: + mapper(syserrno); + } +} /* pt_MapError */ + +static PRStatus pt_Close(PRFileDesc *fd) +{ + 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; + } + if (pt_TestAbort()) return PR_FAILURE; + + if (_PR_FILEDESC_OPEN == fd->secret->state) + { + if (-1 == close(fd->secret->md.osfd)) + { +#ifdef OSF1 + /* + * Bug 86941: On Tru64 UNIX V5.0A and V5.1, the close() + * system call, when called to close a TCP socket, may + * return -1 with errno set to EINVAL but the system call + * does close the socket successfully. An application + * may safely ignore the EINVAL error. This bug is fixed + * on Tru64 UNIX V5.1A and later. The defect tracking + * number is QAR 81431. + */ + if (PR_DESC_SOCKET_TCP != fd->methods->file_type + || EINVAL != errno) + { + pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno); + return PR_FAILURE; + } +#else + pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno); + return PR_FAILURE; +#endif + } + fd->secret->state = _PR_FILEDESC_CLOSED; + } + _PR_Putfd(fd); + return PR_SUCCESS; +} /* pt_Close */ + +static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + PRInt32 syserrno, bytes = -1; + + if (pt_TestAbort()) return bytes; + + bytes = read(fd->secret->md.osfd, buf, amount); + syserrno = errno; + + if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking)) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = buf; + op.arg3.amount = amount; + op.timeout = PR_INTERVAL_NO_TIMEOUT; + op.function = pt_read_cont; + op.event = POLLIN | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + if (bytes < 0) + pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno); + return bytes; +} /* pt_Read */ + +static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + PRInt32 syserrno, bytes = -1; + PRBool fNeedContinue = PR_FALSE; + + if (pt_TestAbort()) return bytes; + + bytes = write(fd->secret->md.osfd, buf, amount); + syserrno = errno; + + if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) ) + { + buf = (char *) buf + bytes; + amount -= bytes; + fNeedContinue = PR_TRUE; + } + if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking) ) + { + bytes = 0; + fNeedContinue = PR_TRUE; + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)buf; + op.arg3.amount = amount; + op.timeout = PR_INTERVAL_NO_TIMEOUT; + op.result.code = bytes; /* initialize the number sent */ + op.function = pt_write_cont; + op.event = POLLOUT | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + if (bytes == -1) + pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno); + return bytes; +} /* pt_Write */ + +static PRInt32 pt_Writev( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout) +{ + PRIntn iov_index; + PRBool fNeedContinue = PR_FALSE; + PRInt32 syserrno, bytes, rv = -1; + struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov; + int osiov_len; + + if (pt_TestAbort()) return rv; + + /* Ensured by PR_Writev */ + PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE); + + /* + * We can't pass iov to writev because PRIOVec and struct iovec + * may not be binary compatible. Make osiov a copy of iov and + * pass osiov to writev. We can modify osiov if we need to + * continue the operation. + */ + osiov = osiov_local; + osiov_len = iov_len; + for (iov_index = 0; iov_index < osiov_len; iov_index++) + { + osiov[iov_index].iov_base = iov[iov_index].iov_base; + osiov[iov_index].iov_len = iov[iov_index].iov_len; + } + + rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len); + syserrno = errno; + + if (!fd->secret->nonblocking) + { + if (bytes >= 0) + { + /* + * If we moved some bytes, how does that implicate the + * i/o vector list? In other words, exactly where are + * we within that array? What are the parameters for + * resumption? Maybe we're done! + */ + for ( ;osiov_len > 0; osiov++, osiov_len--) + { + if (bytes < osiov->iov_len) + { + /* this one's not done yet */ + osiov->iov_base = (char*)osiov->iov_base + bytes; + osiov->iov_len -= bytes; + break; /* go off and do that */ + } + bytes -= osiov->iov_len; /* this one's done cooked */ + } + PR_ASSERT(osiov_len > 0 || bytes == 0); + if (osiov_len > 0) + { + if (PR_INTERVAL_NO_WAIT == timeout) + { + rv = -1; + syserrno = ETIMEDOUT; + } + else fNeedContinue = PR_TRUE; + } + } + else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + rv = 0; + fNeedContinue = PR_TRUE; + } + } + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)osiov; + op.arg3.amount = osiov_len; + op.timeout = timeout; + op.result.code = rv; + op.function = pt_writev_cont; + op.event = POLLOUT | POLLPRI; + rv = pt_Continue(&op); + syserrno = op.syserrno; + } + if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno); + return rv; +} /* pt_Writev */ + +static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) +{ + return _PR_MD_LSEEK(fd, offset, whence); +} /* pt_Seek */ + +static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) +{ + return _PR_MD_LSEEK64(fd, offset, whence); +} /* pt_Seek64 */ + +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; + + rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes); + + if (rv == -1) + pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno); + return bytes; +} /* pt_Available_s */ + +static PRInt64 pt_Available64_s(PRFileDesc *fd) +{ + PRInt64 rv; + LL_I2L(rv, pt_Available_s(fd)); + return rv; +} /* pt_Available64_s */ + +static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info) +{ + PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info); + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* pt_FileInfo */ + +static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info) +{ + 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; + if (pt_TestAbort()) return PR_FAILURE; + + rv = fsync(fd->secret->md.osfd); + if (rv < 0) { + pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Fsync */ + +static PRStatus pt_Connect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRIntn rv = -1, syserrno; + pt_SockLen addr_len; + const PRNetAddr *addrp = addr; +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) + PRUint16 md_af = addr->raw.family; + PRNetAddr addrCopy; +#endif + + if (pt_TestAbort()) return PR_FAILURE; + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + addr_len = PR_NETADDR_SIZE(addr); +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + md_af = AF_INET6; +#ifndef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; +#endif + } +#endif + +#ifdef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + ((struct sockaddr*)&addrCopy)->sa_len = addr_len; + ((struct sockaddr*)&addrCopy)->sa_family = md_af; + addrp = &addrCopy; +#endif + rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len); + syserrno = errno; + if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking)) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)addrp; + op.arg3.amount = addr_len; + op.timeout = timeout; + op.function = pt_connect_cont; + op.event = POLLOUT | POLLPRI; + rv = pt_Continue(&op); + syserrno = op.syserrno; + } + } + if (-1 == rv) { + pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Connect */ + +static PRStatus pt_ConnectContinue( + PRFileDesc *fd, PRInt16 out_flags) +{ + int err; + PRInt32 osfd; + + if (out_flags & PR_POLL_NVAL) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) + { + PR_ASSERT(out_flags == 0); + PR_SetError(PR_IN_PROGRESS_ERROR, 0); + return PR_FAILURE; + } + + osfd = fd->secret->md.osfd; + + err = _MD_unix_get_nonblocking_connect_error(osfd); + if (err != 0) + { + _PR_MD_MAP_CONNECT_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_ConnectContinue */ + +PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd) +{ + /* Find the NSPR layer and invoke its connectcontinue method */ + PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + + if (NULL == bottom) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + return pt_ConnectContinue(bottom, pd->out_flags); +} /* PR_GetConnectStatus */ + +static PRFileDesc* pt_Accept( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRFileDesc *newfd = NULL; + PRIntn syserrno, osfd = -1; + pt_SockLen addr_len = sizeof(PRNetAddr); + + if (pt_TestAbort()) return newfd; + +#ifdef _PR_STRICT_ADDR_LEN + if (addr) + { + /* + * Set addr->raw.family just so that we can use the + * PR_NETADDR_SIZE macro. + */ + addr->raw.family = fd->secret->af; + addr_len = PR_NETADDR_SIZE(addr); + } +#endif + + osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); + syserrno = errno; + + if (osfd == -1) + { + if (fd->secret->nonblocking) goto failed; + + if (EWOULDBLOCK != syserrno && EAGAIN != syserrno + && ECONNABORTED != syserrno) + goto failed; + else + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = addr; + op.arg3.addr_len = &addr_len; + op.timeout = timeout; + op.function = pt_accept_cont; + op.event = POLLIN | POLLPRI; + osfd = pt_Continue(&op); + syserrno = op.syserrno; + } + if (osfd < 0) goto failed; + } + } +#ifdef _PR_HAVE_SOCKADDR_LEN + /* ignore the sa_len field of struct sockaddr */ + if (addr) + { + addr->raw.family = ((struct sockaddr*)addr)->sa_family; + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ +#ifdef _PR_INET6 + if (addr && (AF_INET6 == addr->raw.family)) + addr->raw.family = PR_AF_INET6; +#endif + newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE); + if (newfd == NULL) close(osfd); /* $$$ whoops! this doesn't work $$$ */ + else + { + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); +#ifdef LINUX + /* + * On Linux, experiments showed that the accepted sockets + * inherit the TCP_NODELAY socket option of the listening + * socket. + */ + newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay; +#endif + } + return newfd; + +failed: + pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno); + return NULL; +} /* pt_Accept */ + +static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr) +{ + PRIntn rv; + pt_SockLen addr_len; + const PRNetAddr *addrp = addr; +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) + PRUint16 md_af = addr->raw.family; + PRNetAddr addrCopy; +#endif + + if (pt_TestAbort()) return PR_FAILURE; + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + if (addr->raw.family == AF_UNIX) + { + /* Disallow relative pathnames */ + if (addr->local.path[0] != '/') + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + } + +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + md_af = AF_INET6; +#ifndef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; +#endif + } +#endif + + addr_len = PR_NETADDR_SIZE(addr); +#ifdef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + ((struct sockaddr*)&addrCopy)->sa_len = addr_len; + ((struct sockaddr*)&addrCopy)->sa_family = md_af; + addrp = &addrCopy; +#endif + rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len); + + if (rv == -1) { + pt_MapError(_PR_MD_MAP_BIND_ERROR, errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Bind */ + +static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog) +{ + PRIntn rv; + + if (pt_TestAbort()) return PR_FAILURE; + + rv = listen(fd->secret->md.osfd, backlog); + if (rv == -1) { + pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Listen */ + +static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how) +{ + PRIntn rv = -1; + if (pt_TestAbort()) return PR_FAILURE; + + rv = shutdown(fd->secret->md.osfd, how); + + if (rv == -1) { + pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Shutdown */ + +static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + *out_flags = 0; + return in_flags; +} /* pt_Poll */ + +static PRInt32 pt_Recv( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + PRInt32 syserrno, bytes = -1; + PRIntn osflags; + + if (0 == flags) + osflags = 0; + else if (PR_MSG_PEEK == flags) + osflags = MSG_PEEK; + else + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return bytes; + } + + if (pt_TestAbort()) return bytes; + + /* recv() is a much slower call on pre-2.6 Solaris than read(). */ +#if defined(SOLARIS) + if (0 == osflags) + bytes = read(fd->secret->md.osfd, buf, amount); + else + bytes = recv(fd->secret->md.osfd, buf, amount, osflags); +#else + bytes = recv(fd->secret->md.osfd, buf, amount, osflags); +#endif + syserrno = errno; + + if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking)) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = buf; + op.arg3.amount = amount; + op.arg4.flags = osflags; + op.timeout = timeout; + op.function = pt_recv_cont; + op.event = POLLIN | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + } + if (bytes < 0) + pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno); + return bytes; +} /* pt_Recv */ + +static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); +} /* pt_SocketRead */ + +static PRInt32 pt_Send( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + PRInt32 syserrno, bytes = -1; + PRBool fNeedContinue = PR_FALSE; +#if defined(SOLARIS) + PRInt32 tmp_amount = amount; +#endif + + /* + * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h, + * which has the following: + * # define send cma_send + * extern int cma_send (int , void *, int, int ); + * So we need to cast away the 'const' of argument #2 for send(). + */ +#if defined (HPUX) && defined(_PR_DCETHREADS) +#define PT_SENDBUF_CAST (void *) +#else +#define PT_SENDBUF_CAST +#endif + + 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); +retry: + bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount); +#else + bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags); +#endif + syserrno = errno; + +#if defined(SOLARIS) + /* + * The write system call has been reported to return the ERANGE error + * on occasion. Try to write in smaller chunks to workaround this bug. + */ + if ((bytes == -1) && (syserrno == ERANGE)) + { + if (tmp_amount > 1) + { + tmp_amount = tmp_amount/2; /* half the bytes */ + goto retry; + } + } +#endif + + if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) ) + { + if (PR_INTERVAL_NO_WAIT == timeout) + { + bytes = -1; + syserrno = ETIMEDOUT; + } + else + { + buf = (char *) buf + bytes; + amount -= bytes; + fNeedContinue = PR_TRUE; + } + } + if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking) ) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + bytes = 0; + fNeedContinue = PR_TRUE; + } + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.timeout = timeout; + op.result.code = bytes; /* initialize the number sent */ + op.function = pt_send_cont; + op.event = POLLOUT | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + if (bytes == -1) + pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno); + return bytes; +} /* pt_Send */ + +static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); +} /* pt_SocketWrite */ + +static PRInt32 pt_SendTo( + PRFileDesc *fd, const void *buf, + PRInt32 amount, PRIntn flags, const PRNetAddr *addr, + PRIntervalTime timeout) +{ + PRInt32 syserrno, bytes = -1; + PRBool fNeedContinue = PR_FALSE; + pt_SockLen addr_len; + const PRNetAddr *addrp = addr; +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) + PRUint16 md_af = addr->raw.family; + PRNetAddr addrCopy; +#endif + + if (pt_TestAbort()) return bytes; + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + md_af = AF_INET6; +#ifndef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; +#endif + } +#endif + + addr_len = PR_NETADDR_SIZE(addr); +#ifdef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + ((struct sockaddr*)&addrCopy)->sa_len = addr_len; + ((struct sockaddr*)&addrCopy)->sa_family = md_af; + addrp = &addrCopy; +#endif + bytes = sendto( + fd->secret->md.osfd, buf, amount, flags, + (struct sockaddr*)addrp, addr_len); + syserrno = errno; + if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking) ) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else fNeedContinue = PR_TRUE; + } + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.arg5.addr = (PRNetAddr*)addrp; + op.timeout = timeout; + op.result.code = 0; /* initialize the number sent */ + op.function = pt_sendto_cont; + op.event = POLLOUT | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + if (bytes < 0) + pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno); + return bytes; +} /* pt_SendTo */ + +static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRBool fNeedContinue = PR_FALSE; + PRInt32 syserrno, bytes = -1; + pt_SockLen addr_len = sizeof(PRNetAddr); + + if (pt_TestAbort()) return bytes; + + bytes = recvfrom( + fd->secret->md.osfd, buf, amount, flags, + (struct sockaddr*)addr, &addr_len); + syserrno = errno; + + if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking) ) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else fNeedContinue = PR_TRUE; + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.arg5.addr = addr; + op.timeout = timeout; + op.function = pt_recvfrom_cont; + op.event = POLLIN | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } +#ifdef _PR_HAVE_SOCKADDR_LEN + if (bytes >= 0) + { + /* ignore the sa_len field of struct sockaddr */ + if (addr) + { + addr->raw.family = ((struct sockaddr*)addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ +#ifdef _PR_INET6 + if (addr && (AF_INET6 == addr->raw.family)) + addr->raw.family = PR_AF_INET6; +#endif + if (bytes < 0) + pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno); + return bytes; +} /* pt_RecvFrom */ + +#ifdef AIX +#ifndef HAVE_SEND_FILE +static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT; + +static void pt_aix_sendfile_init_routine(void) +{ + void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); + pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file"); + dlclose(handle); +} + +/* + * pt_AIXDispatchSendFile + */ +static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + int rv; + + rv = pthread_once(&pt_aix_sendfile_once_block, + pt_aix_sendfile_init_routine); + PR_ASSERT(0 == rv); + if (pt_aix_sendfile_fptr) { + return pt_AIXSendFile(sd, sfd, flags, timeout); + } else { + return PR_EmulateSendFile(sd, sfd, flags, timeout); + } +} +#endif /* !HAVE_SEND_FILE */ + + +/* + * pt_AIXSendFile + * + * Send file sfd->fd across socket sd. If specified, header and trailer + * buffers are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + * This implementation takes advantage of the send_file() system + * call available in AIX 4.3.2. + */ + +static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + struct sf_parms sf_struct; + uint_t send_flags; + ssize_t rv; + int syserrno; + PRInt32 count; + unsigned long long saved_file_offset; + long long saved_file_bytes; + + sf_struct.header_data = (void *) sfd->header; /* cast away the 'const' */ + sf_struct.header_length = sfd->hlen; + sf_struct.file_descriptor = sfd->fd->secret->md.osfd; + sf_struct.file_size = 0; + sf_struct.file_offset = sfd->file_offset; + if (sfd->file_nbytes == 0) + sf_struct.file_bytes = -1; + else + sf_struct.file_bytes = sfd->file_nbytes; + sf_struct.trailer_data = (void *) sfd->trailer; + sf_struct.trailer_length = sfd->tlen; + sf_struct.bytes_sent = 0; + + saved_file_offset = sf_struct.file_offset; + saved_file_bytes = sf_struct.file_bytes; + + send_flags = 0; /* flags processed at the end */ + + /* The first argument to send_file() is int*. */ + PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd)); + do { + rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags); + } while (rv == -1 && (syserrno = errno) == EINTR); + + if (rv == -1) { + if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) { + count = 0; /* Not a real error. Need to continue. */ + } else { + count = -1; + } + } else { + count = sf_struct.bytes_sent; + /* + * A bug in AIX 4.3.2 prevents the 'file_bytes' field from + * being updated. So, 'file_bytes' is maintained by NSPR to + * avoid conflict when this bug is fixed in AIX, in the future. + */ + if (saved_file_bytes != -1) + saved_file_bytes -= (sf_struct.file_offset - saved_file_offset); + sf_struct.file_bytes = saved_file_bytes; + } + + if ((rv == 1) || ((rv == -1) && (count == 0))) { + pt_Continuation op; + + op.arg1.osfd = sd->secret->md.osfd; + op.arg2.buffer = &sf_struct; + op.arg4.flags = send_flags; + op.result.code = count; + op.timeout = timeout; + op.function = pt_aix_sendfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + } + + if (count == -1) { + pt_MapError(_MD_aix_map_sendfile_error, syserrno); + return -1; + } + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + PR_ASSERT(count == (sfd->hlen + sfd->tlen + + ((sfd->file_nbytes == 0) ? + sf_struct.file_size - sfd->file_offset : + sfd->file_nbytes))); + return count; +} +#endif /* AIX */ + +#ifdef HPUX11 +/* + * pt_HPUXSendFile + * + * Send file sfd->fd across socket sd. If specified, header and trailer + * buffers are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + * This implementation takes advantage of the sendfile() system + * call available in HP-UX B.11.00. + */ + +static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + struct stat statbuf; + size_t nbytes_to_send, file_nbytes_to_send; + struct iovec hdtrl[2]; /* optional header and trailer buffers */ + int send_flags; + PRInt32 count; + int syserrno; + + if (sfd->file_nbytes == 0) { + /* Get file size */ + if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { + _PR_MD_MAP_FSTAT_ERROR(errno); + return -1; + } + file_nbytes_to_send = statbuf.st_size - sfd->file_offset; + } else { + file_nbytes_to_send = sfd->file_nbytes; + } + nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send; + + hdtrl[0].iov_base = (void *) sfd->header; /* cast away the 'const' */ + hdtrl[0].iov_len = sfd->hlen; + hdtrl[1].iov_base = (void *) sfd->trailer; + hdtrl[1].iov_len = sfd->tlen; + /* + * SF_DISCONNECT seems to close the socket even if sendfile() + * only does a partial send on a nonblocking socket. This + * would prevent the subsequent sendfile() calls on that socket + * from working. So we don't use the SD_DISCONNECT flag. + */ + send_flags = 0; + + do { + count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd, + sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags); + } while (count == -1 && (syserrno = errno) == EINTR); + + if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) { + count = 0; + } + if (count != -1 && count < nbytes_to_send) { + pt_Continuation op; + + if (count < sfd->hlen) { + /* header not sent */ + + hdtrl[0].iov_base = ((char *) sfd->header) + count; + hdtrl[0].iov_len = sfd->hlen - count; + op.arg3.file_spec.offset = sfd->file_offset; + op.arg3.file_spec.nbytes = file_nbytes_to_send; + } else if (count < (sfd->hlen + file_nbytes_to_send)) { + /* header sent, file not sent */ + + hdtrl[0].iov_base = NULL; + hdtrl[0].iov_len = 0; + + op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen; + op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen); + } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) { + PRUint32 trailer_nbytes_sent; + + /* header sent, file sent, trailer not sent */ + + hdtrl[0].iov_base = NULL; + hdtrl[0].iov_len = 0; + /* + * set file offset and len so that no more file data is + * sent + */ + op.arg3.file_spec.offset = statbuf.st_size; + op.arg3.file_spec.nbytes = 0; + + trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send; + hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent; + hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent; + } + + op.arg1.osfd = sd->secret->md.osfd; + op.filedesc = sfd->fd->secret->md.osfd; + op.arg2.buffer = hdtrl; + op.arg3.file_spec.st_size = statbuf.st_size; + op.arg4.flags = send_flags; + op.nbytes_to_send = nbytes_to_send - count; + op.result.code = count; + op.timeout = timeout; + op.function = pt_hpux_sendfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + } + + if (count == -1) { + pt_MapError(_MD_hpux_map_sendfile_error, syserrno); + return -1; + } + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + PR_ASSERT(count == nbytes_to_send); + return count; +} + +#endif /* HPUX11 */ + +#ifdef SOLARIS + +/* + * pt_SolarisSendFile + * + * Send file sfd->fd across socket sd. If specified, header and trailer + * buffers are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + * This implementation takes advantage of the sendfilev() system + * call available in Solaris 8. + */ + +static PRInt32 pt_SolarisSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + struct stat statbuf; + size_t nbytes_to_send, file_nbytes_to_send; + struct sendfilevec sfv_struct[3]; + int sfvcnt = 0; + size_t xferred; + PRInt32 count; + int syserrno; + + if (sfd->file_nbytes == 0) { + /* Get file size */ + if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { + _PR_MD_MAP_FSTAT_ERROR(errno); + return -1; + } + file_nbytes_to_send = statbuf.st_size - sfd->file_offset; + } else { + file_nbytes_to_send = sfd->file_nbytes; + } + + nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send; + + if (sfd->hlen != 0) { + sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF; + sfv_struct[sfvcnt].sfv_flag = 0; + sfv_struct[sfvcnt].sfv_off = (off_t) sfd->header; + sfv_struct[sfvcnt].sfv_len = sfd->hlen; + sfvcnt++; + } + + if (file_nbytes_to_send != 0) { + sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd; + sfv_struct[sfvcnt].sfv_flag = 0; + sfv_struct[sfvcnt].sfv_off = sfd->file_offset; + sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send; + sfvcnt++; + } + + if (sfd->tlen != 0) { + sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF; + sfv_struct[sfvcnt].sfv_flag = 0; + sfv_struct[sfvcnt].sfv_off = (off_t) sfd->trailer; + sfv_struct[sfvcnt].sfv_len = sfd->tlen; + sfvcnt++; + } + + if (0 == sfvcnt) { + count = 0; + goto done; + } + + /* + * Strictly speaking, we may have sent some bytes when the + * sendfilev() is interrupted and we should retry it from an + * updated offset. We are not doing that here. + */ + count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct, + sfvcnt, &xferred); + + PR_ASSERT((count == -1) || (count == xferred)); + + if (count == -1) { + syserrno = errno; + if (syserrno == EINTR + || syserrno == EAGAIN || syserrno == EWOULDBLOCK) { + count = xferred; + } + } else if (count == 0) { + /* + * We are now at EOF. The file was truncated. Solaris sendfile is + * supposed to return 0 and no error in this case, though some versions + * may return -1 and EINVAL . + */ + count = -1; + syserrno = 0; /* will be treated as EOF */ + } + + if (count != -1 && count < nbytes_to_send) { + pt_Continuation op; + struct sendfilevec *vec = sfv_struct; + PRInt32 rem = count; + + while (rem >= vec->sfv_len) { + rem -= vec->sfv_len; + vec++; + sfvcnt--; + } + PR_ASSERT(sfvcnt > 0); + + vec->sfv_off += rem; + vec->sfv_len -= rem; + PR_ASSERT(vec->sfv_len > 0); + + op.arg1.osfd = sd->secret->md.osfd; + op.arg2.buffer = vec; + op.arg3.amount = sfvcnt; + op.arg4.flags = 0; + op.nbytes_to_send = nbytes_to_send - count; + op.result.code = count; + op.timeout = timeout; + op.function = pt_solaris_sendfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + } + +done: + if (count == -1) { + pt_MapError(_MD_solaris_map_sendfile_error, syserrno); + return -1; + } + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + PR_ASSERT(count == nbytes_to_send); + return count; +} + +#ifndef HAVE_SENDFILEV +static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT; + +static void pt_solaris_sendfilev_init_routine(void) +{ + void *handle; + PRBool close_it = PR_FALSE; + + /* + * We do not want to unload libsendfile.so. This handle is leaked + * intentionally. + */ + handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL); + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("dlopen(libsendfile.so) returns %p", handle)); + + if (NULL == handle) { + /* + * The dlopen(0, mode) call is to allow for the possibility that + * sendfilev() may become part of a standard system library in a + * future Solaris release. + */ + handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL); + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("dlopen(0) returns %p", handle)); + close_it = PR_TRUE; + } + pt_solaris_sendfilev_fptr = (ssize_t (*)()) dlsym(handle, "sendfilev"); + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr)); + + if (close_it) { + dlclose(handle); + } +} + +/* + * pt_SolarisDispatchSendFile + */ +static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + int rv; + + rv = pthread_once(&pt_solaris_sendfilev_once_block, + pt_solaris_sendfilev_init_routine); + PR_ASSERT(0 == rv); + if (pt_solaris_sendfilev_fptr) { + return pt_SolarisSendFile(sd, sfd, flags, timeout); + } else { + return PR_EmulateSendFile(sd, sfd, flags, timeout); + } +} +#endif /* !HAVE_SENDFILEV */ + +#endif /* SOLARIS */ + +#ifdef LINUX +/* + * pt_LinuxSendFile + * + * Send file sfd->fd across socket sd. If specified, header and trailer + * buffers are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + * This implementation takes advantage of the sendfile() system + * call available in Linux kernel 2.2 or higher. + */ + +static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + struct stat statbuf; + size_t file_nbytes_to_send; + PRInt32 count = 0; + ssize_t rv; + int syserrno; + off_t offset; + PRBool tcp_cork_enabled = PR_FALSE; + int tcp_cork; + + if (sfd->file_nbytes == 0) { + /* Get file size */ + if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { + _PR_MD_MAP_FSTAT_ERROR(errno); + return -1; + } + file_nbytes_to_send = statbuf.st_size - sfd->file_offset; + } else { + file_nbytes_to_send = sfd->file_nbytes; + } + + if ((sfd->hlen != 0 || sfd->tlen != 0) + && sd->secret->md.tcp_nodelay == 0) { + tcp_cork = 1; + if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, + &tcp_cork, sizeof tcp_cork) == 0) { + tcp_cork_enabled = PR_TRUE; + } else { + syserrno = errno; + if (syserrno != EINVAL) { + _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno); + return -1; + } + /* + * The most likely reason for the EINVAL error is that + * TCP_NODELAY is set (with a function other than + * PR_SetSocketOption). This is not fatal, so we keep + * on going. + */ + PR_LOG(_pr_io_lm, PR_LOG_WARNING, + ("pt_LinuxSendFile: " + "setsockopt(TCP_CORK) failed with EINVAL\n")); + } + } + + if (sfd->hlen != 0) { + count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout); + if (count == -1) { + goto failed; + } + } + + if (file_nbytes_to_send != 0) { + offset = sfd->file_offset; + do { + rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd, + &offset, file_nbytes_to_send); + } while (rv == -1 && (syserrno = errno) == EINTR); + if (rv == -1) { + if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) { + _MD_linux_map_sendfile_error(syserrno); + count = -1; + goto failed; + } + rv = 0; + } + PR_ASSERT(rv == offset - sfd->file_offset); + count += rv; + + if (rv < file_nbytes_to_send) { + pt_Continuation op; + + op.arg1.osfd = sd->secret->md.osfd; + op.in_fd = sfd->fd->secret->md.osfd; + op.offset = offset; + op.count = file_nbytes_to_send - rv; + op.result.code = count; + op.timeout = timeout; + op.function = pt_linux_sendfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + if (count == -1) { + pt_MapError(_MD_linux_map_sendfile_error, syserrno); + goto failed; + } + } + } + + if (sfd->tlen != 0) { + rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); + if (rv == -1) { + count = -1; + goto failed; + } + count += rv; + } + +failed: + if (tcp_cork_enabled) { + tcp_cork = 0; + if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, + &tcp_cork, sizeof tcp_cork) == -1 && count != -1) { + _PR_MD_MAP_SETSOCKOPT_ERROR(errno); + count = -1; + } + } + if (count != -1) { + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send); + } + return count; +} +#endif /* LINUX */ + +#ifdef AIX +extern int _pr_aix_send_file_use_disabled; +#endif + +static PRInt32 pt_SendFile( + PRFileDesc *sd, PRSendFileData *sfd, + 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_HPUXSendFile(sd, sfd, flags, timeout)); +#elif defined(AIX) +#ifdef HAVE_SEND_FILE + /* + * A bug in AIX 4.3.2 results in corruption of data transferred by + * send_file(); AIX patch PTF U463956 contains the fix. A user can + * disable the use of send_file function in NSPR, when this patch is + * not installed on the system, by setting the envionment variable + * NSPR_AIX_SEND_FILE_USE_DISABLED to 1. + */ + if (_pr_aix_send_file_use_disabled) + return(PR_EmulateSendFile(sd, sfd, flags, timeout)); + else + return(pt_AIXSendFile(sd, sfd, flags, timeout)); +#else + return(PR_EmulateSendFile(sd, sfd, flags, timeout)); + /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/ +#endif /* HAVE_SEND_FILE */ +#elif defined(SOLARIS) +#ifdef HAVE_SENDFILEV + return(pt_SolarisSendFile(sd, sfd, flags, timeout)); +#else + return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout)); +#endif /* HAVE_SENDFILEV */ +#elif defined(LINUX) + return(pt_LinuxSendFile(sd, sfd, flags, timeout)); +#else + return(PR_EmulateSendFile(sd, sfd, flags, timeout)); +#endif +} + +static PRInt32 pt_TransmitFile( + PRFileDesc *sd, PRFileDesc *fd, const void *headers, + PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRSendFileData sfd; + + sfd.fd = fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = headers; + sfd.hlen = hlen; + sfd.trailer = NULL; + sfd.tlen = 0; + + return(pt_SendFile(sd, &sfd, flags, timeout)); +} /* pt_TransmitFile */ + +static PRInt32 pt_AcceptRead( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + PRInt32 rv = -1; + + if (pt_TestAbort()) return rv; + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return rv; + } + + rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); + return rv; +} /* pt_AcceptRead */ + +static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr) +{ + PRIntn rv = -1; + pt_SockLen addr_len = sizeof(PRNetAddr); + + if (pt_TestAbort()) return PR_FAILURE; + + rv = getsockname( + fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); + if (rv == -1) { + pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno); + return PR_FAILURE; + } else { +#ifdef _PR_HAVE_SOCKADDR_LEN + /* ignore the sa_len field of struct sockaddr */ + if (addr) + { + addr->raw.family = ((struct sockaddr*)addr)->sa_family; + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); + return PR_SUCCESS; + } +} /* pt_GetSockName */ + +static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) +{ + PRIntn rv = -1; + pt_SockLen addr_len = sizeof(PRNetAddr); + + if (pt_TestAbort()) return PR_FAILURE; + + rv = getpeername( + fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); + + if (rv == -1) { + pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno); + return PR_FAILURE; + } else { +#ifdef _PR_HAVE_SOCKADDR_LEN + /* ignore the sa_len field of struct sockaddr */ + if (addr) + { + addr->raw.family = ((struct sockaddr*)addr)->sa_family; + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); + return PR_SUCCESS; + } +} /* pt_GetPeerName */ + +static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data) +{ + PRIntn rv; + pt_SockLen length; + PRInt32 level, name; + + /* + * PR_SockOpt_Nonblocking is a special case that does not + * translate to a getsockopt() call + */ + if (PR_SockOpt_Nonblocking == data->option) + { + data->value.non_blocking = fd->secret->nonblocking; + return PR_SUCCESS; + } + + rv = _PR_MapOptionName(data->option, &level, &name); + if (PR_SUCCESS == rv) + { + switch (data->option) + { + case PR_SockOpt_Linger: + { + struct linger linger; + length = sizeof(linger); + rv = getsockopt( + fd->secret->md.osfd, level, name, (char *) &linger, &length); + PR_ASSERT((-1 == rv) || (sizeof(linger) == length)); + data->value.linger.polarity = + (linger.l_onoff) ? PR_TRUE : PR_FALSE; + data->value.linger.linger = + PR_SecondsToInterval(linger.l_linger); + break; + } + case PR_SockOpt_Reuseaddr: + case PR_SockOpt_Keepalive: + case PR_SockOpt_NoDelay: + case PR_SockOpt_Broadcast: + { + PRIntn value; + length = sizeof(PRIntn); + rv = getsockopt( + fd->secret->md.osfd, level, name, (char*)&value, &length); + PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); + data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE; + break; + } + case PR_SockOpt_McastLoopback: + { + PRUint8 xbool; + length = sizeof(xbool); + rv = getsockopt( + fd->secret->md.osfd, level, name, + (char*)&xbool, &length); + PR_ASSERT((-1 == rv) || (sizeof(xbool) == length)); + data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE; + break; + } + case PR_SockOpt_RecvBufferSize: + case PR_SockOpt_SendBufferSize: + case PR_SockOpt_MaxSegment: + { + PRIntn value; + length = sizeof(PRIntn); + rv = getsockopt( + fd->secret->md.osfd, level, name, (char*)&value, &length); + PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); + data->value.recv_buffer_size = value; + break; + } + case PR_SockOpt_IpTimeToLive: + case PR_SockOpt_IpTypeOfService: + { + length = sizeof(PRUintn); + rv = getsockopt( + fd->secret->md.osfd, level, name, + (char*)&data->value.ip_ttl, &length); + PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); + break; + } + case PR_SockOpt_McastTimeToLive: + { + PRUint8 ttl; + length = sizeof(ttl); + rv = getsockopt( + fd->secret->md.osfd, level, name, + (char*)&ttl, &length); + PR_ASSERT((-1 == rv) || (sizeof(ttl) == length)); + data->value.mcast_ttl = ttl; + break; + } + case PR_SockOpt_AddMember: + case PR_SockOpt_DropMember: + { + struct ip_mreq mreq; + length = sizeof(mreq); + rv = getsockopt( + fd->secret->md.osfd, level, name, (char*)&mreq, &length); + PR_ASSERT((-1 == rv) || (sizeof(mreq) == length)); + data->value.add_member.mcaddr.inet.ip = + mreq.imr_multiaddr.s_addr; + data->value.add_member.ifaddr.inet.ip = + mreq.imr_interface.s_addr; + break; + } + case PR_SockOpt_McastInterface: + { + length = sizeof(data->value.mcast_if.inet.ip); + rv = getsockopt( + fd->secret->md.osfd, level, name, + (char*)&data->value.mcast_if.inet.ip, &length); + PR_ASSERT((-1 == rv) + || (sizeof(data->value.mcast_if.inet.ip) == length)); + break; + } + default: + PR_NOT_REACHED("Unknown socket option"); + break; + } + if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno); + } + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* pt_GetSocketOption */ + +static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data) +{ + PRIntn rv; + PRInt32 level, name; + + /* + * PR_SockOpt_Nonblocking is a special case that does not + * translate to a setsockopt call. + */ + if (PR_SockOpt_Nonblocking == data->option) + { + fd->secret->nonblocking = data->value.non_blocking; + return PR_SUCCESS; + } + + rv = _PR_MapOptionName(data->option, &level, &name); + if (PR_SUCCESS == rv) + { + switch (data->option) + { + case PR_SockOpt_Linger: + { + struct linger linger; + linger.l_onoff = data->value.linger.polarity; + linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger); + rv = setsockopt( + fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger)); + break; + } + case PR_SockOpt_Reuseaddr: + case PR_SockOpt_Keepalive: + case PR_SockOpt_NoDelay: + case PR_SockOpt_Broadcast: + { + PRIntn value = (data->value.reuse_addr) ? 1 : 0; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&value, sizeof(PRIntn)); +#ifdef LINUX + /* for pt_LinuxSendFile */ + if (name == TCP_NODELAY && rv == 0) { + fd->secret->md.tcp_nodelay = value; + } +#endif + break; + } + case PR_SockOpt_McastLoopback: + { + PRUint8 xbool = data->value.mcast_loopback ? 1 : 0; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&xbool, sizeof(xbool)); + break; + } + case PR_SockOpt_RecvBufferSize: + case PR_SockOpt_SendBufferSize: + case PR_SockOpt_MaxSegment: + { + PRIntn value = data->value.recv_buffer_size; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&value, sizeof(PRIntn)); + break; + } + case PR_SockOpt_IpTimeToLive: + case PR_SockOpt_IpTypeOfService: + { + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&data->value.ip_ttl, sizeof(PRUintn)); + break; + } + case PR_SockOpt_McastTimeToLive: + { + PRUint8 ttl = data->value.mcast_ttl; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&ttl, sizeof(ttl)); + break; + } + case PR_SockOpt_AddMember: + case PR_SockOpt_DropMember: + { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = + data->value.add_member.mcaddr.inet.ip; + mreq.imr_interface.s_addr = + data->value.add_member.ifaddr.inet.ip; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&mreq, sizeof(mreq)); + break; + } + case PR_SockOpt_McastInterface: + { + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&data->value.mcast_if.inet.ip, + sizeof(data->value.mcast_if.inet.ip)); + break; + } + default: + PR_NOT_REACHED("Unknown socket option"); + break; + } + if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno); + } + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* pt_SetSocketOption */ + +/*****************************************************************************/ +/****************************** I/O method objects ***************************/ +/*****************************************************************************/ + +static PRIOMethods _pr_file_methods = { + PR_DESC_FILE, + pt_Close, + pt_Read, + pt_Write, + pt_Available_f, + pt_Available64_f, + pt_Fsync, + pt_Seek, + pt_Seek64, + pt_FileInfo, + pt_FileInfo64, + (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, + pt_Poll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods _pr_pipe_methods = { + PR_DESC_PIPE, + pt_Close, + pt_Read, + pt_Write, + pt_Available_s, + pt_Available64_s, + pt_Synch, + (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, + pt_Poll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods _pr_tcp_methods = { + PR_DESC_SOCKET_TCP, + pt_Close, + pt_SocketRead, + pt_SocketWrite, + pt_Available_s, + pt_Available64_s, + pt_Synch, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + pt_Writev, + pt_Connect, + pt_Accept, + pt_Bind, + pt_Listen, + pt_Shutdown, + pt_Recv, + pt_Send, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + pt_Poll, + pt_AcceptRead, + pt_TransmitFile, + pt_GetSockName, + pt_GetPeerName, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + pt_GetSocketOption, + pt_SetSocketOption, + pt_SendFile, + pt_ConnectContinue, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods _pr_udp_methods = { + PR_DESC_SOCKET_UDP, + pt_Close, + pt_SocketRead, + pt_SocketWrite, + pt_Available_s, + pt_Available64_s, + pt_Synch, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + pt_Writev, + pt_Connect, + (PRAcceptFN)_PR_InvalidDesc, + pt_Bind, + pt_Listen, + pt_Shutdown, + pt_Recv, + pt_Send, + pt_RecvFrom, + pt_SendTo, + pt_Poll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + pt_GetSockName, + pt_GetPeerName, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + pt_GetSocketOption, + pt_SetSocketOption, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods _pr_socketpollfd_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, + pt_Poll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +#if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \ + || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \ + || defined(AIX) || defined(FREEBSD) || defined(NETBSD) \ + || defined(OPENBSD) || defined(BSDI) || defined(VMS) || defined(NTO) \ + || defined(DARWIN) || defined(UNIXWARE) || defined(RISCOS) +#define _PR_FCNTL_FLAGS O_NONBLOCK +#else +#error "Can't determine architecture" +#endif + +/* + * Put a Unix file descriptor in non-blocking mode. + */ +static void pt_MakeFdNonblock(PRIntn osfd) +{ + PRIntn flags; + flags = fcntl(osfd, F_GETFL, 0); + flags |= _PR_FCNTL_FLAGS; + (void)fcntl(osfd, F_SETFL, flags); +} + +/* + * Put a Unix socket fd in non-blocking mode that can + * ideally be inherited by an accepted socket. + * + * Why doesn't pt_MakeFdNonblock do? This is to deal with + * the special case of HP-UX. HP-UX has three kinds of + * non-blocking modes for sockets: the fcntl() O_NONBLOCK + * and O_NDELAY flags and ioctl() FIOSNBIO request. Only + * the ioctl() FIOSNBIO form of non-blocking mode is + * inherited by an accepted socket. + * + * Other platforms just use the generic pt_MakeFdNonblock + * to put a socket in non-blocking mode. + */ +#ifdef HPUX +static void pt_MakeSocketNonblock(PRIntn osfd) +{ + PRIntn one = 1; + (void)ioctl(osfd, FIOSNBIO, &one); +} +#else +#define pt_MakeSocketNonblock pt_MakeFdNonblock +#endif + +static PRFileDesc *pt_SetMethods( + PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported) +{ + PRFileDesc *fd = _PR_Getfd(); + + if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->secret->md.osfd = osfd; + fd->secret->state = _PR_FILEDESC_OPEN; + if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN; + else + { + /* By default, a Unix fd is not closed on exec. */ +#ifdef DEBUG + PRIntn flags; + flags = fcntl(osfd, F_GETFD, 0); + PR_ASSERT(0 == flags); +#endif + fd->secret->inheritable = _PR_TRI_TRUE; + } + switch (type) + { + case PR_DESC_FILE: + fd->methods = PR_GetFileMethods(); + break; + case PR_DESC_SOCKET_TCP: + fd->methods = PR_GetTCPMethods(); +#ifdef _PR_ACCEPT_INHERIT_NONBLOCK + if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd); +#else + pt_MakeSocketNonblock(osfd); +#endif + break; + case PR_DESC_SOCKET_UDP: + fd->methods = PR_GetUDPMethods(); + pt_MakeFdNonblock(osfd); + break; + case PR_DESC_PIPE: + fd->methods = PR_GetPipeMethods(); + pt_MakeFdNonblock(osfd); + break; + default: + break; + } + } + return fd; +} /* pt_SetMethods */ + +PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void) +{ + return &_pr_file_methods; +} /* PR_GetFileMethods */ + +PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void) +{ + return &_pr_pipe_methods; +} /* PR_GetPipeMethods */ + +PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void) +{ + return &_pr_tcp_methods; +} /* PR_GetTCPMethods */ + +PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void) +{ + return &_pr_udp_methods; +} /* PR_GetUDPMethods */ + +static const PRIOMethods* PR_GetSocketPollFdMethods(void) +{ + return &_pr_socketpollfd_methods; +} /* PR_GetSocketPollFdMethods */ + +PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc( + PRInt32 osfd, const PRIOMethods *methods) +{ + PRFileDesc *fd = _PR_Getfd(); + + if (NULL == fd) goto failed; + + fd->methods = methods; + fd->secret->md.osfd = osfd; + /* Make fd non-blocking */ + if (osfd > 2) + { + /* Don't mess around with stdin, stdout or stderr */ + if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd); + else pt_MakeFdNonblock(osfd); + } + fd->secret->state = _PR_FILEDESC_OPEN; + fd->secret->inheritable = _PR_TRI_UNKNOWN; + return fd; + +failed: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return fd; +} /* PR_AllocFileDesc */ + +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) +PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd); +#if defined(_PR_INET6_PROBE) +extern PRBool _pr_ipv6_is_present(void); +PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() +{ +PRInt32 osfd; + +#if defined(DARWIN) + /* + * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3). IPv6 on + * lesser versions is not ready for general use (see bug 222031). + */ + { + struct utsname u; + if (uname(&u) != 0 || atoi(u.release) < 7) + return PR_FALSE; + } +#endif + + /* + * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001) + * suggests that we call open("/dev/ip6", O_RDWR) to determine + * whether IPv6 APIs and the IPv6 stack are on the system. + * Our portable test below seems to work fine, so I am using it. + */ + osfd = socket(AF_INET6, SOCK_STREAM, 0); + if (osfd != -1) { + close(osfd); + return PR_TRUE; + } + return PR_FALSE; +} +#endif /* _PR_INET6_PROBE */ +#endif + +PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) +{ + PRIntn osfd; + PRDescType ftype; + PRFileDesc *fd = NULL; + PRInt32 tmp_domain = domain; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (pt_TestAbort()) return NULL; + + if (PF_INET != domain + && PR_AF_INET6 != domain + && PF_UNIX != domain) + { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return fd; + } + if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP; + else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP; + else + { + (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return fd; + } +#if defined(_PR_INET6_PROBE) + if (PR_AF_INET6 == domain) + domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET; +#elif defined(_PR_INET6) + if (PR_AF_INET6 == domain) + domain = AF_INET6; +#else + if (PR_AF_INET6 == domain) + domain = AF_INET; +#endif + + osfd = socket(domain, type, proto); + if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno); + else + { +#ifdef _PR_IPV6_V6ONLY_PROBE + if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default) + { + int on = 0; + (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, + &on, sizeof(on)); + } +#endif + fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE); + if (fd == NULL) close(osfd); + } +#ifdef _PR_NEED_SECRET_AF + if (fd != NULL) fd->secret->af = domain; +#endif +#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) + if (fd != NULL) { + /* + * For platforms with no support for IPv6 + * create layered socket for IPv4-mapped IPv6 addresses + */ + if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) { + if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) { + PR_Close(fd); + fd = NULL; + } + } + } +#endif + return fd; +} /* PR_Socket */ + +/*****************************************************************************/ +/****************************** I/O public methods ***************************/ +/*****************************************************************************/ + +PR_IMPLEMENT(PRFileDesc*) PR_OpenFile( + const char *name, PRIntn flags, PRIntn mode) +{ + PRFileDesc *fd = NULL; + PRIntn syserrno, osfd = -1, osflags = 0;; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (pt_TestAbort()) return NULL; + + if (flags & PR_RDONLY) osflags |= O_RDONLY; + if (flags & PR_WRONLY) osflags |= O_WRONLY; + if (flags & PR_RDWR) osflags |= O_RDWR; + if (flags & PR_APPEND) osflags |= O_APPEND; + if (flags & PR_TRUNCATE) osflags |= O_TRUNC; + if (flags & PR_EXCL) osflags |= O_EXCL; + if (flags & PR_SYNC) + { +#if defined(O_SYNC) + osflags |= O_SYNC; +#elif defined(O_FSYNC) + osflags |= O_FSYNC; +#else +#error "Neither O_SYNC nor O_FSYNC is defined on this platform" +#endif + } + + /* + ** We have to hold the lock across the creation in order to + ** enforce the sematics of PR_Rename(). (see the latter for + ** more details) + */ + if (flags & PR_CREATE_FILE) + { + osflags |= O_CREAT; + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + } + + osfd = _md_iovector._open64(name, osflags, mode); + syserrno = errno; + + if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) + PR_Unlock(_pr_rename_lock); + + if (osfd == -1) + pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno); + else + { + fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE); + if (fd == NULL) close(osfd); /* $$$ whoops! this is bad $$$ */ + } + return fd; +} /* PR_OpenFile */ + +PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode) +{ + return PR_OpenFile(name, flags, mode); +} /* PR_Open */ + +PR_IMPLEMENT(PRStatus) PR_Delete(const char *name) +{ + PRIntn rv = -1; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (pt_TestAbort()) return PR_FAILURE; + + rv = unlink(name); + + if (rv == -1) { + pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno); + return PR_FAILURE; + } else + return PR_SUCCESS; +} /* PR_Delete */ + +PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how) +{ + PRIntn rv; + + if (pt_TestAbort()) return PR_FAILURE; + + switch (how) + { + case PR_ACCESS_READ_OK: + rv = access(name, R_OK); + break; + case PR_ACCESS_WRITE_OK: + rv = access(name, W_OK); + break; + case PR_ACCESS_EXISTS: + default: + rv = access(name, F_OK); + } + if (0 == rv) return PR_SUCCESS; + pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno); + return PR_FAILURE; + +} /* PR_Access */ + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info) +{ + PRInt32 rv = _PR_MD_GETFILEINFO(fn, info); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; +} /* PR_GetFileInfo */ + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info) +{ + PRInt32 rv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_GETFILEINFO64(fn, info); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; +} /* PR_GetFileInfo64 */ + +PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to) +{ + PRIntn rv = -1; + + if (pt_TestAbort()) return PR_FAILURE; + + /* + ** We have to acquire a lock here to stiffle anybody trying to create + ** a new file at the same time. And we have to hold that lock while we + ** test to see if the file exists and do the rename. The other place + ** where the lock is held is in PR_Open() when possibly creating a + ** new file. + */ + + PR_Lock(_pr_rename_lock); + rv = access(to, F_OK); + if (0 == rv) + { + PR_SetError(PR_FILE_EXISTS_ERROR, 0); + rv = -1; + } + else + { + rv = rename(from, to); + if (rv == -1) + pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno); + } + PR_Unlock(_pr_rename_lock); + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* PR_Rename */ + +PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir) +{ + if (pt_TestAbort()) return PR_FAILURE; + + if (NULL != 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 */ + +PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode) +{ + PRInt32 rv = -1; + + if (pt_TestAbort()) return PR_FAILURE; + + /* + ** This lock is used to enforce rename semantics as described + ** in PR_Rename. + */ + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + rv = mkdir(name, mode); + if (-1 == rv) + pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno); + if (NULL !=_pr_rename_lock) + PR_Unlock(_pr_rename_lock); + + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* PR_Makedir */ + +PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode) +{ + return PR_MakeDir(name, mode); +} /* PR_Mkdir */ + +PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name) +{ + PRInt32 rv; + + if (pt_TestAbort()) return PR_FAILURE; + + rv = rmdir(name); + if (0 == rv) { + return PR_SUCCESS; + } else { + pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno); + return PR_FAILURE; + } +} /* PR_Rmdir */ + + +PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name) +{ + DIR *osdir; + PRDir *dir = NULL; + + if (pt_TestAbort()) return dir; + + osdir = opendir(name); + if (osdir == NULL) + pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno); + else + { + dir = PR_NEWZAP(PRDir); + if (dir) + dir->md.d = osdir; + else + (void)closedir(osdir); + } + return dir; +} /* PR_OpenDir */ + +static PRInt32 _pr_poll_with_poll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + 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. + */ + PRIntervalTime start, elapsed, remaining; + + if (pt_TestAbort()) return -1; + + if (0 == npds) PR_Sleep(timeout); + else + { +#define STACK_POLL_DESC_COUNT 64 + struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT]; + struct pollfd *syspoll; + PRIntn index, msecs; + + if (npds <= STACK_POLL_DESC_COUNT) + { + syspoll = stack_syspoll; + } + else + { + PRThread *me = PR_GetCurrentThread(); + if (npds > me->syspoll_count) + { + PR_Free(me->syspoll_list); + me->syspoll_list = + (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd)); + if (NULL == me->syspoll_list) + { + me->syspoll_count = 0; + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + me->syspoll_count = npds; + } + syspoll = me->syspoll_list; + } + + for (index = 0; index < npds; ++index) + { + 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 + { + /* now locate the NSPR layer at the bottom of the stack */ + 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)) + { + 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 = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + /* make poll() ignore this entry */ + syspoll[index].fd = -1; + syspoll[index].events = 0; + pds[index].out_flags = 0; + } + } + 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 = 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; /* don't retry, just time out */ + 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) + { + 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; + } + } + } + } + return ready; + +} /* _pr_poll_with_poll */ + +#if defined(_PR_POLL_WITH_SELECT) +/* + * OSF1 and HPUX report the POLLHUP event for a socket when the + * shutdown(SHUT_WR) operation is called for the remote end, even though + * the socket is still writeable. Use select(), instead of poll(), to + * workaround this problem. + */ +static PRInt32 _pr_poll_with_select( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRInt32 ready = 0; + /* + * For restarting 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 (pt_TestAbort()) return -1; + + if (0 == npds) PR_Sleep(timeout); + else + { +#define STACK_POLL_DESC_COUNT 64 + int stack_selectfd[STACK_POLL_DESC_COUNT]; + int *selectfd; + fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL; + struct timeval tv, *tvp; + PRIntn index, msecs, maxfd = 0; + + if (npds <= STACK_POLL_DESC_COUNT) + { + selectfd = stack_selectfd; + } + else + { + PRThread *me = PR_GetCurrentThread(); + if (npds > me->selectfd_count) + { + PR_Free(me->selectfd_list); + me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int)); + if (NULL == me->selectfd_list) + { + me->selectfd_count = 0; + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + me->selectfd_count = npds; + } + selectfd = me->selectfd_list; + } + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + + for (index = 0; index < npds; ++index) + { + 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 + { + /* now locate the NSPR layer at the bottom of the stack */ + 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)) + { + if (0 == ready) + { + PRBool add_to_rd = PR_FALSE; + PRBool add_to_wr = PR_FALSE; + PRBool add_to_ex = PR_FALSE; + + selectfd[index] = bottom->secret->md.osfd; + if (in_flags_read & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_READ; + add_to_rd = PR_TRUE; + } + if (in_flags_read & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_WRITE; + add_to_wr = PR_TRUE; + } + if (in_flags_write & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_READ; + add_to_rd = PR_TRUE; + } + if (in_flags_write & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_WRITE; + add_to_wr = PR_TRUE; + } + if (pds[index].in_flags & PR_POLL_EXCEPT) + { + add_to_ex = PR_TRUE; + } + if ((selectfd[index] > maxfd) && + (add_to_rd || add_to_wr || add_to_ex)) + { + maxfd = selectfd[index]; + /* + * If maxfd is too large to be used with + * select, fall back to calling poll. + */ + if (maxfd >= FD_SETSIZE) + break; + } + if (add_to_rd) + { + FD_SET(bottom->secret->md.osfd, &rd); + rdp = &rd; + } + if (add_to_wr) + { + FD_SET(bottom->secret->md.osfd, &wr); + wrp = ≀ + } + if (add_to_ex) + { + FD_SET(bottom->secret->md.osfd, &ex); + exp = &ex; + } + } + } + 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 + { + pds[index].out_flags = 0; + } + } + if (0 == ready) + { + if (maxfd >= FD_SETSIZE) + { + /* + * maxfd too large to be used with select, fall back to + * calling poll + */ + return(_pr_poll_with_poll(pds, npds, timeout)); + } + switch (timeout) + { + case PR_INTERVAL_NO_WAIT: + tv.tv_sec = 0; + tv.tv_usec = 0; + tvp = &tv; + break; + case PR_INTERVAL_NO_TIMEOUT: + tvp = NULL; + break; + default: + msecs = PR_IntervalToMilliseconds(timeout); + tv.tv_sec = msecs/PR_MSEC_PER_SEC; + tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC; + tvp = &tv; + start = PR_IntervalNow(); + } + +retry: + ready = select(maxfd + 1, rdp, wrp, exp, tvp); + if (-1 == ready) + { + PRIntn oserror = errno; + + if ((EINTR == oserror) || (EAGAIN == oserror)) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) + goto retry; + else if (timeout == PR_INTERVAL_NO_WAIT) + ready = 0; /* don't retry, just time out */ + else + { + elapsed = (PRIntervalTime) (PR_IntervalNow() + - start); + if (elapsed > timeout) + ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + msecs = PR_IntervalToMilliseconds(remaining); + tv.tv_sec = msecs/PR_MSEC_PER_SEC; + tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * + PR_USEC_PER_MSEC; + goto retry; + } + } + } else if (EBADF == oserror) + { + /* find all the bad fds */ + ready = 0; + for (index = 0; index < npds; ++index) + { + pds[index].out_flags = 0; + if ((NULL != pds[index].fd) && + (0 != pds[index].in_flags)) + { + if (fcntl(selectfd[index], F_GETFL, 0) == -1) + { + pds[index].out_flags = PR_POLL_NVAL; + ready++; + } + } + } + } else + _PR_MD_MAP_SELECT_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 (FD_ISSET(selectfd[index], &rd)) + { + 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 (FD_ISSET(selectfd[index], &wr)) + { + 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 (FD_ISSET(selectfd[index], &ex)) + out_flags |= PR_POLL_EXCEPT; + } + pds[index].out_flags = out_flags; + } + } + } + } + return ready; + +} /* _pr_poll_with_select */ +#endif /* _PR_POLL_WITH_SELECT */ + +PR_IMPLEMENT(PRInt32) PR_Poll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ +#if defined(_PR_POLL_WITH_SELECT) + return(_pr_poll_with_select(pds, npds, timeout)); +#else + return(_pr_poll_with_poll(pds, npds, timeout)); +#endif +} + +PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags) +{ + struct dirent *dp; + + if (pt_TestAbort()) return NULL; + + for (;;) + { + errno = 0; + dp = readdir(dir->md.d); + if (NULL == dp) + { + pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno); + return NULL; + } + if ((flags & PR_SKIP_DOT) + && ('.' == dp->d_name[0]) + && (0 == dp->d_name[1])) continue; + if ((flags & PR_SKIP_DOT_DOT) + && ('.' == dp->d_name[0]) + && ('.' == dp->d_name[1]) + && (0 == dp->d_name[2])) continue; + if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0])) + continue; + break; + } + dir->d.name = dp->d_name; + return &dir->d; +} /* PR_ReadDir */ + +PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) +{ + PRIntn domain = PF_INET; + + return PR_Socket(domain, SOCK_DGRAM, 0); +} /* PR_NewUDPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void) +{ + PRIntn domain = PF_INET; + + return PR_Socket(domain, SOCK_STREAM, 0); +} /* PR_NewTCPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) +{ + return PR_Socket(af, SOCK_DGRAM, 0); +} /* PR_NewUDPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af) +{ + return PR_Socket(af, SOCK_STREAM, 0); +} /* PR_NewTCPSocket */ + +PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2]) +{ + PRInt32 osfd[2]; + + if (pt_TestAbort()) return PR_FAILURE; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) { + pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno); + return PR_FAILURE; + } + + fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE); + if (fds[0] == NULL) { + close(osfd[0]); + close(osfd[1]); + return PR_FAILURE; + } + fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE); + if (fds[1] == NULL) { + PR_Close(fds[0]); + close(osfd[1]); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* PR_NewTCPSocketPair */ + +PR_IMPLEMENT(PRStatus) PR_CreatePipe( + PRFileDesc **readPipe, + PRFileDesc **writePipe +) +{ + int pipefd[2]; + + if (pt_TestAbort()) return PR_FAILURE; + + if (pipe(pipefd) == -1) + { + /* XXX map pipe error */ + PR_SetError(PR_UNKNOWN_ERROR, errno); + return PR_FAILURE; + } + *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE); + if (NULL == *readPipe) + { + close(pipefd[0]); + close(pipefd[1]); + return PR_FAILURE; + } + *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE); + if (NULL == *writePipe) + { + PR_Close(*readPipe); + close(pipefd[1]); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +/* +** Set the inheritance attribute of a file descriptor. +*/ +PR_IMPLEMENT(PRStatus) PR_SetFDInheritable( + PRFileDesc *fd, + PRBool inheritable) +{ + /* + * Only a non-layered, NSPR file descriptor can be inherited + * by a child process. + */ + if (fd->identity != PR_NSPR_IO_LAYER) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + if (fd->secret->inheritable != inheritable) + { + if (fcntl(fd->secret->md.osfd, F_SETFD, + inheritable ? 0 : FD_CLOEXEC) == -1) + { + return PR_FAILURE; + } + fd->secret->inheritable = (_PRTriStateBool) inheritable; + } + return PR_SUCCESS; +} + +/*****************************************************************************/ +/***************************** I/O friends methods ***************************/ +/*****************************************************************************/ + +PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE); + if (NULL == fd) close(osfd); + return fd; +} /* PR_ImportFile */ + +PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE); + if (NULL == fd) close(osfd); + return fd; +} /* PR_ImportPipe */ + +PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE); + if (NULL == fd) close(osfd); +#ifdef _PR_NEED_SECRET_AF + if (NULL != fd) fd->secret->af = PF_INET; +#endif + return fd; +} /* PR_ImportTCPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE); + if (NULL != fd) close(osfd); + return fd; +} /* PR_ImportUDPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + fd = _PR_Getfd(); + + if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->secret->md.osfd = osfd; + fd->secret->inheritable = _PR_TRI_FALSE; + fd->secret->state = _PR_FILEDESC_OPEN; + fd->methods = PR_GetSocketPollFdMethods(); + } + + return fd; +} /* PR_CreateSocketPollFD */ + +PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd) +{ + if (NULL == fd) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + fd->secret->state = _PR_FILEDESC_CLOSED; + _PR_Putfd(fd); + return PR_SUCCESS; +} /* PR_DestroySocketPollFd */ + +PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom) +{ + PRInt32 osfd = -1; + bottom = (NULL == bottom) ? + NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER); + if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + else osfd = bottom->secret->md.osfd; + return osfd; +} /* PR_FileDesc2NativeHandle */ + +PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd, + PRInt32 handle) +{ + if (fd) fd->secret->md.osfd = handle; +} /* PR_ChangeFileDescNativeHandle*/ + +PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + + if (pt_TestAbort()) return PR_FAILURE; + + PR_Lock(_pr_flock_lock); + while (-1 == fd->secret->lockCount) + PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT); + if (0 == fd->secret->lockCount) + { + fd->secret->lockCount = -1; + PR_Unlock(_pr_flock_lock); + status = _PR_MD_LOCKFILE(fd->secret->md.osfd); + PR_Lock(_pr_flock_lock); + fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0; + PR_NotifyAllCondVar(_pr_flock_cv); + } + else + { + fd->secret->lockCount += 1; + } + PR_Unlock(_pr_flock_lock); + + return status; +} /* PR_LockFile */ + +PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + + if (pt_TestAbort()) return PR_FAILURE; + + PR_Lock(_pr_flock_lock); + if (0 == fd->secret->lockCount) + { + status = _PR_MD_TLOCKFILE(fd->secret->md.osfd); + if (PR_SUCCESS == status) fd->secret->lockCount = 1; + } + else fd->secret->lockCount += 1; + PR_Unlock(_pr_flock_lock); + + return status; +} /* PR_TLockFile */ + +PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + + if (pt_TestAbort()) return PR_FAILURE; + + PR_Lock(_pr_flock_lock); + if (fd->secret->lockCount == 1) + { + status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd); + if (PR_SUCCESS == status) fd->secret->lockCount = 0; + } + else fd->secret->lockCount -= 1; + PR_Unlock(_pr_flock_lock); + + return status; +} + +/* + * The next two entry points should not be in the API, but they are + * defined here for historical (or hysterical) reasons. + */ + +PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void) +{ +#if defined(XP_UNIX) && !defined(AIX) && !defined(VMS) + struct rlimit rlim; + + if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) + return -1; + + return rlim.rlim_max; +#elif defined(AIX) || defined(VMS) + return sysconf(_SC_OPEN_MAX); +#endif +} + +PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size) +{ +#if defined(XP_UNIX) && !defined(AIX) && !defined(VMS) + struct rlimit rlim; + PRInt32 tableMax = PR_GetSysfdTableMax(); + + if (tableMax < 0) return -1; + rlim.rlim_max = tableMax; + + /* Grow as much as we can; even if too big */ + if ( rlim.rlim_max < table_size ) + rlim.rlim_cur = rlim.rlim_max; + else + rlim.rlim_cur = table_size; + + if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) + return -1; + + return rlim.rlim_cur; +#elif defined(AIX) || defined(VMS) + return -1; +#endif +} + +/* + * PR_Stat is supported for backward compatibility; some existing Java + * code uses it. New code should use PR_GetFileInfo. + */ + +#ifndef NO_NSPR_10_SUPPORT +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 -1; + + if (-1 == stat(name, buf)) { + pt_MapError(_PR_MD_MAP_STAT_ERROR, errno); + return -1; + } else { + return 0; + } +} +#endif /* ! NO_NSPR_10_SUPPORT */ + + +PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll"); + memset(set, 0, sizeof(PR_fd_set)); +} + +PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll"); + PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC ); + + set->harray[set->hsize++] = fh; +} + +PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set) +{ + PRUint32 index, index2; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll"); + + for (index = 0; indexhsize; index++) + if (set->harray[index] == fh) { + for (index2=index; index2 < (set->hsize-1); index2++) { + set->harray[index2] = set->harray[index2+1]; + } + set->hsize--; + break; + } +} + +PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set) +{ + PRUint32 index; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll"); + for (index = 0; indexhsize; index++) + if (set->harray[index] == fh) { + return 1; + } + return 0; +} + +PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll"); + PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC ); + + set->narray[set->nsize++] = fd; +} + +PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set) +{ + PRUint32 index, index2; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll"); + + for (index = 0; indexnsize; index++) + if (set->narray[index] == fd) { + for (index2=index; index2 < (set->nsize-1); index2++) { + set->narray[index2] = set->narray[index2+1]; + } + set->nsize--; + break; + } +} + +PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set) +{ + PRUint32 index; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll"); + for (index = 0; indexnsize; index++) + if (set->narray[index] == fd) { + return 1; + } + return 0; +} + +#include +#include +#if !defined(SUNOS4) && !defined(HPUX) \ + && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__) +#include +#endif + +static PRInt32 +_PR_getset(PR_fd_set *pr_set, fd_set *set) +{ + PRUint32 index; + PRInt32 max = 0; + + if (!pr_set) + return 0; + + FD_ZERO(set); + + /* First set the pr file handle osfds */ + for (index=0; indexhsize; index++) { + FD_SET(pr_set->harray[index]->secret->md.osfd, set); + if (pr_set->harray[index]->secret->md.osfd > max) + max = pr_set->harray[index]->secret->md.osfd; + } + /* Second set the native osfds */ + for (index=0; indexnsize; index++) { + FD_SET(pr_set->narray[index], set); + if (pr_set->narray[index] > max) + max = pr_set->narray[index]; + } + return max; +} + +static void +_PR_setset(PR_fd_set *pr_set, fd_set *set) +{ + PRUint32 index, last_used; + + if (!pr_set) + return; + + for (last_used=0, index=0; indexhsize; index++) { + if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) { + pr_set->harray[last_used++] = pr_set->harray[index]; + } + } + pr_set->hsize = last_used; + + for (last_used=0, index=0; indexnsize; index++) { + if ( FD_ISSET(pr_set->narray[index], set) ) { + pr_set->narray[last_used++] = pr_set->narray[index]; + } + } + pr_set->nsize = last_used; +} + +PR_IMPLEMENT(PRInt32) PR_Select( + PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, + PR_fd_set *pr_ex, PRIntervalTime timeout) +{ + fd_set rd, wr, ex; + struct timeval tv, *tvp; + PRInt32 max, max_fd; + PRInt32 rv; + /* + * For restarting select() if it is interrupted by a Unix 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; + + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll"); + + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + + max_fd = _PR_getset(pr_rd, &rd); + max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd; + max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd; + + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + tvp = NULL; + } else { + tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout); + tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + start = PR_IntervalNow(); + } + +retry: + rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd, + (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp); + + if (rv == -1 && errno == EINTR) { + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + goto retry; + } else { + elapsed = (PRIntervalTime) (PR_IntervalNow() - start); + if (elapsed > timeout) { + rv = 0; /* timed out */ + } else { + remaining = timeout - elapsed; + tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining); + tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds( + remaining - PR_SecondsToInterval(tv.tv_sec)); + goto retry; + } + } + } + + if (rv > 0) { + _PR_setset(pr_rd, &rd); + _PR_setset(pr_wr, &wr); + _PR_setset(pr_ex, &ex); + } else if (rv == -1) { + pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno); + } + return rv; +} +#endif /* defined(_PR_PTHREADS) */ + +#ifdef MOZ_UNICODE +/* ================ UTF16 Interfaces ================================ */ +PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16( + const PRUnichar *name, PRIntn flags, PRIntn mode) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} +/* ================ UTF16 Interfaces ================================ */ +#endif /* MOZ_UNICODE */ + +/* ptio.c */ diff --git a/nsprpub/pr/src/pthreads/ptmisc.c b/nsprpub/pr/src/pthreads/ptmisc.c new file mode 100644 index 00000000000..920d00dbfa6 --- /dev/null +++ b/nsprpub/pr/src/pthreads/ptmisc.c @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: ptmisc.c +** Descritpion: Implemenation of miscellaneous methods for pthreads +*/ + +#if defined(_PR_PTHREADS) + +#include "primpl.h" + +#include +#ifdef SOLARIS +#include +#endif + +#define PT_LOG(f) + +void _PR_InitCPUs(void) {PT_LOG("_PR_InitCPUs")} +void _PR_InitStacks(void) {PT_LOG("_PR_InitStacks")} + +PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs) +{ +#ifdef SOLARIS + thr_setconcurrency(numCPUs); +#else + PT_LOG("PR_SetConcurrency"); +#endif +} + +PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 flag) + {PT_LOG("PR_SetThreadRecycleMode")} + +#endif /* defined(_PR_PTHREADS) */ + +/* ptmisc.c */ diff --git a/nsprpub/pr/src/pthreads/ptsynch.c b/nsprpub/pr/src/pthreads/ptsynch.c new file mode 100644 index 00000000000..bd0688c2c90 --- /dev/null +++ b/nsprpub/pr/src/pthreads/ptsynch.c @@ -0,0 +1,1139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: ptsynch.c +** Descritpion: Implemenation for thread synchronization using pthreads +** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h +*/ + +#if defined(_PR_PTHREADS) + +#include "primpl.h" +#include "obsolete/prsem.h" + +#include +#include +#include + +static pthread_mutexattr_t _pt_mattr; +static pthread_condattr_t _pt_cvar_attr; + +#if defined(DEBUG) +extern PTDebug pt_debug; /* this is shared between several modules */ + +#if defined(_PR_DCETHREADS) +static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct + * in DCE threads) to compare with */ +#endif /* defined(_PR_DCETHREADS) */ +#endif /* defined(DEBUG) */ + +#if defined(FREEBSD) +/* + * On older versions of FreeBSD, pthread_mutex_trylock returns EDEADLK. + * Newer versions return EBUSY. We still need to support both. + */ +static int +pt_pthread_mutex_is_locked(pthread_mutex_t *m) +{ + int rv = pthread_mutex_trylock(m); + return (EBUSY == rv || EDEADLK == rv); +} +#endif + +/**************************************************************/ +/**************************************************************/ +/*****************************LOCKS****************************/ +/**************************************************************/ +/**************************************************************/ + +void _PR_InitLocks(void) +{ + int rv; + rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr); + PR_ASSERT(0 == rv); + +#ifdef LINUX +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) + rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP); + PR_ASSERT(0 == rv); +#endif +#endif + + rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr); + PR_ASSERT(0 == rv); +} + +static void pt_PostNotifies(PRLock *lock, PRBool unlock) +{ + PRIntn index, rv; + _PT_Notified post; + _PT_Notified *notified, *prev = NULL; + /* + * Time to actually notify any conditions that were affected + * while the lock was held. Get a copy of the list that's in + * the lock structure and then zero the original. If it's + * linked to other such structures, we own that storage. + */ + post = lock->notified; /* a safe copy; we own the lock */ + +#if defined(DEBUG) + memset(&lock->notified, 0, sizeof(_PT_Notified)); /* reset */ +#else + lock->notified.length = 0; /* these are really sufficient */ + lock->notified.link = NULL; +#endif + + /* should (may) we release lock before notifying? */ + if (unlock) + { + rv = pthread_mutex_unlock(&lock->mutex); + PR_ASSERT(0 == rv); + } + + notified = &post; /* this is where we start */ + do + { + for (index = 0; index < notified->length; ++index) + { + PRCondVar *cv = notified->cv[index].cv; + PR_ASSERT(NULL != cv); + PR_ASSERT(0 != notified->cv[index].times); + if (-1 == notified->cv[index].times) + { + rv = pthread_cond_broadcast(&cv->cv); + PR_ASSERT(0 == rv); + } + else + { + while (notified->cv[index].times-- > 0) + { + rv = pthread_cond_signal(&cv->cv); + PR_ASSERT(0 == rv); + } + } +#if defined(DEBUG) + pt_debug.cvars_notified += 1; + if (0 > PR_AtomicDecrement(&cv->notify_pending)) + { + pt_debug.delayed_cv_deletes += 1; + PR_DestroyCondVar(cv); + } +#else /* defined(DEBUG) */ + if (0 > PR_AtomicDecrement(&cv->notify_pending)) + PR_DestroyCondVar(cv); +#endif /* defined(DEBUG) */ + } + prev = notified; + notified = notified->link; + if (&post != prev) PR_DELETE(prev); + } while (NULL != notified); +} /* pt_PostNotifies */ + +PR_IMPLEMENT(PRLock*) PR_NewLock(void) +{ + PRIntn rv; + PRLock *lock; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + lock = PR_NEWZAP(PRLock); + if (lock != NULL) + { + rv = _PT_PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr); + PR_ASSERT(0 == rv); + } +#if defined(DEBUG) + pt_debug.locks_created += 1; +#endif + return lock; +} /* PR_NewLock */ + +PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock) +{ + PRIntn rv; + PR_ASSERT(NULL != lock); + PR_ASSERT(PR_FALSE == lock->locked); + PR_ASSERT(0 == lock->notified.length); + PR_ASSERT(NULL == lock->notified.link); + rv = pthread_mutex_destroy(&lock->mutex); + PR_ASSERT(0 == rv); +#if defined(DEBUG) + memset(lock, 0xaf, sizeof(PRLock)); + pt_debug.locks_destroyed += 1; +#endif + PR_DELETE(lock); +} /* PR_DestroyLock */ + +PR_IMPLEMENT(void) PR_Lock(PRLock *lock) +{ + PRIntn rv; + PR_ASSERT(lock != NULL); + rv = pthread_mutex_lock(&lock->mutex); + PR_ASSERT(0 == rv); + PR_ASSERT(0 == lock->notified.length); + PR_ASSERT(NULL == lock->notified.link); + PR_ASSERT(PR_FALSE == lock->locked); + lock->locked = PR_TRUE; + lock->owner = pthread_self(); +#if defined(DEBUG) + pt_debug.locks_acquired += 1; +#endif +} /* PR_Lock */ + +PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) +{ + PRIntn rv; + + PR_ASSERT(lock != NULL); + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex)); + PR_ASSERT(PR_TRUE == lock->locked); + PR_ASSERT(pthread_equal(lock->owner, pthread_self())); + + if (!lock->locked || !pthread_equal(lock->owner, pthread_self())) + return PR_FAILURE; + + lock->locked = PR_FALSE; + if (0 == lock->notified.length) /* shortcut */ + { + rv = pthread_mutex_unlock(&lock->mutex); + PR_ASSERT(0 == rv); + } + else pt_PostNotifies(lock, PR_TRUE); + +#if defined(DEBUG) + pt_debug.locks_released += 1; +#endif + return PR_SUCCESS; +} /* PR_Unlock */ + + +/**************************************************************/ +/**************************************************************/ +/***************************CONDITIONS*************************/ +/**************************************************************/ +/**************************************************************/ + + +/* + * This code is used to compute the absolute time for the wakeup. + * It's moderately ugly, so it's defined here and called in a + * couple of places. + */ +#define PT_NANOPERMICRO 1000UL +#define PT_BILLION 1000000000UL + +static PRIntn pt_TimedWait( + pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout) +{ + int rv; + struct timeval now; + struct timespec tmo; + PRUint32 ticks = PR_TicksPerSecond(); + + tmo.tv_sec = (PRInt32)(timeout / ticks); + tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks)); + tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec); + + /* pthreads wants this in absolute time, off we go ... */ + (void)GETTIMEOFDAY(&now); + /* that one's usecs, this one's nsecs - grrrr! */ + tmo.tv_sec += now.tv_sec; + tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec); + tmo.tv_sec += tmo.tv_nsec / PT_BILLION; + tmo.tv_nsec %= PT_BILLION; + + rv = pthread_cond_timedwait(cv, ml, &tmo); + + /* NSPR doesn't report timeouts */ +#ifdef _PR_DCETHREADS + if (rv == -1) return (errno == EAGAIN) ? 0 : errno; + else return rv; +#else + return (rv == ETIMEDOUT) ? 0 : rv; +#endif +} /* pt_TimedWait */ + + +/* + * Notifies just get posted to the protecting mutex. The + * actual notification is done when the lock is released so that + * MP systems don't contend for a lock that they can't have. + */ +static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast) +{ + PRIntn index = 0; + _PT_Notified *notified = &cvar->lock->notified; + + PR_ASSERT(PR_TRUE == cvar->lock->locked); + PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); + + while (1) + { + for (index = 0; index < notified->length; ++index) + { + if (notified->cv[index].cv == cvar) + { + if (broadcast) + notified->cv[index].times = -1; + else if (-1 != notified->cv[index].times) + notified->cv[index].times += 1; + goto finished; /* we're finished */ + } + } + /* if not full, enter new CV in this array */ + if (notified->length < PT_CV_NOTIFIED_LENGTH) break; + + /* if there's no link, create an empty array and link it */ + if (NULL == notified->link) + notified->link = PR_NEWZAP(_PT_Notified); + notified = notified->link; + } + + /* A brand new entry in the array */ + (void)PR_AtomicIncrement(&cvar->notify_pending); + notified->cv[index].times = (broadcast) ? -1 : 1; + notified->cv[index].cv = cvar; + notified->length += 1; + +finished: + PR_ASSERT(PR_TRUE == cvar->lock->locked); + PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); +} /* pt_PostNotifyToCvar */ + +PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) +{ + PRCondVar *cv = PR_NEW(PRCondVar); + PR_ASSERT(lock != NULL); + if (cv != NULL) + { + int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); + PR_ASSERT(0 == rv); + cv->lock = lock; + cv->notify_pending = 0; +#if defined(DEBUG) + pt_debug.cvars_created += 1; +#endif + } + return cv; +} /* PR_NewCondVar */ + +PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) +{ + if (0 > PR_AtomicDecrement(&cvar->notify_pending)) + { + PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); +#if defined(DEBUG) + memset(cvar, 0xaf, sizeof(PRCondVar)); + pt_debug.cvars_destroyed += 1; +#endif + PR_DELETE(cvar); + } +} /* PR_DestroyCondVar */ + +PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) +{ + PRIntn rv; + PRThread *thred = PR_GetCurrentThread(); + + PR_ASSERT(cvar != NULL); + /* We'd better be locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); + PR_ASSERT(PR_TRUE == cvar->lock->locked); + /* and it better be by us */ + PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); + + if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; + + /* + * The thread waiting is used for PR_Interrupt + */ + thred->waiting = cvar; /* this is where we're waiting */ + + /* + * If we have pending notifies, post them now. + * + * This is not optimal. We're going to post these notifies + * while we're holding the lock. That means on MP systems + * that they are going to collide for the lock that we will + * hold until we actually wait. + */ + if (0 != cvar->lock->notified.length) + pt_PostNotifies(cvar->lock, PR_FALSE); + + /* + * We're surrendering the lock, so clear out the locked field. + */ + cvar->lock->locked = PR_FALSE; + + if (timeout == PR_INTERVAL_NO_TIMEOUT) + rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex); + else + rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout); + + /* We just got the lock back - this better be empty */ + PR_ASSERT(PR_FALSE == cvar->lock->locked); + cvar->lock->locked = PR_TRUE; + cvar->lock->owner = pthread_self(); + + PR_ASSERT(0 == cvar->lock->notified.length); + thred->waiting = NULL; /* and now we're not */ + if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; + if (rv != 0) + { + _PR_MD_MAP_DEFAULT_ERROR(rv); + return PR_FAILURE; + } + return PR_SUCCESS; + +aborted: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thred->state &= ~PT_THREAD_ABORTED; + return PR_FAILURE; +} /* PR_WaitCondVar */ + +PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) +{ + PR_ASSERT(cvar != NULL); + pt_PostNotifyToCvar(cvar, PR_FALSE); + return PR_SUCCESS; +} /* PR_NotifyCondVar */ + +PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) +{ + PR_ASSERT(cvar != NULL); + pt_PostNotifyToCvar(cvar, PR_TRUE); + return PR_SUCCESS; +} /* PR_NotifyAllCondVar */ + +/**************************************************************/ +/**************************************************************/ +/***************************MONITORS***************************/ +/**************************************************************/ +/**************************************************************/ + +PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) +{ + PRMonitor *mon; + PRCondVar *cvar; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + 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; + rv = _PT_PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr); + PR_ASSERT(0 == rv); + + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); + + mon->cvar = cvar; + rv = _PT_PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr); + PR_ASSERT(0 == rv); + mon->entryCount = 0; + mon->cvar->lock = &mon->lock; + if (0 != rv) + { + PR_DELETE(mon); + PR_DELETE(cvar); + mon = NULL; + } + } + return mon; +} /* PR_NewMonitor */ + +PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) +{ + PRMonitor* mon = PR_NewMonitor(); + if (mon) + mon->name = name; + return mon; +} + +PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) +{ + int rv; + PR_ASSERT(mon != NULL); + PR_DestroyCondVar(mon->cvar); + rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv); +#if defined(DEBUG) + memset(mon, 0xaf, sizeof(PRMonitor)); +#endif + PR_DELETE(mon); +} /* PR_DestroyMonitor */ + + +/* The GC uses this; it is quite arguably a bad interface. I'm just + * duplicating it for now - XXXMB + */ +PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) +{ + pthread_t self = pthread_self(); + if (pthread_equal(mon->owner, self)) + return mon->entryCount; + return 0; +} + +PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) +{ + pthread_t self = pthread_self(); + + PR_ASSERT(mon != NULL); + /* + * This is safe only if mon->owner (a pthread_t) can be + * read in one instruction. Perhaps mon->owner should be + * a "PRThread *"? + */ + if (!pthread_equal(mon->owner, self)) + { + PR_Lock(&mon->lock); + /* and now I have the lock */ + PR_ASSERT(0 == mon->entryCount); + PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner)); + _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner); + } + mon->entryCount += 1; +} /* PR_EnterMonitor */ + +PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) +{ + pthread_t self = pthread_self(); + + PR_ASSERT(mon != NULL); + /* The lock better be that - locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); + /* we'd better be the owner */ + PR_ASSERT(pthread_equal(mon->owner, self)); + if (!pthread_equal(mon->owner, self)) + return PR_FAILURE; + + /* if it's locked and we have it, then the entries should be > 0 */ + PR_ASSERT(mon->entryCount > 0); + mon->entryCount -= 1; /* reduce by one */ + if (mon->entryCount == 0) + { + /* and if it transitioned to zero - unlock */ + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); /* make the owner unknown */ + PR_Unlock(&mon->lock); + } + return PR_SUCCESS; +} /* PR_ExitMonitor */ + +PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) +{ + PRStatus rv; + PRInt16 saved_entries; + pthread_t saved_owner; + + PR_ASSERT(mon != NULL); + /* we'd better be locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); + /* and the entries better be positive */ + PR_ASSERT(mon->entryCount > 0); + /* and it better be by us */ + PR_ASSERT(pthread_equal(mon->owner, pthread_self())); + + /* tuck these away 'till later */ + saved_entries = mon->entryCount; + mon->entryCount = 0; + _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); + + rv = PR_WaitCondVar(mon->cvar, timeout); + + /* reinstate the intresting information */ + mon->entryCount = saved_entries; + _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); + + return rv; +} /* PR_Wait */ + +PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) +{ + PR_ASSERT(NULL != mon); + /* we'd better be locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); + /* and the entries better be positive */ + PR_ASSERT(mon->entryCount > 0); + /* and it better be by us */ + PR_ASSERT(pthread_equal(mon->owner, pthread_self())); + + pt_PostNotifyToCvar(mon->cvar, PR_FALSE); + + return PR_SUCCESS; +} /* PR_Notify */ + +PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) +{ + PR_ASSERT(mon != NULL); + /* we'd better be locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); + /* and the entries better be positive */ + PR_ASSERT(mon->entryCount > 0); + /* and it better be by us */ + PR_ASSERT(pthread_equal(mon->owner, pthread_self())); + + pt_PostNotifyToCvar(mon->cvar, PR_TRUE); + + return PR_SUCCESS; +} /* PR_NotifyAll */ + +/**************************************************************/ +/**************************************************************/ +/**************************SEMAPHORES**************************/ +/**************************************************************/ +/**************************************************************/ +PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete( + "PR_PostSem", "locks & condition variables"); + PR_Lock(semaphore->cvar->lock); + PR_NotifyCondVar(semaphore->cvar); + semaphore->count += 1; + PR_Unlock(semaphore->cvar->lock); +} /* PR_PostSem */ + +PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore) +{ + PRStatus status = PR_SUCCESS; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete( + "PR_WaitSem", "locks & condition variables"); + PR_Lock(semaphore->cvar->lock); + while ((semaphore->count == 0) && (PR_SUCCESS == status)) + status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT); + if (PR_SUCCESS == status) semaphore->count -= 1; + PR_Unlock(semaphore->cvar->lock); + return status; +} /* PR_WaitSem */ + +PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete( + "PR_DestroySem", "locks & condition variables"); + PR_DestroyLock(semaphore->cvar->lock); + PR_DestroyCondVar(semaphore->cvar); + PR_DELETE(semaphore); +} /* PR_DestroySem */ + +PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value) +{ + PRSemaphore *semaphore; + static PRBool unwarned = PR_TRUE; + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (unwarned) unwarned = _PR_Obsolete( + "PR_NewSem", "locks & condition variables"); + + semaphore = PR_NEWZAP(PRSemaphore); + if (NULL != semaphore) + { + PRLock *lock = PR_NewLock(); + if (NULL != lock) + { + semaphore->cvar = PR_NewCondVar(lock); + if (NULL != semaphore->cvar) + { + semaphore->count = value; + return semaphore; + } + PR_DestroyLock(lock); + } + PR_DELETE(semaphore); + } + return NULL; +} + +/* + * Define the interprocess named semaphore functions. + * There are three implementations: + * 1. POSIX semaphore based; + * 2. System V semaphore based; + * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR). + */ + +#ifdef _PR_HAVE_POSIX_SEMAPHORES +#include + +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( + const char *name, + PRIntn flags, + PRIntn mode, + PRUintn value) +{ + PRSem *sem; + char osname[PR_IPC_NAME_SIZE]; + + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) + { + return NULL; + } + + sem = PR_NEW(PRSem); + if (NULL == sem) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + if (flags & PR_SEM_CREATE) + { + int oflag = O_CREAT; + + if (flags & PR_SEM_EXCL) oflag |= O_EXCL; + sem->sem = sem_open(osname, oflag, mode, value); + } + else + { +#ifdef HPUX + /* Pass 0 as the mode and value arguments to work around a bug. */ + sem->sem = sem_open(osname, 0, 0, 0); +#else + sem->sem = sem_open(osname, 0); +#endif + } + if ((sem_t *) -1 == sem->sem) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + return sem; +} + +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) +{ + int rv; + rv = sem_wait(sem->sem); + if (0 != rv) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) +{ + int rv; + rv = sem_post(sem->sem); + if (0 != rv) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) +{ + int rv; + rv = sem_close(sem->sem); + if (0 != rv) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + PR_DELETE(sem); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) +{ + int rv; + char osname[PR_IPC_NAME_SIZE]; + + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) + { + return PR_FAILURE; + } + rv = sem_unlink(osname); + if (0 != rv) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) + +#include +#include + +/* + * From the semctl(2) man page in glibc 2.0 + */ +#if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \ + || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) +/* union semun is defined by including */ +#else +/* according to X/OPEN we have to define it ourselves */ +union semun { + int val; + struct semid_ds *buf; + unsigned short *array; +}; +#endif + +/* + * 'a' (97) is the final closing price of NSCP stock. + */ +#define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */ + +#define NSPR_SEM_MODE 0666 + +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( + const char *name, + PRIntn flags, + PRIntn mode, + PRUintn value) +{ + PRSem *sem; + key_t key; + union semun arg; + struct sembuf sop; + struct semid_ds seminfo; +#define MAX_TRIES 60 + PRIntn i; + char osname[PR_IPC_NAME_SIZE]; + + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) + { + return NULL; + } + + /* Make sure the file exists before calling ftok. */ + if (flags & PR_SEM_CREATE) + { + int osfd = open(osname, O_RDWR|O_CREAT, mode); + if (-1 == osfd) + { + _PR_MD_MAP_OPEN_ERROR(errno); + return NULL; + } + if (close(osfd) == -1) + { + _PR_MD_MAP_CLOSE_ERROR(errno); + return NULL; + } + } + key = ftok(osname, NSPR_IPC_KEY_ID); + if ((key_t)-1 == key) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return NULL; + } + + sem = PR_NEW(PRSem); + if (NULL == sem) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + if (flags & PR_SEM_CREATE) + { + sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL); + if (sem->semid >= 0) + { + /* creator of a semaphore is responsible for initializing it */ + arg.val = 0; + if (semctl(sem->semid, 0, SETVAL, arg) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + /* call semop to set sem_otime to nonzero */ + sop.sem_num = 0; + sop.sem_op = value; + sop.sem_flg = 0; + if (semop(sem->semid, &sop, 1) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + return sem; + } + + if (errno != EEXIST || flags & PR_SEM_EXCL) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + } + + sem->semid = semget(key, 1, NSPR_SEM_MODE); + if (sem->semid == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + for (i = 0; i < MAX_TRIES; i++) + { + arg.buf = &seminfo; + semctl(sem->semid, 0, IPC_STAT, arg); + if (seminfo.sem_otime != 0) break; + sleep(1); + } + if (i == MAX_TRIES) + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + PR_DELETE(sem); + return NULL; + } + return sem; +} + +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) +{ + struct sembuf sop; + + sop.sem_num = 0; + sop.sem_op = -1; + sop.sem_flg = 0; + if (semop(sem->semid, &sop, 1) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) +{ + struct sembuf sop; + + sop.sem_num = 0; + sop.sem_op = 1; + sop.sem_flg = 0; + if (semop(sem->semid, &sop, 1) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) +{ + PR_DELETE(sem); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) +{ + key_t key; + int semid; + /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */ + union semun unused; + char osname[PR_IPC_NAME_SIZE]; + + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) + { + return PR_FAILURE; + } + key = ftok(osname, NSPR_IPC_KEY_ID); + if ((key_t) -1 == key) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + if (unlink(osname) == -1) + { + _PR_MD_MAP_UNLINK_ERROR(errno); + return PR_FAILURE; + } + semid = semget(key, 1, NSPR_SEM_MODE); + if (-1 == semid) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + unused.val = 0; + if (semctl(semid, 0, IPC_RMID, unused) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#else /* neither POSIX nor System V semaphores are available */ + +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( + const char *name, + PRIntn flags, + PRIntn mode, + PRUintn value) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +#endif /* end of interprocess named semaphore functions */ + +/**************************************************************/ +/**************************************************************/ +/******************ROUTINES FOR DCE EMULATION******************/ +/**************************************************************/ +/**************************************************************/ + +#include "prpdce.h" + +PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock) +{ + PRIntn rv = pthread_mutex_trylock(&lock->mutex); + if (rv == PT_TRYLOCK_SUCCESS) + { + PR_ASSERT(PR_FALSE == lock->locked); + lock->locked = PR_TRUE; + lock->owner = pthread_self(); + } + /* XXX set error code? */ + return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE; +} /* PRP_TryLock */ + +PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) +{ + PRCondVar *cv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + cv = PR_NEW(PRCondVar); + if (cv != NULL) + { + int rv; + rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); + PR_ASSERT(0 == rv); + cv->lock = _PR_NAKED_CV_LOCK; + } + return cv; +} /* PRP_NewNakedCondVar */ + +PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) +{ + int rv; + rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); +#if defined(DEBUG) + memset(cvar, 0xaf, sizeof(PRCondVar)); +#endif + PR_DELETE(cvar); +} /* PRP_DestroyNakedCondVar */ + +PR_IMPLEMENT(PRStatus) PRP_NakedWait( + PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout) +{ + PRIntn rv; + PR_ASSERT(cvar != NULL); + /* XXX do we really want to assert this in a naked wait? */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex)); + if (timeout == PR_INTERVAL_NO_TIMEOUT) + rv = pthread_cond_wait(&cvar->cv, &ml->mutex); + else + rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout); + if (rv != 0) + { + _PR_MD_MAP_DEFAULT_ERROR(rv); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* PRP_NakedWait */ + +PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) +{ + int rv; + PR_ASSERT(cvar != NULL); + rv = pthread_cond_signal(&cvar->cv); + PR_ASSERT(0 == rv); + return PR_SUCCESS; +} /* PRP_NakedNotify */ + +PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) +{ + int rv; + PR_ASSERT(cvar != NULL); + rv = pthread_cond_broadcast(&cvar->cv); + PR_ASSERT(0 == rv); + return PR_SUCCESS; +} /* PRP_NakedBroadcast */ + +#endif /* defined(_PR_PTHREADS) */ + +/* ptsynch.c */ diff --git a/nsprpub/pr/src/pthreads/ptthread.c b/nsprpub/pr/src/pthreads/ptthread.c new file mode 100644 index 00000000000..d97c364c84e --- /dev/null +++ b/nsprpub/pr/src/pthreads/ptthread.c @@ -0,0 +1,1653 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: ptthread.c +** Descritpion: Implemenation for threds using pthreds +** Exports: ptthread.h +*/ + +#if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) + +#include "prlog.h" +#include "primpl.h" +#include "prpdce.h" + +#include +#include +#include +#include + +/* + * Record whether or not we have the privilege to set the scheduling + * policy and priority of threads. 0 means that privilege is available. + * EPERM means that privilege is not available. + */ + +static PRIntn pt_schedpriv = 0; +extern PRLock *_pr_sleeplock; + +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 */ + 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 _pt_thread_death_internal(void *arg, PRBool callDestructors); +static void init_pthread_gc_support(void); + +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) +static PRIntn pt_PriorityMap(PRThreadPriority pri) +{ +#ifdef NTO + /* This priority algorithm causes lots of problems on Neutrino + * for now I have just hard coded everything to run at priority 10 + * until I can come up with a new algorithm. + * Jerry.Kirk@Nexwarecorp.com + */ + return 10; +#else + return pt_book.minPrio + + pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; +#endif +} +#endif + +#if defined(GC_LEAK_DETECTOR) && (__GLIBC__ >= 2) && defined(__i386__) + +#include + +typedef struct stack_frame stack_frame; + +struct stack_frame { + stack_frame* next; + void* pc; +}; + +static stack_frame* GetStackFrame() +{ + jmp_buf jb; + stack_frame* currentFrame; + setjmp(jb); + currentFrame = (stack_frame*)(jb[0].__jmpbuf[JB_BP]); + currentFrame = currentFrame->next; + return currentFrame; +} + +static void* GetStackTop() +{ + stack_frame* frame; + frame = GetStackFrame(); + while (frame != NULL) + { + ptrdiff_t pc = (ptrdiff_t)frame->pc; + if ((pc < 0x08000000) || (pc > 0x7fffffff) || (frame->next < frame)) + return frame; + frame = frame->next; + } + return NULL; +} +#endif /* GC_LEAK_DETECTOR && (__GLIBC__ >= 2) && __i386__ */ + +/* +** Initialize a stack for a native pthread thread +*/ +static void _PR_InitializeStack(PRThreadStack *ts) +{ + if( ts && (ts->stackTop == 0) ) { + ts->allocBase = (char *) &ts; + ts->allocSize = ts->stackSize; + + /* + ** Setup stackTop and stackBottom values. + */ +#ifdef HAVE_STACK_GROWING_UP + ts->stackBottom = ts->allocBase + ts->stackSize; + ts->stackTop = ts->allocBase; +#else +#ifdef GC_LEAK_DETECTOR + ts->stackTop = GetStackTop(); + ts->stackBottom = ts->stackTop - ts->stackSize; +#else + ts->stackTop = ts->allocBase; + ts->stackBottom = ts->allocBase - ts->stackSize; +#endif +#endif + } +} + +static void *_pt_root(void *arg) +{ + PRIntn rv; + PRThread *thred = (PRThread*)arg; + PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE; + + /* + * Both the parent thread and this new thread set thred->id. + * The new thread must ensure that thred->id is set before + * it executes its startFunc. The parent thread must ensure + * that thred->id is set before PR_CreateThread() returns. + * Both threads set thred->id without holding a lock. Since + * they are writing the same value, this unprotected double + * write should be safe. + */ + thred->id = pthread_self(); + + /* + ** DCE Threads can't detach during creation, so do it late. + ** I would like to do it only here, but that doesn't seem + ** to work. + */ +#if defined(_PR_DCETHREADS) + if (detached) + { + /* pthread_detach() modifies its argument, so we must pass a copy */ + pthread_t self = thred->id; + rv = pthread_detach(&self); + PR_ASSERT(0 == rv); + } +#endif /* defined(_PR_DCETHREADS) */ + + /* Set up the thread stack information */ + _PR_InitializeStack(thred->stack); + + /* + * Set within the current thread the pointer to our object. + * This object will be deleted when the thread termintates, + * whether in a join or detached (see _PR_InitThreads()). + */ + rv = pthread_setspecific(pt_book.key, thred); + PR_ASSERT(0 == rv); + + /* make the thread visible to the rest of the runtime */ + PR_Lock(pt_book.ml); + + /* If this is a GCABLE thread, set its state appropriately */ + if (thred->suspend & PT_THREAD_SETGCABLE) + thred->state |= PT_THREAD_GCABLE; + thred->suspend = 0; + + thred->prev = pt_book.last; + if (pt_book.last) + pt_book.last->next = thred; + else + pt_book.first = thred; + thred->next = NULL; + pt_book.last = thred; + PR_Unlock(pt_book.ml); + + thred->startFunc(thred->arg); /* make visible to the client */ + + /* unhook the thread from the runtime */ + PR_Lock(pt_book.ml); + /* + * At this moment, PR_CreateThread() may not have set thred->id yet. + * It is safe for a detached thread to free thred only after + * PR_CreateThread() has set thred->id. + */ + if (detached) + { + while (!thred->okToDelete) + PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); + } + + if (thred->state & PT_THREAD_SYSTEM) + pt_book.system -= 1; + else if (--pt_book.user == pt_book.this_many) + PR_NotifyAllCondVar(pt_book.cv); + if (NULL == thred->prev) + pt_book.first = thred->next; + else + 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); + + /* + * Here we set the pthread's backpointer to the PRThread to NULL. + * Otherwise the destructor 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 destructor do the work. + */ + if (PR_FALSE == detached) + { + /* Call TPD destructors on this thread. */ + _PR_DestroyThreadPrivate(thred); + rv = pthread_setspecific(pt_book.key, NULL); + PR_ASSERT(0 == rv); + } + + return NULL; +} /* _pt_root */ + +static PRThread* pt_AttachThread(void) +{ + PRThread *thred = 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 any function that calls PR_GetCurrentThread() + * either (e.g., PR_SetError()) as that will result in infinite + * recursion. + */ + if (!_pr_initialized) return NULL; + + /* PR_NEWZAP must not call PR_GetCurrentThread() */ + thred = PR_NEWZAP(PRThread); + if (NULL != thred) + { + 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; + if (pt_book.last) + pt_book.last->next = thred; + else + pt_book.first = 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, + PRThreadState state, PRUint32 stackSize, PRBool isGCAble) +{ + int rv; + PRThread *thred; + pthread_attr_t tattr; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority) + priority = PR_PRIORITY_FIRST; + else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority) + priority = PR_PRIORITY_LAST; + + rv = _PT_PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + if (EPERM != pt_schedpriv) + { +#if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + struct sched_param schedule; +#endif + +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED); + PR_ASSERT(0 == rv); +#endif + + /* Use the default scheduling policy */ + +#if defined(_PR_DCETHREADS) + rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority)); + PR_ASSERT(0 == rv); +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + rv = pthread_attr_getschedparam(&tattr, &schedule); + PR_ASSERT(0 == rv); + schedule.sched_priority = pt_PriorityMap(priority); + rv = pthread_attr_setschedparam(&tattr, &schedule); + PR_ASSERT(0 == rv); +#ifdef NTO + rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */ + PR_ASSERT(0 == rv); +#endif +#endif /* !defined(_PR_DCETHREADS) */ + } + + /* + * DCE threads can't set detach state before creating the thread. + * AIX can't set detach late. Why can't we all just get along? + */ +#if !defined(_PR_DCETHREADS) + rv = pthread_attr_setdetachstate(&tattr, + ((PR_JOINABLE_THREAD == state) ? + PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED)); + PR_ASSERT(0 == rv); +#endif /* !defined(_PR_DCETHREADS) */ + + /* + * If stackSize is 0, we use the default pthread stack size. + */ + if (stackSize) + { +#ifdef _MD_MINIMUM_STACK_SIZE + if (stackSize < _MD_MINIMUM_STACK_SIZE) + stackSize = _MD_MINIMUM_STACK_SIZE; +#endif + rv = pthread_attr_setstacksize(&tattr, stackSize); + PR_ASSERT(0 == rv); + } + + thred = PR_NEWZAP(PRThread); + if (NULL == thred) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno); + goto done; + } + else + { + pthread_t id; + + thred->arg = arg; + thred->startFunc = start; + thred->priority = priority; + if (PR_UNJOINABLE_THREAD == state) + thred->state |= PT_THREAD_DETACHED; + + if (PR_LOCAL_THREAD == scope) + scope = PR_GLOBAL_THREAD; + + if (PR_GLOBAL_BOUND_THREAD == scope) { +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); + if (rv) { + /* + * system scope not supported + */ + scope = PR_GLOBAL_THREAD; + /* + * reset scope + */ + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS); + PR_ASSERT(0 == rv); + } +#endif + } + if (PR_GLOBAL_THREAD == scope) + thred->state |= PT_THREAD_GLOBAL; + else if (PR_GLOBAL_BOUND_THREAD == scope) + thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND); + else /* force it global */ + thred->state |= PT_THREAD_GLOBAL; + if (PR_SYSTEM_THREAD == type) + thred->state |= PT_THREAD_SYSTEM; + + thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0; + + thred->stack = PR_NEWZAP(PRThreadStack); + if (thred->stack == NULL) { + 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; + } + thred->stack->stackSize = stackSize; + thred->stack->thr = thred; + +#ifdef PT_NO_SIGTIMEDWAIT + 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 (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. + */ + rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred); + +#if !defined(_PR_DCETHREADS) + if (EPERM == rv) + { +#if defined(IRIX) + if (PR_GLOBAL_BOUND_THREAD == scope) { + /* + * SCOPE_SYSTEM requires appropriate privilege + * reset to process scope and try again + */ + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS); + PR_ASSERT(0 == rv); + thred->state &= ~PT_THREAD_BOUND; + } +#else + /* 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. */ +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED); + PR_ASSERT(0 == rv); +#endif +#endif /* IRIX */ + rv = _PT_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; + else if (--pt_book.user == pt_book.this_many) + PR_NotifyAllCondVar(pt_book.cv); + PR_Unlock(pt_book.ml); + + 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; + } + + /* + * Both the parent thread and this new thread set thred->id. + * The parent thread must ensure that thred->id is set before + * PR_CreateThread() returns. (See comments in _pt_root().) + */ + thred->id = id; + + /* + * If the new thread is detached, tell it that PR_CreateThread() + * has set thred->id so it's ok to delete thred. + */ + if (PR_UNJOINABLE_THREAD == state) + { + PR_Lock(pt_book.ml); + thred->okToDelete = PR_TRUE; + PR_NotifyAllCondVar(pt_book.cv); + PR_Unlock(pt_book.ml); + } + } + +done: + rv = _PT_PTHREAD_ATTR_DESTROY(&tattr); + PR_ASSERT(0 == rv); + + return thred; +} /* _PR_CreateThread */ + +PR_IMPLEMENT(PRThread*) PR_CreateThread( + PRThreadType type, void (*start)(void *arg), void *arg, + PRThreadPriority priority, PRThreadScope scope, + PRThreadState state, PRUint32 stackSize) +{ + return _PR_CreateThread( + type, start, arg, priority, scope, state, stackSize, PR_FALSE); +} /* PR_CreateThread */ + +PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble( + PRThreadType type, void (*start)(void *arg), void *arg, + PRThreadPriority priority, PRThreadScope scope, + PRThreadState state, PRUint32 stackSize) +{ + return _PR_CreateThread( + type, start, arg, priority, scope, state, stackSize, PR_TRUE); +} /* PR_CreateThreadGCAble */ + +PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred) +{ + return thred->environment; +} /* GetExecutionEnvironment */ + +PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env) +{ + thred->environment = env; +} /* SetExecutionEnvironment */ + +PR_IMPLEMENT(PRThread*) PR_AttachThread( + PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) +{ + return PR_GetCurrentThread(); +} /* PR_AttachThread */ + + +PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred) +{ + int rv = -1; + void *result = NULL; + PR_ASSERT(thred != NULL); + + if ((0xafafafaf == 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 + * either be an unjoinable thread or it's already had the object + * deleted. However, the client that called join on a detached + * thread deserves all the rath I can muster.... + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + PR_LogPrint( + "PR_JoinThread: %p not joinable | already smashed\n", thred); + } + else + { + pthread_t id = thred->id; + rv = pthread_join(id, &result); + PR_ASSERT(rv == 0 && result == NULL); + if (0 == rv) + { +#ifdef _PR_DCETHREADS + rv = pthread_detach(&id); + PR_ASSERT(0 == rv); +#endif + /* + * PR_FALSE, because the thread already called the TPD + * destructors before exiting _pt_root. + */ + _pt_thread_death_internal(thred, PR_FALSE); + } + 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) +{ + void *thred; + int rv; + + _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); + if (NULL == thred) return; + _pt_thread_death(thred); + rv = pthread_setspecific(pt_book.key, NULL); + PR_ASSERT(0 == rv); +} /* PR_DetachThread */ + +PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void) +{ + void *thred; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _PT_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_BOUND) ? + PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD; +} /* PR_GetThreadScope() */ + +PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred) +{ + return (thred->state & PT_THREAD_SYSTEM) ? + PR_SYSTEM_THREAD : PR_USER_THREAD; +} + +PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred) +{ + return (thred->state & PT_THREAD_DETACHED) ? + PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD; +} /* PR_GetThreadState */ + +PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred) +{ + PR_ASSERT(thred != NULL); + return thred->priority; +} /* PR_GetThreadPriority */ + +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri) +{ + PRIntn rv = -1; + + PR_ASSERT(NULL != thred); + + if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri) + newPri = PR_PRIORITY_FIRST; + else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri) + newPri = PR_PRIORITY_LAST; + +#if defined(_PR_DCETHREADS) + rv = pthread_setprio(thred->id, pt_PriorityMap(newPri)); + /* pthread_setprio returns the old priority */ +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + if (EPERM != pt_schedpriv) + { + int policy; + struct sched_param schedule; + + rv = pthread_getschedparam(thred->id, &policy, &schedule); + if(0 == rv) { + schedule.sched_priority = pt_PriorityMap(newPri); + rv = pthread_setschedparam(thred->id, policy, &schedule); + if (EPERM == rv) + { + pt_schedpriv = EPERM; + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: no thread scheduling privilege")); + } + } + if (rv != 0) + rv = -1; + } +#endif + + thred->priority = newPri; +} /* PR_SetThreadPriority */ + +PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred) +{ + /* + ** If the target thread indicates that it's waiting, + ** find the condition and broadcast to it. Broadcast + ** since we don't know which thread (if there are more + ** than one). This sounds risky, but clients must + ** test their invariants when resumed from a wait and + ** I don't expect very many threads to be waiting on + ** a single condition and I don't expect interrupt to + ** be used very often. + ** + ** I don't know why I thought this would work. Must have + ** been one of those weaker momements after I'd been + ** smelling the vapors. + ** + ** Even with the followng changes it is possible that + ** the pointer to the condition variable is pointing + ** at a bogus value. Will the unerlying code detect + ** that? + */ + PRCondVar *cv; + PR_ASSERT(NULL != thred); + if (NULL == thred) return PR_FAILURE; + + thred->state |= PT_THREAD_ABORTED; + + cv = thred->waiting; + if ((NULL != cv) && !thred->interrupt_blocked) + { + PRIntn rv; + (void)PR_AtomicIncrement(&cv->notify_pending); + rv = pthread_cond_broadcast(&cv->cv); + PR_ASSERT(0 == rv); + if (0 > PR_AtomicDecrement(&cv->notify_pending)) + PR_DestroyCondVar(cv); + } + return PR_SUCCESS; +} /* PR_Interrupt */ + +PR_IMPLEMENT(void) PR_ClearInterrupt(void) +{ + PRThread *me = PR_GetCurrentThread(); + me->state &= ~PT_THREAD_ABORTED; +} /* PR_ClearInterrupt */ + +PR_IMPLEMENT(void) PR_BlockInterrupt(void) +{ + PRThread *me = PR_GetCurrentThread(); + _PT_THREAD_BLOCK_INTERRUPT(me); +} /* PR_BlockInterrupt */ + +PR_IMPLEMENT(void) PR_UnblockInterrupt(void) +{ + PRThread *me = PR_GetCurrentThread(); + _PT_THREAD_UNBLOCK_INTERRUPT(me); +} /* PR_UnblockInterrupt */ + +PR_IMPLEMENT(PRStatus) PR_Yield(void) +{ + static PRBool warning = PR_TRUE; + if (warning) warning = _PR_Obsolete( + "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); + return PR_Sleep(PR_INTERVAL_NO_WAIT); +} + +PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks) +{ + PRStatus rv = PR_SUCCESS; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (PR_INTERVAL_NO_WAIT == ticks) + { + _PT_PTHREAD_YIELD(); + } + else + { + PRCondVar *cv; + PRIntervalTime timein; + + timein = PR_IntervalNow(); + cv = PR_NewCondVar(_pr_sleeplock); + PR_ASSERT(cv != NULL); + PR_Lock(_pr_sleeplock); + 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) +{ + /* PR_TRUE for: call destructors */ + _pt_thread_death_internal(arg, PR_TRUE); +} + +static void _pt_thread_death_internal(void *arg, PRBool callDestructors) +{ + PRThread *thred = (PRThread*)arg; + + if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD)) + { + PR_Lock(pt_book.ml); + if (NULL == thred->prev) + pt_book.first = thred->next; + else + 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 (callDestructors) + _PR_DestroyThreadPrivate(thred); + PR_Free(thred->privateData); + if (NULL != thred->errorString) + PR_Free(thred->errorString); + PR_Free(thred->stack); + if (NULL != thred->syspoll_list) + PR_Free(thred->syspoll_list); +#if defined(_PR_POLL_WITH_SELECT) + if (NULL != thred->selectfd_list) + PR_Free(thred->selectfd_list); +#endif +#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; + +#ifdef _PR_NEED_PTHREAD_INIT + /* + * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily + * initialized, but pthread_self() fails to initialize + * pthreads and hence returns a null thread ID if invoked + * by the primordial thread before any other pthread call. + * So we explicitly initialize pthreads here. + */ + pthread_init(); +#endif + +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) +#if defined(FREEBSD) + { + pthread_attr_t attr; + int policy; + /* get the min and max priorities of the default policy */ + pthread_attr_init(&attr); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_getschedpolicy(&attr, &policy); + pt_book.minPrio = sched_get_priority_min(policy); + PR_ASSERT(-1 != pt_book.minPrio); + pt_book.maxPrio = sched_get_priority_max(policy); + PR_ASSERT(-1 != pt_book.maxPrio); + pthread_attr_destroy(&attr); + } +#else + /* + ** These might be function evaluations + */ + pt_book.minPrio = PT_PRIO_MIN; + pt_book.maxPrio = PT_PRIO_MAX; +#endif +#endif + + PR_ASSERT(NULL == pt_book.ml); + pt_book.ml = PR_NewLock(); + PR_ASSERT(NULL != pt_book.ml); + pt_book.cv = PR_NewCondVar(pt_book.ml); + PR_ASSERT(NULL != pt_book.cv); + thred = PR_NEWZAP(PRThread); + PR_ASSERT(NULL != thred); + thred->arg = NULL; + thred->startFunc = NULL; + thred->priority = priority; + thred->id = pthread_self(); + + thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); + if (PR_SYSTEM_THREAD == type) + { + thred->state |= PT_THREAD_SYSTEM; + pt_book.system += 1; + pt_book.this_many = 0; + } + else + { + pt_book.user += 1; + pt_book.this_many = 1; + } + thred->next = thred->prev = NULL; + pt_book.first = pt_book.last = thred; + + thred->stack = PR_NEWZAP(PRThreadStack); + PR_ASSERT(thred->stack != NULL); + thred->stack->stackSize = 0; + thred->stack->thr = thred; + _PR_InitializeStack(thred->stack); + + /* + * Create a key for our use to store a backpointer in the pthread + * to our PRThread object. This object gets deleted when the thread + * returns from its root in the case of a detached thread. Other + * 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 = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death); + PR_ASSERT(0 == rv); + rv = pthread_setspecific(pt_book.key, thred); + PR_ASSERT(0 == rv); + PR_SetThreadPriority(thred, priority); +} /* _PR_InitThreads */ + +#ifdef __GNUC__ +/* + * GCC supports the constructor and destructor attributes as of + * version 2.5. + */ +static void _PR_Fini(void) __attribute__ ((destructor)); +#elif defined(__SUNPRO_C) +/* + * Sun Studio compiler + */ +#pragma fini(_PR_Fini) +static void _PR_Fini(void); +#elif defined(HPUX) +/* + * Current versions of HP C compiler define __HP_cc. + * HP C compiler A.11.01.20 doesn't define __HP_cc. + */ +#if defined(__ia64) || defined(_LP64) +#pragma FINI "_PR_Fini" +static void _PR_Fini(void); +#else +/* + * Only HP-UX 10.x style initializers are supported in 32-bit links. + * Need to use the +I PR_HPUX10xInit linker option. + */ +#include + +static void _PR_Fini(void); + +void PR_HPUX10xInit(shl_t handle, int loading) +{ + /* + * This function is called when a shared library is loaded as well + * as when the shared library is unloaded. Note that it may not + * be called when the user's program terminates. + * + * handle is the shl_load API handle for the shared library being + * initialized. + * + * loading is non-zero at startup and zero at termination. + */ + if (loading) { + /* ... do some initializations ... */ + } else { + _PR_Fini(); + } +} +#endif +#elif defined(AIX) +/* Need to use the -binitfini::_PR_Fini linker option. */ +#endif + +void _PR_Fini(void) +{ + void *thred; + int rv; + + if (!_pr_initialized) return; + + _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); + if (NULL != thred) + { + /* + * PR_FALSE, because it is unsafe to call back to the + * thread private data destructors at final cleanup. + */ + _pt_thread_death_internal(thred, PR_FALSE); + rv = pthread_setspecific(pt_book.key, NULL); + PR_ASSERT(0 == rv); + } + /* TODO: free other resources used by NSPR */ + /* _pr_initialized = PR_FALSE; */ +} /* _PR_Fini */ + +PR_IMPLEMENT(PRStatus) PR_Cleanup(void) +{ + PRThread *me = PR_GetCurrentThread(); + int rv; + PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR")); + PR_ASSERT(me->state & PT_THREAD_PRIMORD); + if (me->state & PT_THREAD_PRIMORD) + { + PR_Lock(pt_book.ml); + while (pt_book.user > pt_book.this_many) + PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(pt_book.ml); + + _PR_CleanupMW(); + _PR_CleanupTime(); + _PR_CleanupDtoa(); + _PR_CleanupCallOnce(); + _PR_ShutdownLinker(); + _PR_LogCleanup(); + _PR_CleanupNet(); + /* Close all the fd's before calling _PR_CleanupIO */ + _PR_CleanupIO(); + _PR_CleanupCMon(); + + _pt_thread_death(me); + rv = pthread_setspecific(pt_book.key, NULL); + PR_ASSERT(0 == rv); + /* + * 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 + * call isn't immediately prior to exiting, then there's a + * problem. + */ + if (0 == pt_book.system) + { + PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL; + PR_DestroyLock(pt_book.ml); pt_book.ml = NULL; + } + PR_DestroyLock(_pr_sleeplock); + _pr_sleeplock = NULL; + _PR_CleanupLayerCache(); + _PR_CleanupEnv(); +#ifdef _PR_ZONE_ALLOCATOR + _PR_DestroyZones(); +#endif + _pr_initialized = PR_FALSE; + return PR_SUCCESS; + } + return PR_FAILURE; +} /* PR_Cleanup */ + +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 + * yet implemented for pthreads. By the way, these functions should return + * PRStatus rather than PRInt32 to indicate the success/failure status. + * $$$ + */ + +PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask) +{ + return 0; /* not implemented */ +} + +PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ) +{ + return 0; /* not implemented */ +} + +PR_IMPLEMENT(void) +PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg) +{ + thread->dump = dump; + thread->dumpArg = arg; +} + +/* + * Garbage collection support follows. + */ + +#if defined(_PR_DCETHREADS) + +/* + * statics for Garbage Collection support. We don't need to protect these + * signal masks since the garbage collector itself is protected by a lock + * and multiple threads will not be garbage collecting at the same time. + */ +static sigset_t javagc_vtalarm_sigmask; +static sigset_t javagc_intsoff_sigmask; + +#else /* defined(_PR_DCETHREADS) */ + +/* a bogus signal mask for forcing a timed wait */ +/* Not so bogus in AIX as we really do a sigwait */ +static sigset_t sigwait_set; + +static struct timespec onemillisec = {0, 1000000L}; +#ifndef PT_NO_SIGTIMEDWAIT +static struct timespec hundredmillisec = {0, 100000000L}; +#endif + +static void suspend_signal_handler(PRIntn sig); + +#ifdef PT_NO_SIGTIMEDWAIT +static void null_signal_handler(PRIntn sig); +#endif + +#endif /* defined(_PR_DCETHREADS) */ + +/* + * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which + * conflict with the use of these two signals in our GC support. + * So we don't know how to support GC on Linux pthreads. + */ +static void init_pthread_gc_support(void) +{ + PRIntn rv; + +#if defined(_PR_DCETHREADS) + rv = sigemptyset(&javagc_vtalarm_sigmask); + PR_ASSERT(0 == rv); + rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM); + PR_ASSERT(0 == rv); +#else /* defined(_PR_DCETHREADS) */ + { + struct sigaction sigact_usr2; + + sigact_usr2.sa_handler = suspend_signal_handler; + sigact_usr2.sa_flags = SA_RESTART; + sigemptyset (&sigact_usr2.sa_mask); + + rv = sigaction (SIGUSR2, &sigact_usr2, NULL); + PR_ASSERT(0 == rv); + + sigemptyset (&sigwait_set); +#if defined(PT_NO_SIGTIMEDWAIT) + sigaddset (&sigwait_set, SIGUSR1); +#else + sigaddset (&sigwait_set, SIGUSR2); +#endif /* defined(PT_NO_SIGTIMEDWAIT) */ + } +#if defined(PT_NO_SIGTIMEDWAIT) + { + struct sigaction sigact_null; + sigact_null.sa_handler = null_signal_handler; + sigact_null.sa_flags = SA_RESTART; + sigemptyset (&sigact_null.sa_mask); + rv = sigaction (SIGUSR1, &sigact_null, NULL); + PR_ASSERT(0 ==rv); + } +#endif /* defined(PT_NO_SIGTIMEDWAIT) */ +#endif /* defined(_PR_DCETHREADS) */ +} + +PR_IMPLEMENT(void) PR_SetThreadGCAble(void) +{ + PR_Lock(pt_book.ml); + PR_GetCurrentThread()->state |= PT_THREAD_GCABLE; + PR_Unlock(pt_book.ml); +} + +PR_IMPLEMENT(void) PR_ClearThreadGCAble(void) +{ + PR_Lock(pt_book.ml); + PR_GetCurrentThread()->state &= (~PT_THREAD_GCABLE); + PR_Unlock(pt_book.ml); +} + +#if defined(DEBUG) +static PRBool suspendAllOn = PR_FALSE; +#endif + +static PRBool suspendAllSuspended = PR_FALSE; + +PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg) +{ + PRIntn count = 0; + PRStatus rv = PR_SUCCESS; + PRThread* thred = pt_book.first; + +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) +#if !defined(_PR_DCETHREADS) + PRThread *me = PR_GetCurrentThread(); +#endif +#endif + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n")); + /* + * $$$ + * Need to suspend all threads other than me before doing this. + * This is really a gross and disgusting thing to do. The only + * good thing is that since all other threads are suspended, holding + * the lock during a callback seems like child's play. + * $$$ + */ + PR_ASSERT(suspendAllOn); + + while (thred != NULL) + { + /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking + * qp->next after applying the function "func". In particular, "func" + * might remove the thread from the queue and put it into another one in + * which case qp->next no longer points to the next entry in the original + * queue. + * + * To get around this problem, we save qp->next in qp_next before applying + * "func" and use that saved value as the next value after applying "func". + */ + PRThread* next = thred->next; + + if (_PT_IS_GCABLE_THREAD(thred)) + { +#if !defined(_PR_DCETHREADS) + PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED)); +#endif + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("In PR_EnumerateThreads callback thread %p thid = %X\n", + thred, thred->id)); + + rv = func(thred, count++, arg); + if (rv != PR_SUCCESS) + return rv; + } + thred = next; + } + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("End PR_EnumerateThreads count = %d \n", count)); + return rv; +} /* PR_EnumerateThreads */ + +/* + * PR_SuspendAll and PR_ResumeAll are called during garbage collection. The strategy + * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend. + * The signal handler will record the stack pointer and will block until resumed by + * the resume call. Since the signal handler is the last routine called for the + * suspended thread, the stack pointer will also serve as a place where all the + * registers have been saved on the stack for the previously executing routines. + * + * Through global variables, we also make sure that PR_Suspend and PR_Resume does not + * proceed until the thread is suspended or resumed. + */ + +#if !defined(_PR_DCETHREADS) + +/* + * In the signal handler, we can not use condition variable notify or wait. + * This does not work consistently across all pthread platforms. We also can not + * use locking since that does not seem to work reliably across platforms. + * Only thing we can do is yielding while testing for a global condition + * to change. This does work on pthread supported platforms. We may have + * to play with priortities if there are any problems detected. + */ + + /* + * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps + * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no + * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually + * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java, + * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal + * handler as all synchronization mechanisms just break down. + */ + +#if defined(PT_NO_SIGTIMEDWAIT) +static void null_signal_handler(PRIntn sig) +{ + return; +} +#endif + +static void suspend_signal_handler(PRIntn sig) +{ + PRThread *me = PR_GetCurrentThread(); + + PR_ASSERT(me != NULL); + PR_ASSERT(_PT_IS_GCABLE_THREAD(me)); + PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("Begin suspend_signal_handler thred %p thread id = %X\n", + me, me->id)); + + /* + * save stack pointer + */ + me->sp = &me; + + /* + At this point, the thread's stack pointer has been saved, + And it is going to enter a wait loop until it is resumed. + So it is _really_ suspended + */ + + me->suspend |= PT_THREAD_SUSPENDED; + + /* + * now, block current thread + */ +#if defined(PT_NO_SIGTIMEDWAIT) + pthread_cond_signal(&me->suspendResumeCV); + while (me->suspend & PT_THREAD_SUSPENDED) + { +#if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) \ + && !defined(BSDI) && !defined(VMS) && !defined(UNIXWARE) \ + && !defined(DARWIN) && !defined(RISCOS) /*XXX*/ + PRIntn rv; + sigwait(&sigwait_set, &rv); +#endif + } + me->suspend |= PT_THREAD_RESUMED; + pthread_cond_signal(&me->suspendResumeCV); +#else /* defined(PT_NO_SIGTIMEDWAIT) */ + while (me->suspend & PT_THREAD_SUSPENDED) + { + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec); + PR_ASSERT(-1 == rv); + } + me->suspend |= PT_THREAD_RESUMED; +#endif + + /* + * At this point, thread has been resumed, so set a global condition. + * The ResumeAll needs to know that this has really been resumed. + * So the signal handler sets a flag which PR_ResumeAll will reset. + * The PR_ResumeAll must reset this flag ... + */ + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("End suspend_signal_handler thred = %p tid = %X\n", me, me->id)); +} /* suspend_signal_handler */ + +static void pt_SuspendSet(PRThread *thred) +{ + PRIntn rv; + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("pt_SuspendSet thred %p thread id = %X\n", thred, thred->id)); + + + /* + * Check the thread state and signal the thread to suspend + */ + + PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("doing pthread_kill in pt_SuspendSet thred %p tid = %X\n", + thred, thred->id)); +#if defined(VMS) + rv = thread_suspend(thred); +#else + rv = pthread_kill (thred->id, SIGUSR2); +#endif + PR_ASSERT(0 == rv); +} + +static void pt_SuspendTest(PRThread *thred) +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("Begin pt_SuspendTest thred %p thread id = %X\n", thred, thred->id)); + + + /* + * Wait for the thread to be really suspended. This happens when the + * suspend signal handler stores the stack pointer and sets the state + * to suspended. + */ + +#if defined(PT_NO_SIGTIMEDWAIT) + pthread_mutex_lock(&thred->suspendResumeMutex); + while ((thred->suspend & PT_THREAD_SUSPENDED) == 0) + { + pthread_cond_timedwait( + &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec); + } + pthread_mutex_unlock(&thred->suspendResumeMutex); +#else + while ((thred->suspend & PT_THREAD_SUSPENDED) == 0) + { + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); + PR_ASSERT(-1 == rv); + } +#endif + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("End pt_SuspendTest thred %p tid %X\n", thred, thred->id)); +} /* pt_SuspendTest */ + +static void pt_ResumeSet(PRThread *thred) +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("pt_ResumeSet thred %p thread id = %X\n", thred, thred->id)); + + /* + * Clear the global state and set the thread state so that it will + * continue past yield loop in the suspend signal handler + */ + + PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED); + + + thred->suspend &= ~PT_THREAD_SUSPENDED; + +#if defined(PT_NO_SIGTIMEDWAIT) +#if defined(VMS) + thread_resume(thred); +#else + pthread_kill(thred->id, SIGUSR1); +#endif +#endif + +} /* pt_ResumeSet */ + +static void pt_ResumeTest(PRThread *thred) +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("Begin pt_ResumeTest thred %p thread id = %X\n", thred, thred->id)); + + /* + * Wait for the threads resume state to change + * to indicate it is really resumed + */ +#if defined(PT_NO_SIGTIMEDWAIT) + pthread_mutex_lock(&thred->suspendResumeMutex); + while ((thred->suspend & PT_THREAD_RESUMED) == 0) + { + pthread_cond_timedwait( + &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec); + } + pthread_mutex_unlock(&thred->suspendResumeMutex); +#else + while ((thred->suspend & PT_THREAD_RESUMED) == 0) { + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); + PR_ASSERT(-1 == rv); + } +#endif + + thred->suspend &= ~PT_THREAD_RESUMED; + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ( + "End pt_ResumeTest thred %p tid %X\n", thred, thred->id)); +} /* pt_ResumeTest */ + +static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT; + +PR_IMPLEMENT(void) PR_SuspendAll(void) +{ +#ifdef DEBUG + PRIntervalTime stime, etime; +#endif + PRThread* thred = pt_book.first; + PRThread *me = PR_GetCurrentThread(); + int rv; + + rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support); + PR_ASSERT(0 == rv); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n")); + /* + * Stop all threads which are marked GC able. + */ + PR_Lock(pt_book.ml); +#ifdef DEBUG + suspendAllOn = PR_TRUE; + stime = PR_IntervalNow(); +#endif + while (thred != NULL) + { + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) + pt_SuspendSet(thred); + thred = thred->next; + } + + /* Wait till they are really suspended */ + thred = pt_book.first; + while (thred != NULL) + { + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) + pt_SuspendTest(thred); + thred = thred->next; + } + + suspendAllSuspended = PR_TRUE; + +#ifdef DEBUG + etime = PR_IntervalNow(); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\ + ("End PR_SuspendAll (time %dms)\n", + PR_IntervalToMilliseconds(etime - stime))); +#endif +} /* PR_SuspendAll */ + +PR_IMPLEMENT(void) PR_ResumeAll(void) +{ +#ifdef DEBUG + PRIntervalTime stime, etime; +#endif + PRThread* thred = pt_book.first; + PRThread *me = PR_GetCurrentThread(); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n")); + /* + * Resume all previously suspended GC able threads. + */ + suspendAllSuspended = PR_FALSE; +#ifdef DEBUG + stime = PR_IntervalNow(); +#endif + + while (thred != NULL) + { + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) + pt_ResumeSet(thred); + thred = thred->next; + } + + thred = pt_book.first; + while (thred != NULL) + { + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) + pt_ResumeTest(thred); + thred = thred->next; + } + + PR_Unlock(pt_book.ml); +#ifdef DEBUG + suspendAllOn = PR_FALSE; + etime = PR_IntervalNow(); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("End PR_ResumeAll (time %dms)\n", + PR_IntervalToMilliseconds(etime - stime))); +#endif +} /* PR_ResumeAll */ + +/* Return the stack pointer for the given thread- used by the GC */ +PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred) +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("in PR_GetSP thred %p thid = %X, sp = %p\n", + thred, thred->id, thred->sp)); + return thred->sp; +} /* PR_GetSP */ + +#else /* !defined(_PR_DCETHREADS) */ + +static pthread_once_t pt_gc_support_control = pthread_once_init; + +/* + * For DCE threads, there is no pthread_kill or a way of suspending or resuming a + * particular thread. We will just disable the preemption (virtual timer alarm) and + * let the executing thread finish the garbage collection. This stops all other threads + * (GC able or not) and is very inefficient but there is no other choice. + */ +PR_IMPLEMENT(void) PR_SuspendAll() +{ + PRIntn rv; + + rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support); + PR_ASSERT(0 == rv); /* returns -1 on failure */ +#ifdef DEBUG + suspendAllOn = PR_TRUE; +#endif + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n")); + /* + * turn off preemption - i.e add virtual alarm signal to the set of + * blocking signals + */ + rv = sigprocmask( + SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask); + PR_ASSERT(0 == rv); + suspendAllSuspended = PR_TRUE; + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n")); +} /* PR_SuspendAll */ + +PR_IMPLEMENT(void) PR_ResumeAll() +{ + PRIntn rv; + + suspendAllSuspended = PR_FALSE; + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n")); + /* turn on preemption - i.e re-enable virtual alarm signal */ + + rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL); + PR_ASSERT(0 == rv); +#ifdef DEBUG + suspendAllOn = PR_FALSE; +#endif + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n")); +} /* PR_ResumeAll */ + +/* Return the stack pointer for the given thread- used by the GC */ +PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred) +{ + pthread_t tid = thred->id; + char *thread_tcb, *top_sp; + + /* + * For HPUX DCE threads, pthread_t is a struct with the + * following three fields (see pthread.h, dce/cma.h): + * cma_t_address field1; + * short int field2; + * short int field3; + * where cma_t_address is typedef'd to be either void* + * or char*. + */ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n")); + thread_tcb = (char*)tid.field1; + top_sp = *(char**)(thread_tcb + 128); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %p \n", top_sp)); + return top_sp; +} /* PR_GetSP */ + +#endif /* !defined(_PR_DCETHREADS) */ + +#endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */ + +/* ptthread.c */ diff --git a/nsprpub/pr/src/threads/.cvsignore b/nsprpub/pr/src/threads/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/threads/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/threads/Makefile.in b/nsprpub/pr/src/threads/Makefile.in new file mode 100644 index 00000000000..5e6731c5085 --- /dev/null +++ b/nsprpub/pr/src/threads/Makefile.in @@ -0,0 +1,94 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifdef USE_PTHREADS + DIRS = +else +ifdef USE_BTHREADS + DIRS = +else + DIRS = combined +endif +endif + +ifdef USE_PTHREADS +CSRCS = \ + prcmon.c \ + prrwlock.c \ + prtpd.c \ + $(NULL) +else +ifdef USE_BTHREADS +CSRCS = \ + prcmon.c \ + prrwlock.c \ + prtpd.c \ + $(NULL) +else +CSRCS = \ + prcmon.c \ + prdump.c \ + prmon.c \ + prsem.c \ + prrwlock.c \ + prcthr.c \ + prtpd.c \ + $(NULL) +endif +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/pr/src/threads/combined/.cvsignore b/nsprpub/pr/src/threads/combined/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/src/threads/combined/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/src/threads/combined/Makefile.in b/nsprpub/pr/src/threads/combined/Makefile.in new file mode 100644 index 00000000000..476c6c9ad2d --- /dev/null +++ b/nsprpub/pr/src/threads/combined/Makefile.in @@ -0,0 +1,79 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +ifdef USE_PTHREADS +CSRCS = \ + $(NULL) +else +CSRCS = \ + prucpu.c \ + prucv.c \ + prulock.c \ + pruthr.c \ + prustack.c \ + $(NULL) +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/nsprpub/pr/src/threads/combined/README b/nsprpub/pr/src/threads/combined/README new file mode 100644 index 00000000000..aa266652828 --- /dev/null +++ b/nsprpub/pr/src/threads/combined/README @@ -0,0 +1,62 @@ +NSPR 2.0 evolution +------------------ + + +Phase 1- today + +Currently (Oct 10, 1996) NSPR 2.0 has two modes. Either _PR_NTHREAD +is defined, in which case the PR_CreateThread() call always creates a +native kernel thread, or _PR_NTHREAD is not defined and PR_CreateThread() +always creates user level threads within the single, original process. This +source code is reflected in two directories, nspr20/pr/src/threads/native, and +nspr20/pr/src/threads/user. Although the PR_CreateThread() function has +a paramter to specify the "scope" of a thread, this parameter is not yet +used- except on solaris where it uses it to specify bound vs unbound threads. + +Phase 2 - next week + +The next step is to provide a combination of user and native threads. The +idea, of course, is to have some small number of native threads and each of +those threads be able to run user level threads. The number of native +threads created will most likely be proportional to the number of CPUs in +the system. For this reason, the specific set of native threads which are +used to run the user-level threads will be called "CPU" threads. + +The user level threads which will be run on the CPU threads are able to +run on any of the CPU threads available, and over the course of a user-level +thread's lifetime, it may drift from one CPU thread to another. All +user-level threads will compete for processing time via a single run queue. + +Creation of a CPU thread will be primarily controlled by NSPR itself or by +the user running a function PR_Concurrency(). The details of PR_Concurrency() +have not yet been worked out; but the idea is that the user can specify to +NSPR how many CPU threads are desired. + +In this system, user-level threads are created by using PR_CreateThread() and +specifying the PR_LOCAL_SCOPE option. LOCAL_SCOPE indicates that the thread +will be under the control of the "local" scheduler. Creating threads with +GLOBAL_SCOPE, on the other hand will create a thread which is under the +control of the system's scheduler. In otherwords, this creates a native thread +which is not a CPU thread; it runs a single thread task and never has more +than one task to run. LOCAL_SCOPE is much like creating a Solaris unbound +thread, while GLOBAL_SCOPE is similar to creating a Solaris bound thread. + +To implement this architecture, the source code will still maintain the "user" +and "native" directories which is has today. However a third directory +"combined" will also exist. To compile a version of NSPR which only creates +native threads, the user can define _PR_NTHREAD. For exclusive user-level +threads, do not define _PR_NTHREAD. To get the combined threads, define +_PR_NTHREAD and _PR_USE_CPUS. + + +Phase 3 - later than next week + +The goal is to eliminate the 3 directories. Once these three models are in +place, the remaining work will be to eliminate the native and user thread +directories for all platforms, so that the entire thread model is contained +within what is today called the "combined" model. This new and glorious +source code will attempt to make the "combined" model on any platforms which +provide the necessary underlying native threading, but will also be +capable of using exclusive user-level threads on systems which don't have +native threads. + diff --git a/nsprpub/pr/src/threads/combined/prucpu.c b/nsprpub/pr/src/threads/combined/prucpu.c new file mode 100644 index 00000000000..a3938b1ffe6 --- /dev/null +++ b/nsprpub/pr/src/threads/combined/prucpu.c @@ -0,0 +1,440 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +_PRCPU *_pr_primordialCPU = NULL; + +PRInt32 _pr_md_idle_cpus; /* number of idle cpus */ +/* + * The idle threads in MxN models increment/decrement _pr_md_idle_cpus. + * If _PR_HAVE_ATOMIC_OPS is not defined, they can't use the atomic + * increment/decrement routines (which are based on PR_Lock/PR_Unlock), + * because PR_Lock asserts that the calling thread is not an idle thread. + * So we use a _MDLock to protect _pr_md_idle_cpus. + */ +#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY) +#ifndef _PR_HAVE_ATOMIC_OPS +static _MDLock _pr_md_idle_cpus_lock; +#endif +#endif +PRUintn _pr_numCPU; +PRInt32 _pr_cpus_exit; +PRInt32 _pr_cpu_affinity_mask = 0; + +#if !defined (_PR_GLOBAL_THREADS_ONLY) + +static PRUintn _pr_cpuID; + +static void PR_CALLBACK _PR_CPU_Idle(void *); + +static _PRCPU *_PR_CreateCPU(void); +static PRStatus _PR_StartCPU(_PRCPU *cpu, PRThread *thread); + +#if !defined(_PR_LOCAL_THREADS_ONLY) +static void _PR_RunCPU(void *arg); +#endif + +void _PR_InitCPUs() +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_native_threads_only) + return; + + _pr_cpuID = 0; + _MD_NEW_LOCK( &_pr_cpuLock); +#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY) +#ifndef _PR_HAVE_ATOMIC_OPS + _MD_NEW_LOCK(&_pr_md_idle_cpus_lock); +#endif +#endif + +#ifdef _PR_LOCAL_THREADS_ONLY + +#ifdef HAVE_CUSTOM_USER_THREADS + _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me); +#endif + + /* Now start the first CPU. */ + _pr_primordialCPU = _PR_CreateCPU(); + _pr_numCPU = 1; + _PR_StartCPU(_pr_primordialCPU, me); + + _PR_MD_SET_CURRENT_CPU(_pr_primordialCPU); + + /* Initialize cpu for current thread (could be different from me) */ + _PR_MD_CURRENT_THREAD()->cpu = _pr_primordialCPU; + + _PR_MD_SET_LAST_THREAD(me); + +#else /* Combined MxN model */ + + _pr_primordialCPU = _PR_CreateCPU(); + _pr_numCPU = 1; + _PR_CreateThread(PR_SYSTEM_THREAD, + _PR_RunCPU, + _pr_primordialCPU, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, + _PR_IDLE_THREAD); + +#endif /* _PR_LOCAL_THREADS_ONLY */ + + _PR_MD_INIT_CPUS(); +} + +#ifdef WINNT +/* + * Right now this function merely stops the CPUs and does + * not do any other cleanup. + * + * It is only implemented for WINNT because bug 161998 only + * affects the WINNT version of NSPR, but it would be nice + * to implement this function for other platforms too. + */ +void _PR_CleanupCPUs(void) +{ + PRUintn i; + PRCList *qp; + _PRCPU *cpu; + + _pr_cpus_exit = 1; + for (i = 0; i < _pr_numCPU; i++) { + _PR_MD_WAKEUP_WAITER(NULL); + } + for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) { + cpu = _PR_CPU_PTR(qp); + _PR_MD_JOIN_THREAD(&cpu->thread->md); + } +} +#endif + +static _PRCPUQueue *_PR_CreateCPUQueue(void) +{ + PRInt32 index; + _PRCPUQueue *cpuQueue; + cpuQueue = PR_NEWZAP(_PRCPUQueue); + + _MD_NEW_LOCK( &cpuQueue->runQLock ); + _MD_NEW_LOCK( &cpuQueue->sleepQLock ); + _MD_NEW_LOCK( &cpuQueue->miscQLock ); + + for (index = 0; index < PR_PRIORITY_LAST + 1; index++) + PR_INIT_CLIST( &(cpuQueue->runQ[index]) ); + PR_INIT_CLIST( &(cpuQueue->sleepQ) ); + PR_INIT_CLIST( &(cpuQueue->pauseQ) ); + PR_INIT_CLIST( &(cpuQueue->suspendQ) ); + PR_INIT_CLIST( &(cpuQueue->waitingToJoinQ) ); + + cpuQueue->numCPUs = 1; + + return cpuQueue; +} + +/* + * Create a new CPU. + * + * This function initializes enough of the _PRCPU structure so + * that it can be accessed safely by a global thread or another + * CPU. This function does not create the native thread that + * will run the CPU nor does it initialize the parts of _PRCPU + * that must be initialized by that native thread. + * + * The reason we cannot simply have the native thread create + * and fully initialize a new CPU is that we need to be able to + * create a usable _pr_primordialCPU in _PR_InitCPUs without + * assuming that the primordial CPU thread we created can run + * during NSPR initialization. For example, on Windows while + * new threads can be created by DllMain, they won't be able + * to run during DLL initialization. If NSPR is initialized + * by DllMain, the primordial CPU thread won't run until DLL + * initialization is finished. + */ +static _PRCPU *_PR_CreateCPU(void) +{ + _PRCPU *cpu; + + cpu = PR_NEWZAP(_PRCPU); + if (cpu) { + cpu->queue = _PR_CreateCPUQueue(); + if (!cpu->queue) { + PR_DELETE(cpu); + return NULL; + } + } + return cpu; +} + +/* + * Start a new CPU. + * + * 'cpu' is a _PRCPU structure created by _PR_CreateCPU(). + * 'thread' is the native thread that will run the CPU. + * + * If this function fails, 'cpu' is destroyed. + */ +static PRStatus _PR_StartCPU(_PRCPU *cpu, PRThread *thread) +{ + /* + ** Start a new cpu. The assumption this code makes is that the + ** underlying operating system creates a stack to go with the new + ** native thread. That stack will be used by the cpu when pausing. + */ + + PR_ASSERT(!_native_threads_only); + + cpu->last_clock = PR_IntervalNow(); + + /* Before we create any threads on this CPU we have to + * set the current CPU + */ + _PR_MD_SET_CURRENT_CPU(cpu); + _PR_MD_INIT_RUNNING_CPU(cpu); + thread->cpu = cpu; + + cpu->idle_thread = _PR_CreateThread(PR_SYSTEM_THREAD, + _PR_CPU_Idle, + (void *)cpu, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, + _PR_IDLE_THREAD); + + if (!cpu->idle_thread) { + /* didn't clean up CPU queue XXXMB */ + PR_DELETE(cpu); + return PR_FAILURE; + } + PR_ASSERT(cpu->idle_thread->cpu == cpu); + + cpu->idle_thread->no_sched = 0; + + cpu->thread = thread; + + if (_pr_cpu_affinity_mask) + PR_SetThreadAffinityMask(thread, _pr_cpu_affinity_mask); + + /* Created and started a new CPU */ + _PR_CPU_LIST_LOCK(); + cpu->id = _pr_cpuID++; + PR_APPEND_LINK(&cpu->links, &_PR_CPUQ()); + _PR_CPU_LIST_UNLOCK(); + + return PR_SUCCESS; +} + +#if !defined(_PR_GLOBAL_THREADS_ONLY) && !defined(_PR_LOCAL_THREADS_ONLY) +/* +** This code is used during a cpu's initial creation. +*/ +static void _PR_RunCPU(void *arg) +{ + _PRCPU *cpu = (_PRCPU *)arg; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(NULL != me); + + /* + * _PR_StartCPU calls _PR_CreateThread to create the + * idle thread. Because _PR_CreateThread calls PR_Lock, + * the current thread has to remain a global thread + * during the _PR_StartCPU call so that it can wait for + * the lock if the lock is held by another thread. If + * we clear the _PR_GLOBAL_SCOPE flag in + * _PR_MD_CREATE_PRIMORDIAL_THREAD, the current thread + * will be treated as a local thread and have trouble + * waiting for the lock because the CPU is not fully + * constructed yet. + * + * After the CPU is started, it is safe to mark the + * current thread as a local thread. + */ + +#ifdef HAVE_CUSTOM_USER_THREADS + _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me); +#endif + + me->no_sched = 1; + _PR_StartCPU(cpu, me); + +#ifdef HAVE_CUSTOM_USER_THREADS + me->flags &= (~_PR_GLOBAL_SCOPE); +#endif + + _PR_MD_SET_CURRENT_CPU(cpu); + _PR_MD_SET_CURRENT_THREAD(cpu->thread); + me->cpu = cpu; + + while(1) { + PRInt32 is; + if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_MD_START_INTERRUPTS(); + _PR_MD_SWITCH_CONTEXT(me); + } +} +#endif + +static void PR_CALLBACK _PR_CPU_Idle(void *_cpu) +{ + _PRCPU *cpu = (_PRCPU *)_cpu; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(NULL != me); + + me->cpu = cpu; + cpu->idle_thread = me; + if (_MD_LAST_THREAD()) + _MD_LAST_THREAD()->no_sched = 0; + if (!_PR_IS_NATIVE_THREAD(me)) _PR_MD_SET_INTSOFF(0); + while(1) { + PRInt32 is; + PRIntervalTime timeout; + if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + + _PR_RUNQ_LOCK(cpu); +#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY) +#ifdef _PR_HAVE_ATOMIC_OPS + _PR_MD_ATOMIC_INCREMENT(&_pr_md_idle_cpus); +#else + _PR_MD_LOCK(&_pr_md_idle_cpus_lock); + _pr_md_idle_cpus++; + _PR_MD_UNLOCK(&_pr_md_idle_cpus_lock); +#endif /* _PR_HAVE_ATOMIC_OPS */ +#endif + /* If someone on runq; do a nonblocking PAUSECPU */ + if (_PR_RUNQREADYMASK(me->cpu) != 0) { + _PR_RUNQ_UNLOCK(cpu); + timeout = PR_INTERVAL_NO_WAIT; + } else { + _PR_RUNQ_UNLOCK(cpu); + + _PR_SLEEPQ_LOCK(cpu); + if (PR_CLIST_IS_EMPTY(&_PR_SLEEPQ(me->cpu))) { + timeout = PR_INTERVAL_NO_TIMEOUT; + } else { + PRThread *wakeThread; + wakeThread = _PR_THREAD_PTR(_PR_SLEEPQ(me->cpu).next); + timeout = wakeThread->sleep; + } + _PR_SLEEPQ_UNLOCK(cpu); + } + + /* Wait for an IO to complete */ + (void)_PR_MD_PAUSE_CPU(timeout); + +#ifdef WINNT + if (_pr_cpus_exit) { + /* _PR_CleanupCPUs tells us to exit */ + _PR_MD_END_THREAD(); + } +#endif + +#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY) +#ifdef _PR_HAVE_ATOMIC_OPS + _PR_MD_ATOMIC_DECREMENT(&_pr_md_idle_cpus); +#else + _PR_MD_LOCK(&_pr_md_idle_cpus_lock); + _pr_md_idle_cpus--; + _PR_MD_UNLOCK(&_pr_md_idle_cpus_lock); +#endif /* _PR_HAVE_ATOMIC_OPS */ +#endif + + _PR_ClockInterrupt(); + + /* Now schedule any thread that is on the runq + * INTS must be OFF when calling PR_Schedule() + */ + me->state = _PR_RUNNABLE; + _PR_MD_SWITCH_CONTEXT(me); + if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is); + } +} +#endif /* _PR_GLOBAL_THREADS_ONLY */ + +PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs) +{ +#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_LOCAL_THREADS_ONLY) +#ifdef XP_MAC +#pragma unused(numCPUs) +#endif + + /* do nothing */ + +#else /* combined, MxN thread model */ + + PRUintn newCPU; + _PRCPU *cpu; + PRThread *thr; + + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (_native_threads_only) + return; + + _PR_CPU_LIST_LOCK(); + if (_pr_numCPU < numCPUs) { + newCPU = numCPUs - _pr_numCPU; + _pr_numCPU = numCPUs; + } else newCPU = 0; + _PR_CPU_LIST_UNLOCK(); + + for (; newCPU; newCPU--) { + cpu = _PR_CreateCPU(); + thr = _PR_CreateThread(PR_SYSTEM_THREAD, + _PR_RunCPU, + cpu, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, + _PR_IDLE_THREAD); + } +#endif +} + +PR_IMPLEMENT(_PRCPU *) _PR_GetPrimordialCPU(void) +{ + if (_pr_primordialCPU) + return _pr_primordialCPU; + else + return _PR_MD_CURRENT_CPU(); +} diff --git a/nsprpub/pr/src/threads/combined/prucv.c b/nsprpub/pr/src/threads/combined/prucv.c new file mode 100644 index 00000000000..80d919b8906 --- /dev/null +++ b/nsprpub/pr/src/threads/combined/prucv.c @@ -0,0 +1,681 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "primpl.h" +#include "prinrval.h" +#include "prtypes.h" + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + + +/* +** Notify one thread that it has finished waiting on a condition variable +** Caller must hold the _PR_CVAR_LOCK(cv) +*/ +PRBool _PR_NotifyThread (PRThread *thread, PRThread *me) +{ + PRBool rv; + + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + + _PR_THREAD_LOCK(thread); + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + if ( !_PR_IS_NATIVE_THREAD(thread) ) { + if (thread->wait.cvar != NULL) { + thread->wait.cvar = NULL; + + _PR_SLEEPQ_LOCK(thread->cpu); + /* The notify and timeout can collide; in which case both may + * attempt to delete from the sleepQ; only let one do it. + */ + if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) + _PR_DEL_SLEEPQ(thread, PR_TRUE); + _PR_SLEEPQ_UNLOCK(thread->cpu); + + if (thread->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; a Resume operation + * on the thread will move it to the runQ + */ + thread->state = _PR_SUSPENDED; + _PR_MISCQ_LOCK(thread->cpu); + _PR_ADD_SUSPENDQ(thread, thread->cpu); + _PR_MISCQ_UNLOCK(thread->cpu); + _PR_THREAD_UNLOCK(thread); + } else { + /* Make thread runnable */ + thread->state = _PR_RUNNABLE; + _PR_THREAD_UNLOCK(thread); + + _PR_AddThreadToRunQ(me, thread); + _PR_MD_WAKEUP_WAITER(thread); + } + + rv = PR_TRUE; + } else { + /* Thread has already been notified */ + _PR_THREAD_UNLOCK(thread); + rv = PR_FALSE; + } + } else { /* If the thread is a native thread */ + if (thread->wait.cvar) { + thread->wait.cvar = NULL; + + if (thread->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; a Resume operation + * on the thread will enable the thread to run + */ + thread->state = _PR_SUSPENDED; + } else + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + _PR_MD_WAKEUP_WAITER(thread); + rv = PR_TRUE; + } else { + _PR_THREAD_UNLOCK(thread); + rv = PR_FALSE; + } + } + + return rv; +} + +/* + * Notify thread waiting on cvar; called when thread is interrupted + * The thread lock is held on entry and released before return + */ +void _PR_NotifyLockedThread (PRThread *thread) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRCondVar *cvar; + PRThreadPriority pri; + + if ( !_PR_IS_NATIVE_THREAD(me)) + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + + cvar = thread->wait.cvar; + thread->wait.cvar = NULL; + _PR_THREAD_UNLOCK(thread); + + _PR_CVAR_LOCK(cvar); + _PR_THREAD_LOCK(thread); + + if (!_PR_IS_NATIVE_THREAD(thread)) { + _PR_SLEEPQ_LOCK(thread->cpu); + /* The notify and timeout can collide; in which case both may + * attempt to delete from the sleepQ; only let one do it. + */ + if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) + _PR_DEL_SLEEPQ(thread, PR_TRUE); + _PR_SLEEPQ_UNLOCK(thread->cpu); + + /* Make thread runnable */ + pri = thread->priority; + thread->state = _PR_RUNNABLE; + + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + + _PR_AddThreadToRunQ(me, thread); + _PR_THREAD_UNLOCK(thread); + + _PR_MD_WAKEUP_WAITER(thread); + } else { + if (thread->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; a Resume operation + * on the thread will enable the thread to run + */ + thread->state = _PR_SUSPENDED; + } else + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + _PR_MD_WAKEUP_WAITER(thread); + } + + _PR_CVAR_UNLOCK(cvar); + return; +} + +/* +** Make the given thread wait for the given condition variable +*/ +PRStatus _PR_WaitCondVar( + PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) +{ + PRIntn is; + PRStatus rv = PR_SUCCESS; + + PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + +#ifdef _PR_GLOBAL_THREADS_ONLY + if (_PR_PENDING_INTERRUPT(thread)) { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thread->flags &= ~_PR_INTERRUPT; + return PR_FAILURE; + } + + thread->wait.cvar = cvar; + lock->owner = NULL; + _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout); + thread->wait.cvar = NULL; + lock->owner = thread; + if (_PR_PENDING_INTERRUPT(thread)) { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thread->flags &= ~_PR_INTERRUPT; + return PR_FAILURE; + } + + return PR_SUCCESS; +#else /* _PR_GLOBAL_THREADS_ONLY */ + + if ( !_PR_IS_NATIVE_THREAD(thread)) + _PR_INTSOFF(is); + + _PR_CVAR_LOCK(cvar); + _PR_THREAD_LOCK(thread); + + if (_PR_PENDING_INTERRUPT(thread)) { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thread->flags &= ~_PR_INTERRUPT; + _PR_CVAR_UNLOCK(cvar); + _PR_THREAD_UNLOCK(thread); + if ( !_PR_IS_NATIVE_THREAD(thread)) + _PR_INTSON(is); + return PR_FAILURE; + } + + thread->state = _PR_COND_WAIT; + thread->wait.cvar = cvar; + + /* + ** Put the caller thread on the condition variable's wait Q + */ + PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ); + + /* Note- for global scope threads, we don't put them on the + * global sleepQ, so each global thread must put itself + * to sleep only for the time it wants to. + */ + if ( !_PR_IS_NATIVE_THREAD(thread) ) { + _PR_SLEEPQ_LOCK(thread->cpu); + _PR_ADD_SLEEPQ(thread, timeout); + _PR_SLEEPQ_UNLOCK(thread->cpu); + } + _PR_CVAR_UNLOCK(cvar); + _PR_THREAD_UNLOCK(thread); + + /* + ** Release lock protecting the condition variable and thereby giving time + ** to the next thread which can potentially notify on the condition variable + */ + PR_Unlock(lock); + + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, + ("PR_Wait: cvar=%p waiting for %d", cvar, timeout)); + + rv = _PR_MD_WAIT(thread, timeout); + + _PR_CVAR_LOCK(cvar); + PR_REMOVE_LINK(&thread->waitQLinks); + _PR_CVAR_UNLOCK(cvar); + + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, + ("PR_Wait: cvar=%p done waiting", cvar)); + + if ( !_PR_IS_NATIVE_THREAD(thread)) + _PR_INTSON(is); + + /* Acquire lock again that we had just relinquished */ + PR_Lock(lock); + + if (_PR_PENDING_INTERRUPT(thread)) { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thread->flags &= ~_PR_INTERRUPT; + return PR_FAILURE; + } + + return rv; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me) +{ +#ifdef _PR_GLOBAL_THREADS_ONLY + _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock); +#else /* _PR_GLOBAL_THREADS_ONLY */ + + PRCList *q; + PRIntn is; + + if ( !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + + _PR_CVAR_LOCK(cvar); + q = cvar->condQ.next; + while (q != &cvar->condQ) { +#ifndef XP_MAC + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar)); +#endif + if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar) { + if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE) + break; + } + q = q->next; + } + _PR_CVAR_UNLOCK(cvar); + + if ( !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/* +** Cndition variable debugging log info. +*/ +PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen) +{ + PRUint32 nb; + + if (cvar->lock->owner) { + nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]", + cvar, cvar->lock->owner->id, cvar->lock->owner); + } else { + nb = PR_snprintf(buf, buflen, "[%p]", cvar); + } + return nb; +} + +/* +** Expire condition variable waits that are ready to expire. "now" is the current +** time. +*/ +void _PR_ClockInterrupt(void) +{ + PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); + _PRCPU *cpu = me->cpu; + PRIntervalTime elapsed, now; + + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + /* Figure out how much time elapsed since the last clock tick */ + now = PR_IntervalNow(); + elapsed = now - cpu->last_clock; + cpu->last_clock = now; + +#ifndef XP_MAC + PR_LOG(_pr_clock_lm, PR_LOG_MAX, + ("ExpireWaits: elapsed=%lld usec", elapsed)); +#endif + + while(1) { + _PR_SLEEPQ_LOCK(cpu); + if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) { + _PR_SLEEPQ_UNLOCK(cpu); + break; + } + + thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next); + PR_ASSERT(thread->cpu == cpu); + + if (elapsed < thread->sleep) { + thread->sleep -= elapsed; + _PR_SLEEPQMAX(thread->cpu) -= elapsed; + _PR_SLEEPQ_UNLOCK(cpu); + break; + } + _PR_SLEEPQ_UNLOCK(cpu); + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); + + _PR_THREAD_LOCK(thread); + + if (thread->cpu != cpu) { + /* + ** The thread was switched to another CPU + ** between the time we unlocked the sleep + ** queue and the time we acquired the thread + ** lock, so it is none of our business now. + */ + _PR_THREAD_UNLOCK(thread); + continue; + } + + /* + ** Consume this sleeper's amount of elapsed time from the elapsed + ** time value. The next remaining piece of elapsed time will be + ** available for the next sleeping thread's timer. + */ + _PR_SLEEPQ_LOCK(cpu); + PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ)); + if (thread->flags & _PR_ON_SLEEPQ) { + _PR_DEL_SLEEPQ(thread, PR_FALSE); + elapsed -= thread->sleep; + _PR_SLEEPQ_UNLOCK(cpu); + } else { + /* Thread was already handled; Go get another one */ + _PR_SLEEPQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(thread); + continue; + } + + /* Notify the thread waiting on the condition variable */ + if (thread->flags & _PR_SUSPENDING) { + PR_ASSERT((thread->state == _PR_IO_WAIT) || + (thread->state == _PR_COND_WAIT)); + /* + ** Thread is suspended and its condition timeout + ** expired. Transfer thread from sleepQ to suspendQ. + */ + thread->wait.cvar = NULL; + _PR_MISCQ_LOCK(cpu); + thread->state = _PR_SUSPENDED; + _PR_ADD_SUSPENDQ(thread, cpu); + _PR_MISCQ_UNLOCK(cpu); + } else { + if (thread->wait.cvar) { + PRThreadPriority pri; + + /* Do work very similar to what _PR_NotifyThread does */ + PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); + + /* Make thread runnable */ + pri = thread->priority; + thread->state = _PR_RUNNABLE; + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + + PR_ASSERT(thread->cpu == cpu); + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thread, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + + if (pri > me->priority) + _PR_SET_RESCHED_FLAG(); + + thread->wait.cvar = NULL; + + _PR_MD_WAKEUP_WAITER(thread); + + } else if (thread->io_pending == PR_TRUE) { + /* Need to put IO sleeper back on runq */ + int pri = thread->priority; + + thread->io_suspended = PR_TRUE; +#ifdef WINNT + /* + * For NT, record the cpu on which I/O was issued + * I/O cancellation is done on the same cpu + */ + thread->md.thr_bound_cpu = cpu; +#endif + + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + PR_ASSERT(thread->cpu == cpu); + thread->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thread, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + } + } + _PR_THREAD_UNLOCK(thread); + } +} + +/************************************************************************/ + +/* +** Create a new condition variable. +** "lock" is the lock to use with the condition variable. +** +** Condition variables are synchronization objects that threads can use +** to wait for some condition to occur. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) +{ + PRCondVar *cvar; + + PR_ASSERT(lock != NULL); + + cvar = PR_NEWZAP(PRCondVar); + if (cvar) { +#ifdef _PR_GLOBAL_THREADS_ONLY + if(_PR_MD_NEW_CV(&cvar->md)) { + PR_DELETE(cvar); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return NULL; + } +#endif + if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) { + PR_DELETE(cvar); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return NULL; + } + cvar->lock = lock; + PR_INIT_CLIST(&cvar->condQ); + + } else { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return cvar; +} + +/* +** Destroy a condition variable. There must be no thread +** waiting on the condvar. The caller is responsible for guaranteeing +** that the condvar is no longer in use. +** +*/ +PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) +{ + PR_ASSERT(cvar->condQ.next == &cvar->condQ); + +#ifdef _PR_GLOBAL_THREADS_ONLY + _PR_MD_FREE_CV(&cvar->md); +#endif + _PR_MD_FREE_LOCK(&(cvar->ilock)); + + PR_DELETE(cvar); +} + +/* +** Wait for a notify on the condition variable. Sleep for "tiemout" amount +** of ticks (if "timeout" is zero then the sleep is indefinite). While +** the thread is waiting it unlocks lock. When the wait has +** finished the thread regains control of the condition variable after +** locking the associated lock. +** +** The thread waiting on the condvar will be resumed when the condvar is +** notified (assuming the thread is the next in line to receive the +** notify) or when the timeout elapses. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable or the thread has been interrupted. +*/ +extern PRThread *suspendAllThread; +PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(cvar->lock->owner == me); + PR_ASSERT(me != suspendAllThread); + if (cvar->lock->owner != me) return PR_FAILURE; + + return _PR_WaitCondVar(me, cvar, cvar->lock, timeout); +} + +/* +** Notify the highest priority thread waiting on the condition +** variable. If a thread is waiting on the condition variable (using +** PR_Wait) then it is awakened and begins waiting on the lock. +*/ +PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(cvar->lock->owner == me); + PR_ASSERT(me != suspendAllThread); + if (cvar->lock->owner != me) return PR_FAILURE; + + _PR_NotifyCondVar(cvar, me); + return PR_SUCCESS; +} + +/* +** Notify all of the threads waiting on the condition variable. All of +** threads are notified in turn. The highest priority thread will +** probably acquire the lock. +*/ +PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) +{ + PRCList *q; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(cvar->lock->owner == me); + if (cvar->lock->owner != me) return PR_FAILURE; + +#ifdef _PR_GLOBAL_THREADS_ONLY + _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock); + return PR_SUCCESS; +#else /* _PR_GLOBAL_THREADS_ONLY */ + if ( !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_CVAR_LOCK(cvar); + q = cvar->condQ.next; + while (q != &cvar->condQ) { + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); + _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); + q = q->next; + } + _PR_CVAR_UNLOCK(cvar); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + + return PR_SUCCESS; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + + +/*********************************************************************/ +/*********************************************************************/ +/********************ROUTINES FOR DCE EMULATION***********************/ +/*********************************************************************/ +/*********************************************************************/ +#include "prpdce.h" + +PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) +{ + PRCondVar *cvar = PR_NEWZAP(PRCondVar); + if (NULL != cvar) + { + if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) + { + PR_DELETE(cvar); cvar = NULL; + } + else + { + PR_INIT_CLIST(&cvar->condQ); + cvar->lock = _PR_NAKED_CV_LOCK; + } + + } + return cvar; +} + +PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) +{ + PR_ASSERT(cvar->condQ.next == &cvar->condQ); + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); + + _PR_MD_FREE_LOCK(&(cvar->ilock)); + + PR_DELETE(cvar); +} + +PR_IMPLEMENT(PRStatus) PRP_NakedWait( + PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); + return _PR_WaitCondVar(me, cvar, lock, timeout); +} /* PRP_NakedWait */ + +PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); + + _PR_NotifyCondVar(cvar, me); + + return PR_SUCCESS; +} /* PRP_NakedNotify */ + +PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) +{ + PRCList *q; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); + + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_MD_LOCK( &(cvar->ilock) ); + q = cvar->condQ.next; + while (q != &cvar->condQ) { + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); + _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); + q = q->next; + } + _PR_MD_UNLOCK( &(cvar->ilock) ); + if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); + + return PR_SUCCESS; +} /* PRP_NakedBroadcast */ + diff --git a/nsprpub/pr/src/threads/combined/prulock.c b/nsprpub/pr/src/threads/combined/prulock.c new file mode 100644 index 00000000000..5ede1c7b7d0 --- /dev/null +++ b/nsprpub/pr/src/threads/combined/prulock.c @@ -0,0 +1,463 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + + +void _PR_InitLocks(void) +{ + _PR_MD_INIT_LOCKS(); +} + +/* +** Deal with delayed interrupts/requested reschedule during interrupt +** re-enables. +*/ +void _PR_IntsOn(_PRCPU *cpu) +{ + PRUintn missed, pri, i; + _PRInterruptTable *it; + PRThread *me; + + PR_ASSERT(cpu); /* Global threads don't have CPUs */ + PR_ASSERT(_PR_MD_GET_INTSOFF() > 0); + me = _PR_MD_CURRENT_THREAD(); +#if !defined(XP_MAC) + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); +#endif + + /* + ** Process delayed interrupts. This logic is kinda scary because we + ** need to avoid losing an interrupt (it's ok to delay an interrupt + ** until later). + ** + ** There are two missed state words. _pr_ints.where indicates to the + ** interrupt handler which state word is currently safe for + ** modification. + ** + ** This code scans both interrupt state words, using the where flag + ** to indicate to the interrupt which state word is safe for writing. + ** If an interrupt comes in during a scan the other word will be + ** modified. This modification will be noticed during the next + ** iteration of the loop or during the next call to this routine. + */ + for (i = 0; i < 2; i++) { + cpu->where = (1 - i); + missed = cpu->u.missed[i]; + if (missed != 0) { + cpu->u.missed[i] = 0; + for (it = _pr_interruptTable; it->name; it++) { + if (missed & it->missed_bit) { +#ifndef XP_MAC + PR_LOG(_pr_sched_lm, PR_LOG_MIN, + ("IntsOn[0]: %s intr", it->name)); +#endif + (*it->handler)(); + } + } + } + } + + if (cpu->u.missed[3] != 0) { + _PRCPU *cpu; + + _PR_THREAD_LOCK(me); + me->state = _PR_RUNNABLE; + pri = me->priority; + + cpu = me->cpu; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(me, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(me); + _PR_MD_SWITCH_CONTEXT(me); + } +} + +/* +** Unblock the first runnable waiting thread. Skip over +** threads that are trying to be suspended +** Note: Caller must hold _PR_LOCK_LOCK() +*/ +void _PR_UnblockLockWaiter(PRLock *lock) +{ + PRThread *t = NULL; + PRThread *me; + PRCList *q; + + q = lock->waitQ.next; + PR_ASSERT(q != &lock->waitQ); + while (q != &lock->waitQ) { + /* Unblock first waiter */ + t = _PR_THREAD_CONDQ_PTR(q); + + /* + ** We are about to change the thread's state to runnable and for local + ** threads, we are going to assign a cpu to it. So, protect thread's + ** data structure. + */ + _PR_THREAD_LOCK(t); + + if (t->flags & _PR_SUSPENDING) { + q = q->next; + _PR_THREAD_UNLOCK(t); + continue; + } + + /* Found a runnable thread */ + PR_ASSERT(t->state == _PR_LOCK_WAIT); + PR_ASSERT(t->wait.lock == lock); + t->wait.lock = 0; + PR_REMOVE_LINK(&t->waitQLinks); /* take it off lock's waitQ */ + + /* + ** If this is a native thread, nothing else to do except to wake it + ** up by calling the machine dependent wakeup routine. + ** + ** If this is a local thread, we need to assign it a cpu and + ** put the thread on that cpu's run queue. There are two cases to + ** take care of. If the currently running thread is also a local + ** thread, we just assign our own cpu to that thread and put it on + ** the cpu's run queue. If the the currently running thread is a + ** native thread, we assign the primordial cpu to it (on NT, + ** MD_WAKEUP handles the cpu assignment). + */ + + if ( !_PR_IS_NATIVE_THREAD(t) ) { + + t->state = _PR_RUNNABLE; + + me = _PR_MD_CURRENT_THREAD(); + + _PR_AddThreadToRunQ(me, t); + _PR_THREAD_UNLOCK(t); + } else { + t->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(t); + } + _PR_MD_WAKEUP_WAITER(t); + break; + } + return; +} + +/************************************************************************/ + + +PR_IMPLEMENT(PRLock*) PR_NewLock(void) +{ + PRLock *lock; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + lock = PR_NEWZAP(PRLock); + if (lock) { + if (_PR_MD_NEW_LOCK(&lock->ilock) == PR_FAILURE) { + PR_DELETE(lock); + return(NULL); + } + PR_INIT_CLIST(&lock->links); + PR_INIT_CLIST(&lock->waitQ); + } + return lock; +} + +/* +** Destroy the given lock "lock". There is no point in making this race +** free because if some other thread has the pointer to this lock all +** bets are off. +*/ +PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock) +{ + PR_ASSERT(lock->owner == 0); + _PR_MD_FREE_LOCK(&lock->ilock); + PR_DELETE(lock); +} + +extern PRThread *suspendAllThread; +/* +** Lock the lock. +*/ +PR_IMPLEMENT(void) PR_Lock(PRLock *lock) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntn is; + PRThread *t; + PRCList *q; + + PR_ASSERT(me != suspendAllThread); +#if !defined(XP_MAC) + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); +#endif + PR_ASSERT(lock != NULL); +#ifdef _PR_GLOBAL_THREADS_ONLY + PR_ASSERT(lock->owner != me); + _PR_MD_LOCK(&lock->ilock); + lock->owner = me; + return; +#else /* _PR_GLOBAL_THREADS_ONLY */ + + if (_native_threads_only) { + PR_ASSERT(lock->owner != me); + _PR_MD_LOCK(&lock->ilock); + lock->owner = me; + return; + } + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + +retry: + _PR_LOCK_LOCK(lock); + if (lock->owner == 0) { + /* Just got the lock */ + lock->owner = me; + lock->priority = me->priority; + /* Add the granted lock to this owning thread's lock list */ + PR_APPEND_LINK(&lock->links, &me->lockList); + _PR_LOCK_UNLOCK(lock); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return; + } + + /* If this thread already owns this lock, then it is a deadlock */ + PR_ASSERT(lock->owner != me); + + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + +#if 0 + if (me->priority > lock->owner->priority) { + /* + ** Give the lock owner a priority boost until we get the + ** lock. Record the priority we boosted it to. + */ + lock->boostPriority = me->priority; + _PR_SetThreadPriority(lock->owner, me->priority); + } +#endif + + /* + Add this thread to the asked for lock's list of waiting threads. We + add this thread thread in the right priority order so when the unlock + occurs, the thread with the higher priority will get the lock. + */ + q = lock->waitQ.next; + if (q == &lock->waitQ || _PR_THREAD_CONDQ_PTR(q)->priority == + _PR_THREAD_CONDQ_PTR(lock->waitQ.prev)->priority) { + /* + * If all the threads in the lock waitQ have the same priority, + * then avoid scanning the list: insert the element at the end. + */ + q = &lock->waitQ; + } else { + /* Sort thread into lock's waitQ at appropriate point */ + /* Now scan the list for where to insert this entry */ + while (q != &lock->waitQ) { + t = _PR_THREAD_CONDQ_PTR(lock->waitQ.next); + if (me->priority > t->priority) { + /* Found a lower priority thread to insert in front of */ + break; + } + q = q->next; + } + } + PR_INSERT_BEFORE(&me->waitQLinks, q); + + /* + Now grab the threadLock since we are about to change the state. We have + to do this since a PR_Suspend or PR_SetThreadPriority type call that takes + a PRThread* as an argument could be changing the state of this thread from + a thread running on a different cpu. + */ + + _PR_THREAD_LOCK(me); + me->state = _PR_LOCK_WAIT; + me->wait.lock = lock; + _PR_THREAD_UNLOCK(me); + + _PR_LOCK_UNLOCK(lock); + + _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + goto retry; + +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/* +** Unlock the lock. +*/ +PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) +{ + PRCList *q; + PRThreadPriority pri, boost; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(lock != NULL); + PR_ASSERT(lock->owner == me); + PR_ASSERT(me != suspendAllThread); +#if !defined(XP_MAC) + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); +#endif + if (lock->owner != me) { + return PR_FAILURE; + } + +#ifdef _PR_GLOBAL_THREADS_ONLY + lock->owner = 0; + _PR_MD_UNLOCK(&lock->ilock); + return PR_SUCCESS; +#else /* _PR_GLOBAL_THREADS_ONLY */ + + if (_native_threads_only) { + lock->owner = 0; + _PR_MD_UNLOCK(&lock->ilock); + return PR_SUCCESS; + } + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_LOCK_LOCK(lock); + + /* Remove the lock from the owning thread's lock list */ + PR_REMOVE_LINK(&lock->links); + pri = lock->priority; + boost = lock->boostPriority; + if (boost > pri) { + /* + ** We received a priority boost during the time we held the lock. + ** We need to figure out what priority to move to by scanning + ** down our list of lock's that we are still holding and using + ** the highest boosted priority found. + */ + q = me->lockList.next; + while (q != &me->lockList) { + PRLock *ll = _PR_LOCK_PTR(q); + if (ll->boostPriority > pri) { + pri = ll->boostPriority; + } + q = q->next; + } + if (pri != me->priority) { + _PR_SetThreadPriority(me, pri); + } + } + + /* Unblock the first waiting thread */ + q = lock->waitQ.next; + if (q != &lock->waitQ) + _PR_UnblockLockWaiter(lock); + lock->boostPriority = PR_PRIORITY_LOW; + lock->owner = 0; + _PR_LOCK_UNLOCK(lock); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + return PR_SUCCESS; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/* +** Test and then lock the lock if it's not already locked by some other +** thread. Return PR_FALSE if some other thread owned the lock at the +** time of the call. +*/ +PR_IMPLEMENT(PRBool) PR_TestAndLock(PRLock *lock) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRBool rv = PR_FALSE; + PRIntn is; + +#ifdef _PR_GLOBAL_THREADS_ONLY + is = _PR_MD_TEST_AND_LOCK(&lock->ilock); + if (is == 0) { + lock->owner = me; + return PR_TRUE; + } + return PR_FALSE; +#else /* _PR_GLOBAL_THREADS_ONLY */ + +#ifndef _PR_LOCAL_THREADS_ONLY + if (_native_threads_only) { + is = _PR_MD_TEST_AND_LOCK(&lock->ilock); + if (is == 0) { + lock->owner = me; + return PR_TRUE; + } + return PR_FALSE; + } +#endif + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + _PR_LOCK_LOCK(lock); + if (lock->owner == 0) { + /* Just got the lock */ + lock->owner = me; + lock->priority = me->priority; + /* Add the granted lock to this owning thread's lock list */ + PR_APPEND_LINK(&lock->links, &me->lockList); + rv = PR_TRUE; + } + _PR_LOCK_UNLOCK(lock); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + return rv; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/************************************************************************/ +/************************************************************************/ +/***********************ROUTINES FOR DCE EMULATION***********************/ +/************************************************************************/ +/************************************************************************/ +PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock) + { return (PR_TestAndLock(lock)) ? PR_SUCCESS : PR_FAILURE; } diff --git a/nsprpub/pr/src/threads/combined/prustack.c b/nsprpub/pr/src/threads/combined/prustack.c new file mode 100644 index 00000000000..fe15843c02b --- /dev/null +++ b/nsprpub/pr/src/threads/combined/prustack.c @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/* List of free stack virtual memory chunks */ +PRLock *_pr_stackLock; +PRCList _pr_freeStacks = PR_INIT_STATIC_CLIST(&_pr_freeStacks); +PRIntn _pr_numFreeStacks; +PRIntn _pr_maxFreeStacks = 4; + +#ifdef DEBUG +/* +** A variable that can be set via the debugger... +*/ +PRBool _pr_debugStacks = PR_FALSE; +#endif + +/* How much space to leave between the stacks, at each end */ +#define REDZONE (2 << _pr_pageShift) + +#define _PR_THREAD_STACK_PTR(_qp) \ + ((PRThreadStack*) ((char*) (_qp) - offsetof(PRThreadStack,links))) + +void _PR_InitStacks(void) +{ + _pr_stackLock = PR_NewLock(); +} + +void _PR_CleanupStacks(void) +{ + if (_pr_stackLock) { + PR_DestroyLock(_pr_stackLock); + _pr_stackLock = NULL; + } +} + +/* +** Allocate a stack for a thread. +*/ +PRThreadStack *_PR_NewStack(PRUint32 stackSize) +{ + PRCList *qp; + PRThreadStack *ts; + PRThread *thr; + + /* + ** Trim the list of free stacks. Trim it backwards, tossing out the + ** oldest stack found first (this way more recent stacks have a + ** chance of being present in the data cache). + */ + PR_Lock(_pr_stackLock); + qp = _pr_freeStacks.prev; + while ((_pr_numFreeStacks > _pr_maxFreeStacks) && (qp != &_pr_freeStacks)) { + ts = _PR_THREAD_STACK_PTR(qp); + thr = _PR_THREAD_STACK_TO_PTR(ts); + qp = qp->prev; + /* + * skip stacks which are still being used + */ + if (thr->no_sched) + continue; + PR_REMOVE_LINK(&ts->links); + + /* Give platform OS to clear out the stack for debugging */ + _PR_MD_CLEAR_STACK(ts); + + _pr_numFreeStacks--; + _PR_DestroySegment(ts->seg); + PR_DELETE(ts); + } + + /* + ** Find a free thread stack. This searches the list of free'd up + ** virtually mapped thread stacks. + */ + qp = _pr_freeStacks.next; + ts = 0; + while (qp != &_pr_freeStacks) { + ts = _PR_THREAD_STACK_PTR(qp); + thr = _PR_THREAD_STACK_TO_PTR(ts); + qp = qp->next; + /* + * skip stacks which are still being used + */ + if ((!(thr->no_sched)) && ((ts->allocSize - 2*REDZONE) >= stackSize)) { + /* + ** Found a stack that is not in use and is big enough. Change + ** stackSize to fit it. + */ + stackSize = ts->allocSize - 2*REDZONE; + PR_REMOVE_LINK(&ts->links); + _pr_numFreeStacks--; + ts->links.next = 0; + ts->links.prev = 0; + PR_Unlock(_pr_stackLock); + goto done; + } + ts = 0; + } + PR_Unlock(_pr_stackLock); + + if (!ts) { + /* Make a new thread stack object. */ + ts = PR_NEWZAP(PRThreadStack); + if (!ts) { + return NULL; + } + + /* + ** Assign some of the virtual space to the new stack object. We + ** may not get that piece of VM, but if nothing else we will + ** advance the pointer so we don't collide (unless the OS screws + ** up). + */ + ts->allocSize = stackSize + 2*REDZONE; + ts->seg = _PR_NewSegment(ts->allocSize, 0); + if (!ts->seg) { + PR_DELETE(ts); + return NULL; + } + } + + done: + ts->allocBase = (char*)ts->seg->vaddr; + ts->flags = _PR_STACK_MAPPED; + ts->stackSize = stackSize; + +#ifdef HAVE_STACK_GROWING_UP + ts->stackTop = ts->allocBase + REDZONE; + ts->stackBottom = ts->stackTop + stackSize; +#else + ts->stackBottom = ts->allocBase + REDZONE; + ts->stackTop = ts->stackBottom + stackSize; +#endif + + PR_LOG(_pr_thread_lm, PR_LOG_NOTICE, + ("thread stack: base=0x%x limit=0x%x bottom=0x%x top=0x%x\n", + ts->allocBase, ts->allocBase + ts->allocSize - 1, + ts->allocBase + REDZONE, + ts->allocBase + REDZONE + stackSize - 1)); + + _PR_MD_INIT_STACK(ts,REDZONE); + + return ts; +} + +/* +** Free the stack for the current thread +*/ +void _PR_FreeStack(PRThreadStack *ts) +{ + if (!ts) { + return; + } + if (ts->flags & _PR_STACK_PRIMORDIAL) { + PR_DELETE(ts); + return; + } + + /* + ** Put the stack on the free list. This is done because we are still + ** using the stack. Next time a thread is created we will trim the + ** list down; it's safe to do it then because we will have had to + ** context switch to a live stack before another thread can be + ** created. + */ + PR_Lock(_pr_stackLock); + PR_APPEND_LINK(&ts->links, _pr_freeStacks.prev); + _pr_numFreeStacks++; + PR_Unlock(_pr_stackLock); +} diff --git a/nsprpub/pr/src/threads/combined/pruthr.c b/nsprpub/pr/src/threads/combined/pruthr.c new file mode 100644 index 00000000000..7e31b56bf6e --- /dev/null +++ b/nsprpub/pr/src/threads/combined/pruthr.c @@ -0,0 +1,1918 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#include +#include + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + +#if defined(XP_MAC) +#include +#endif + +/* _pr_activeLock protects the following global variables */ +PRLock *_pr_activeLock; +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. + */ + +PRLock *_pr_deadQLock; +PRUint32 _pr_numNativeDead; +PRUint32 _pr_numUserDead; +PRCList _pr_deadNativeQ; +PRCList _pr_deadUserQ; + +PRUint32 _pr_join_counter; + +PRUint32 _pr_local_threads; +PRUint32 _pr_global_threads; + +PRBool suspendAllOn = PR_FALSE; +PRThread *suspendAllThread = NULL; + +extern PRCList _pr_active_global_threadQ; +extern PRCList _pr_active_local_threadQ; + +static void _PR_DecrActiveThreadCount(PRThread *thread); +static PRThread *_PR_AttachThread(PRThreadType, PRThreadPriority, PRThreadStack *); +static void _PR_InitializeNativeStack(PRThreadStack *ts); +static void _PR_InitializeRecycledThread(PRThread *thread); +static void _PR_UserRunThread(void); + +void _PR_InitThreads(PRThreadType type, PRThreadPriority priority, + PRUintn maxPTDs) +{ +#if defined(XP_MAC) +#pragma unused (maxPTDs) +#endif + + PRThread *thread; + PRThreadStack *stack; + + _pr_terminationCVLock = PR_NewLock(); + _pr_activeLock = PR_NewLock(); + +#ifndef HAVE_CUSTOM_USER_THREADS + stack = PR_NEWZAP(PRThreadStack); +#ifdef HAVE_STACK_GROWING_UP + stack->stackTop = (char*) ((((long)&type) >> _pr_pageShift) + << _pr_pageShift); +#else +#if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS) + stack->stackTop = (char*) &thread; +#elif defined(XP_MAC) + stack->stackTop = (char*) LMGetCurStackBase(); +#else + stack->stackTop = (char*) ((((long)&type + _pr_pageSize - 1) + >> _pr_pageShift) << _pr_pageShift); +#endif +#endif +#else + /* If stack is NULL, we're using custom user threads like NT fibers. */ + stack = PR_NEWZAP(PRThreadStack); + if (stack) { + stack->stackSize = 0; + _PR_InitializeNativeStack(stack); + } +#endif /* HAVE_CUSTOM_USER_THREADS */ + + thread = _PR_AttachThread(type, priority, stack); + if (thread) { + _PR_MD_SET_CURRENT_THREAD(thread); + + if (type == PR_SYSTEM_THREAD) { + thread->flags = _PR_SYSTEM; + _pr_systemActive++; + _pr_primordialExitCount = 0; + } else { + _pr_userActive++; + _pr_primordialExitCount = 1; + } + thread->no_sched = 1; + _pr_primordialExitCVar = PR_NewCondVar(_pr_activeLock); + } + + if (!thread) PR_Abort(); +#ifdef _PR_LOCAL_THREADS_ONLY + thread->flags |= _PR_PRIMORDIAL; +#else + thread->flags |= _PR_PRIMORDIAL | _PR_GLOBAL_SCOPE; +#endif + + /* + * Needs _PR_PRIMORDIAL flag set before calling + * _PR_MD_INIT_THREAD() + */ + if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { + /* + * XXX do what? + */ + } + + if (_PR_IS_NATIVE_THREAD(thread)) { + 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_recycleThreads = 0; + _pr_deadQLock = PR_NewLock(); + _pr_numNativeDead = 0; + _pr_numUserDead = 0; + PR_INIT_CLIST(&_pr_deadNativeQ); + PR_INIT_CLIST(&_pr_deadUserQ); +} + +void _PR_CleanupThreads(void) +{ + if (_pr_terminationCVLock) { + PR_DestroyLock(_pr_terminationCVLock); + _pr_terminationCVLock = NULL; + } + if (_pr_activeLock) { + PR_DestroyLock(_pr_activeLock); + _pr_activeLock = NULL; + } + if (_pr_primordialExitCVar) { + PR_DestroyCondVar(_pr_primordialExitCVar); + _pr_primordialExitCVar = NULL; + } + /* TODO _pr_dead{Native,User}Q need to be deleted */ + if (_pr_deadQLock) { + PR_DestroyLock(_pr_deadQLock); + _pr_deadQLock = NULL; + } +} + +/* +** Initialize a stack for a native thread +*/ +static void _PR_InitializeNativeStack(PRThreadStack *ts) +{ + if( ts && (ts->stackTop == 0) ) { + ts->allocSize = ts->stackSize; + + /* + ** Setup stackTop and stackBottom values. + */ +#ifdef HAVE_STACK_GROWING_UP + 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->stackTop = ts->allocBase; + ts->stackBottom = ts->allocBase - ts->stackSize; +#endif + } +} + +void _PR_NotifyJoinWaiters(PRThread *thread) +{ + /* + ** Handle joinable threads. Change the state to waiting for join. + ** Remove from our run Q and put it on global waiting to join Q. + ** 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); + _PR_THREAD_LOCK(thread); + thread->state = _PR_JOIN_WAIT; + if ( !_PR_IS_NATIVE_THREAD(thread) ) { + _PR_MISCQ_LOCK(thread->cpu); + _PR_ADD_JOINQ(thread, thread->cpu); + _PR_MISCQ_UNLOCK(thread->cpu); + } + _PR_THREAD_UNLOCK(thread); + PR_NotifyCondVar(thread->term); + PR_Unlock(_pr_terminationCVLock); + _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(thread->state != _PR_JOIN_WAIT); + } + +} + +/* + * Zero some of the data members of a recycled thread. + * + * Note that we can do this either when a dead thread is added to + * the dead thread queue or when it is reused. Here, we are doing + * this lazily, when the thread is reused in _PR_CreateThread(). + */ +static void _PR_InitializeRecycledThread(PRThread *thread) +{ + /* + * Assert that the following data members are already zeroed + * by _PR_CleanupThread(). + */ +#ifdef DEBUG + if (thread->privateData) { + unsigned int i; + for (i = 0; i < thread->tpdLength; i++) { + PR_ASSERT(thread->privateData[i] == NULL); + } + } +#endif + PR_ASSERT(thread->dumpArg == 0 && thread->dump == 0); + PR_ASSERT(thread->errorString == 0 && thread->errorStringSize == 0); + PR_ASSERT(thread->errorStringLength == 0); + + /* Reset data members in thread structure */ + thread->errorCode = thread->osErrorCode = 0; + thread->io_pending = thread->io_suspended = PR_FALSE; + thread->environment = 0; + PR_INIT_CLIST(&thread->lockList); +} + +PRStatus _PR_RecycleThread(PRThread *thread) +{ + if ( _PR_IS_NATIVE_THREAD(thread) && + _PR_NUM_DEADNATIVE < _pr_recycleThreads) { + _PR_DEADQ_LOCK; + PR_APPEND_LINK(&thread->links, &_PR_DEADNATIVEQ); + _PR_INC_DEADNATIVE; + _PR_DEADQ_UNLOCK; + return (PR_SUCCESS); + } else if ( !_PR_IS_NATIVE_THREAD(thread) && + _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_FAILURE); +} + +/* + * Decrement the active thread count, either _pr_systemActive or + * _pr_userActive, depending on whether the thread is a system thread + * or a user thread. If all the user threads, except possibly + * the primordial thread, have terminated, we notify the primordial + * thread of this condition. + * + * Since this function will lock _pr_activeLock, do not call this + * function while holding the _pr_activeLock lock, as this will result + * in a deadlock. + */ + +static void +_PR_DecrActiveThreadCount(PRThread *thread) +{ + PR_Lock(_pr_activeLock); + if (thread->flags & _PR_SYSTEM) { + _pr_systemActive--; + } else { + _pr_userActive--; + if (_pr_userActive == _pr_primordialExitCount) { + PR_NotifyCondVar(_pr_primordialExitCVar); + } + } + PR_Unlock(_pr_activeLock); +} + +/* +** Detach thread structure +*/ +static void +_PR_DestroyThread(PRThread *thread) +{ + _PR_MD_FREE_LOCK(&thread->threadLock); + PR_DELETE(thread); +} + +void +_PR_NativeDestroyThread(PRThread *thread) +{ + if(thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + if (NULL != thread->privateData) { + PR_ASSERT(0 != thread->tpdLength); + PR_DELETE(thread->privateData); + thread->tpdLength = 0; + } + PR_DELETE(thread->stack); + _PR_DestroyThread(thread); +} + +void +_PR_UserDestroyThread(PRThread *thread) +{ + if(thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + if (NULL != thread->privateData) { + PR_ASSERT(0 != thread->tpdLength); + PR_DELETE(thread->privateData); + thread->tpdLength = 0; + } + _PR_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); + } else { +#ifdef WINNT + _PR_MD_CLEAN_THREAD(thread); +#else + /* + * This assertion does not apply to NT. On NT, every fiber + * has its threadAllocatedOnStack equal to 0. Elsewhere, + * only the primordial thread has its threadAllocatedOnStack + * equal to 0. + */ + PR_ASSERT(thread->flags & _PR_PRIMORDIAL); +#endif + } +} + + +/* +** Run a thread's start function. When the start function returns the +** thread is done executing and no longer needs the CPU. If there are no +** more user threads running then we can exit the program. +*/ +void _PR_NativeRunThread(void *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 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; + + /* + * 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); + + /* + * The following two assertions are meant for NT asynch io. + * + * The thread should have no asynch io in progress when it + * exits, otherwise the overlapped buffer, which is part of + * the thread structure, would become invalid. + */ + PR_ASSERT(thread->io_pending == PR_FALSE); + /* + * This assertion enforces the programming guideline that + * if an io function times out or is interrupted, the thread + * should close the fd to force the asynch io to abort + * before it exits. Right now, closing the fd is the only + * way to clear the io_suspended flag. + */ + PR_ASSERT(thread->io_suspended == PR_FALSE); + + /* + * remove thread from list of active threads + */ + PR_Lock(_pr_activeLock); + PR_REMOVE_LINK(&thread->active); + _pr_global_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_NotifyJoinWaiters(thread); + + _PR_DecrActiveThreadCount(thread); + + 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; + } + + /* Now wait for someone to activate us again... */ + _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT); + } +} + +static void _PR_UserRunThread(void) +{ + PRThread *thread = _PR_MD_CURRENT_THREAD(); + PRIntn is; + + if (_MD_LAST_THREAD()) + _MD_LAST_THREAD()->no_sched = 0; + +#ifdef HAVE_CUSTOM_USER_THREADS + if (thread->stack == NULL) { + thread->stack = PR_NEWZAP(PRThreadStack); + _PR_InitializeNativeStack(thread->stack); + } +#endif /* HAVE_CUSTOM_USER_THREADS */ + + while(1) { + /* Run thread main */ + 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); + + /* + * The following two assertions are meant for NT asynch io. + * + * The thread should have no asynch io in progress when it + * exits, otherwise the overlapped buffer, which is part of + * the thread structure, would become invalid. + */ + PR_ASSERT(thread->io_pending == PR_FALSE); + /* + * This assertion enforces the programming guideline that + * if an io function times out or is interrupted, the thread + * should close the fd to force the asynch io to abort + * before it exits. Right now, closing the fd is the only + * way to clear the io_suspended flag. + */ + 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); + PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting")); + + /* All done, time to go away */ + _PR_CleanupThread(thread); + + _PR_INTSOFF(is); + + _PR_NotifyJoinWaiters(thread); + + _PR_DecrActiveThreadCount(thread); + + thread->state = _PR_DEAD_STATE; + + if (!_pr_recycleThreads || (_PR_RecycleThread(thread) == + PR_FAILURE)) { + /* + ** Destroy the thread resources + */ + _PR_UserDestroyThread(thread); + } + + /* + ** Find another user thread to run. This cpu has finished the + ** previous threads main and is now ready to run another thread. + */ + { + PRInt32 is; + _PR_INTSOFF(is); + _PR_MD_SWITCH_CONTEXT(thread); + } + + /* Will land here when we get scheduled again if we are recycling... */ + } +} + +void _PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntn is; + + if ( _PR_IS_NATIVE_THREAD(thread) ) { + _PR_MD_SET_PRIORITY(&(thread->md), newPri); + return; + } + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_THREAD_LOCK(thread); + if (newPri != thread->priority) { + _PRCPU *cpu = thread->cpu; + + 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)) + _PR_SET_RESCHED_FLAG(); + } + _PR_RUNQ_UNLOCK(cpu); + break; + + case _PR_RUNNABLE: + + _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); + + if (newPri > me->priority) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_SET_RESCHED_FLAG(); + } + + break; + + case _PR_LOCK_WAIT: + case _PR_COND_WAIT: + case _PR_IO_WAIT: + case _PR_SUSPENDED: + + thread->priority = newPri; + break; + } + } + _PR_THREAD_UNLOCK(thread); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); +} + +/* +** Suspend the named thread and copy its gc registers into regBuf +*/ +static void _PR_Suspend(PRThread *thread) +{ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(thread != me); + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread) || (!thread->cpu)); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_THREAD_LOCK(thread); + switch (thread->state) { + case _PR_RUNNABLE: + if (!_PR_IS_NATIVE_THREAD(thread)) { + _PR_RUNQ_LOCK(thread->cpu); + _PR_DEL_RUNQ(thread); + _PR_RUNQ_UNLOCK(thread->cpu); + + _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); + } + 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); + break; + + case _PR_LOCK_WAIT: + case _PR_IO_WAIT: + case _PR_COND_WAIT: + if (_PR_IS_NATIVE_THREAD(thread)) { + _PR_MD_SUSPEND_THREAD(thread); + } + thread->flags |= _PR_SUSPENDING; + break; + + default: + PR_Abort(); + } + _PR_THREAD_UNLOCK(thread); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); +} + +static void _PR_Resume(PRThread *thread) +{ + PRThreadPriority pri; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_THREAD_LOCK(thread); + switch (thread->state) { + case _PR_SUSPENDED: + thread->state = _PR_RUNNABLE; + thread->flags &= ~_PR_SUSPENDING; + if (!_PR_IS_NATIVE_THREAD(thread)) { + _PR_MISCQ_LOCK(thread->cpu); + _PR_DEL_SUSPENDQ(thread); + _PR_MISCQ_UNLOCK(thread->cpu); + + pri = thread->priority; + + _PR_RUNQ_LOCK(thread->cpu); + _PR_ADD_RUNQ(thread, thread->cpu, pri); + _PR_RUNQ_UNLOCK(thread->cpu); + + if (pri > _PR_MD_CURRENT_THREAD()->priority) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_SET_RESCHED_FLAG(); + } + } else { + PR_ASSERT(0); + } + break; + + case _PR_IO_WAIT: + case _PR_COND_WAIT: + thread->flags &= ~_PR_SUSPENDING; +/* PR_ASSERT(thread->wait.monitor->stickyCount == 0); */ + break; + + case _PR_LOCK_WAIT: + { + PRLock *wLock = thread->wait.lock; + + thread->flags &= ~_PR_SUSPENDING; + + _PR_LOCK_LOCK(wLock); + if (thread->wait.lock->owner == 0) { + _PR_UnblockLockWaiter(thread->wait.lock); + } + _PR_LOCK_UNLOCK(wLock); + break; + } + case _PR_RUNNABLE: + 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; + + default: + /* + * 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); + +} + +#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) +static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus) +{ + PRThread *thread; + PRIntn pri; + PRUint32 r; + PRCList *qp; + PRIntn priMin, priMax; + + _PR_RUNQ_LOCK(cpu); + r = _PR_RUNQREADYMASK(cpu); + if (r==0) { + priMin = priMax = PR_PRIORITY_FIRST; + } else if (r == (1<= priMin ; pri-- ) { + if (r & (1 << pri)) { + for (qp = _PR_RUNQ(cpu)[pri].next; + qp != &_PR_RUNQ(cpu)[pri]; + qp = qp->next) { + thread = _PR_THREAD_PTR(qp); + /* + * skip non-schedulable threads + */ + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + 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. + */ + + *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. + */ + thread = NULL; + continue; + } else { + /* Pull thread off of its run queue */ + _PR_DEL_RUNQ(thread); + _PR_RUNQ_UNLOCK(cpu); + return(thread); + } + } + } + thread = NULL; + } + _PR_RUNQ_UNLOCK(cpu); + return(thread); +} +#endif /* !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) */ + +/* +** Schedule this native thread by finding the highest priority nspr +** thread that is ready to run. +** +** Note- everyone really needs to call _PR_MD_SWITCH_CONTEXT (which calls +** PR_Schedule() rather than calling PR_Schedule. Otherwise if there +** is initialization required for switching from SWITCH_CONTEXT, +** it will not get done! +*/ +void _PR_Schedule(void) +{ + PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + PRIntn pri; + PRUint32 r; + PRCList *qp; + PRIntn priMin, priMax; +#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) + PRBool wakeup_cpus; +#endif + + /* Interrupts must be disabled */ + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + + /* Since we are rescheduling, we no longer want to */ + _PR_CLEAR_RESCHED_FLAG(); + + /* + ** Find highest priority thread to run. Bigger priority numbers are + ** higher priority threads + */ + _PR_RUNQ_LOCK(cpu); + /* + * if we are in SuspendAll mode, can schedule only the thread + * 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)) { + /* Pull thread off of its run queue */ + _PR_DEL_RUNQ(thread); + _PR_RUNQ_UNLOCK(cpu); + goto found_thread; + } else { + thread = NULL; + _PR_RUNQ_UNLOCK(cpu); + goto idle_thread; + } + } + r = _PR_RUNQREADYMASK(cpu); + if (r==0) { + priMin = priMax = PR_PRIORITY_FIRST; + } else if (r == (1<= priMin ; pri-- ) { + if (r & (1 << pri)) { + for (qp = _PR_RUNQ(cpu)[pri].next; + qp != &_PR_RUNQ(cpu)[pri]; + qp = qp->next) { + thread = _PR_THREAD_PTR(qp); + /* + * skip non-schedulable threads + */ +#if !defined(XP_MAC) + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); +#endif + if ((thread->no_sched) && (me != thread)){ + thread = NULL; + continue; + } else { + /* Pull thread off of its run queue */ + _PR_DEL_RUNQ(thread); + _PR_RUNQ_UNLOCK(cpu); + goto found_thread; + } + } + } + thread = NULL; + } + _PR_RUNQ_UNLOCK(cpu); + +#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) + + 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; + } + } + } + _PR_CPU_LIST_UNLOCK(); + if (wakeup_cpus == PR_TRUE) + _PR_MD_WAKEUP_CPUS(); + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +idle_thread: + /* + ** There are no threads to run. Switch to the idle thread + */ + PR_LOG(_pr_sched_lm, PR_LOG_MAX, ("pausing")); + thread = _PR_MD_CURRENT_CPU()->idle_thread; + +found_thread: + PR_ASSERT((me == thread) || ((thread->state == _PR_RUNNABLE) && + (!(thread->no_sched)))); + + /* Resume the thread */ + PR_LOG(_pr_sched_lm, PR_LOG_MAX, + ("switching to %d[%p]", thread->id, thread)); + PR_ASSERT(thread->state != _PR_RUNNING); + thread->state = _PR_RUNNING; + + /* If we are on the runq, it just means that we went to sleep on some + * 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 + /* XXXMB; with setjmp/longjmp it is impossible to land here, but + * it is not with fibers... Is this a bad thing? I believe it is + * still safe. + */ + PR_NOT_REACHED("impossible return from schedule"); +#endif +} + +/* +** Attaches a thread. +** Does not set the _PR_MD_CURRENT_THREAD. +** Does not specify the scope of the thread. +*/ +static PRThread * +_PR_AttachThread(PRThreadType type, PRThreadPriority priority, + PRThreadStack *stack) +{ +#if defined(XP_MAC) +#pragma unused (type) +#endif + + PRThread *thread; + char *mem; + + if (priority > PR_PRIORITY_LAST) { + priority = PR_PRIORITY_LAST; + } else if (priority < PR_PRIORITY_FIRST) { + priority = PR_PRIORITY_FIRST; + } + + mem = (char*) PR_CALLOC(sizeof(PRThread)); + if (mem) { + thread = (PRThread*) mem; + thread->priority = priority; + thread->stack = stack; + thread->state = _PR_RUNNING; + PR_INIT_CLIST(&thread->lockList); + if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) { + PR_DELETE(thread); + return 0; + } + + return thread; + } + return 0; +} + + + +PR_IMPLEMENT(PRThread*) +_PR_NativeCreateThread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, + PRUint32 flags) +{ +#if defined(XP_MAC) +#pragma unused (scope) +#endif + + PRThread *thread; + + thread = _PR_AttachThread(type, priority, NULL); + + if (thread) { + PR_Lock(_pr_activeLock); + thread->flags = (flags | _PR_GLOBAL_SCOPE); + thread->id = ++_pr_utid; + if (type == PR_SYSTEM_THREAD) { + thread->flags |= _PR_SYSTEM; + _pr_systemActive++; + } else { + _pr_userActive++; + } + PR_Unlock(_pr_activeLock); + + thread->stack = PR_NEWZAP(PRThreadStack); + if (!thread->stack) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto done; + } + thread->stack->stackSize = stackSize?stackSize:_MD_DEFAULT_STACK_SIZE; + thread->stack->thr = thread; + thread->startFunc = start; + thread->arg = arg; + + /* + Set thread flags related to scope and joinable state. If joinable + thread, allocate a "termination" conidition variable. + */ + if (state == PR_JOINABLE_THREAD) { + thread->term = PR_NewCondVar(_pr_terminationCVLock); + if (thread->term == NULL) { + PR_DELETE(thread->stack); + goto done; + } + } + + 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); + } + +done: + if (thread) { + _PR_DecrActiveThreadCount(thread); + _PR_DestroyThread(thread); + } + return NULL; +} + +/************************************************************************/ + +PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, + PRUint32 flags) +{ + PRThread *me; + PRThread *thread = NULL; + PRThreadStack *stack; + char *top; + PRIntn is; + PRIntn native = 0; + 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. + */ + 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(); + +#if defined(_PR_GLOBAL_THREADS_ONLY) + /* + * can create global threads only + */ + if (scope == PR_LOCAL_THREAD) + scope = PR_GLOBAL_THREAD; +#endif + + if (_native_threads_only) + scope = PR_GLOBAL_THREAD; + + native = (((scope == PR_GLOBAL_THREAD)|| (scope == PR_GLOBAL_BOUND_THREAD)) + && _PR_IS_NATIVE_THREAD_SUPPORTED()); + + _PR_ADJUST_STACKSIZE(stackSize); + + if (native) { + /* + * 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; + + if (_PR_NUM_DEADNATIVE == 0) { /* Thread safe check */ + _PR_DEADQ_UNLOCK; + } else { + thread = _PR_THREAD_PTR(_PR_DEADNATIVEQ.next); + PR_REMOVE_LINK(&thread->links); + _PR_DEC_DEADNATIVE; + _PR_DEADQ_UNLOCK; + + _PR_InitializeRecycledThread(thread); + thread->startFunc = start; + thread->arg = arg; + 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_WAKEUP_WAITER(thread); + return thread; + } + } + thread = _PR_NativeCreateThread(type, start, arg, priority, + scope, state, stackSize, flags); + } else { + if (_PR_NUM_DEADUSER > 0) { + _PR_DEADQ_LOCK; + + if (_PR_NUM_DEADUSER == 0) { /* thread safe check */ + _PR_DEADQ_UNLOCK; + } else { + PRCList *ptr; + + /* Go down list checking for a recycled thread with a + * large enough stack. XXXMB - this has a bad degenerate case. + */ + ptr = _PR_DEADUSERQ.next; + while( ptr != &_PR_DEADUSERQ ) { + thread = _PR_THREAD_PTR(ptr); + if ((thread->stack->stackSize >= stackSize) && + (!thread->no_sched)) { + PR_REMOVE_LINK(&thread->links); + _PR_DEC_DEADUSER; + break; + } else { + ptr = ptr->next; + thread = NULL; + } + } + + _PR_DEADQ_UNLOCK; + + if (thread) { + _PR_InitializeRecycledThread(thread); + 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; + } + } + useRecycled++; + } + } + } + if (thread == NULL) { +#ifndef HAVE_CUSTOM_USER_THREADS + stack = _PR_NewStack(stackSize); + if (!stack) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + /* 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 + */ + if ((PRUptrdiff)top & 0x3f) { + top = (char*)(((PRUptrdiff)top + 0x40) & ~0x3f); + } +#else + top = top - sizeof(PRThread); + thread = (PRThread*) top; + /* + * Make stack 64-byte aligned + */ + if ((PRUptrdiff)top & 0x3f) { + top = (char*)((PRUptrdiff)top & ~0x3f); + } +#endif +#if defined(GC_LEAK_DETECTOR) + /* + * sorry, it is not safe to allocate the thread on the stack, + * because we assign to this object before the GC can learn + * about this thread. we'll just leak thread objects instead. + */ + thread = PR_NEW(PRThread); +#endif + stack->thr = thread; + memset(thread, 0, sizeof(PRThread)); + thread->threadAllocatedOnStack = 1; +#else + thread = _PR_MD_CREATE_USER_THREAD(stackSize, start, arg); + if (!thread) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + thread->threadAllocatedOnStack = 0; + stack = NULL; + top = NULL; +#endif + + /* Initialize thread */ + thread->tpdLength = 0; + thread->privateData = NULL; + thread->stack = stack; + thread->priority = priority; + thread->startFunc = start; + thread->arg = arg; + 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 (_PR_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) { + _PR_MD_FREE_LOCK(&thread->threadLock); + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread->privateData); + PR_DELETE(thread); + } + return NULL; + } + + /* + Set thread flags related to scope and joinable state. If joinable + thread, allocate a "termination" condition variable. + */ + if (state == PR_JOINABLE_THREAD) { + thread->term = PR_NewCondVar(_pr_terminationCVLock); + if (thread->term == NULL) { + _PR_MD_FREE_LOCK(&thread->threadLock); + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread->privateData); + PR_DELETE(thread); + } + return NULL; + } + } + + } + + /* Update thread type counter */ + PR_Lock(_pr_activeLock); + thread->flags = flags; + thread->id = ++_pr_utid; + if (type == PR_SYSTEM_THREAD) { + thread->flags |= _PR_SYSTEM; + _pr_systemActive++; + } else { + _pr_userActive++; + } + + /* Make thread runnable */ + thread->state = _PR_RUNNABLE; + /* + * Add to list of active threads + */ + PR_Unlock(_pr_activeLock); + + if ((! (thread->flags & _PR_IDLE_THREAD)) && _PR_IS_NATIVE_THREAD(me) ) + thread->cpu = _PR_GetPrimordialCPU(); + else + thread->cpu = _PR_MD_CURRENT_CPU(); + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); + + if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me)) { + _PR_INTSOFF(is); + _PR_RUNQ_LOCK(thread->cpu); + _PR_ADD_RUNQ(thread, thread->cpu, priority); + _PR_RUNQ_UNLOCK(thread->cpu); + } + + if (thread->flags & _PR_IDLE_THREAD) { + /* + ** If the creating thread is a kernel thread, we need to + ** awaken the user thread idle thread somehow; potentially + ** it could be sleeping in its idle loop, and we need to poke + ** it. To do so, wake the idle thread... + */ + _PR_MD_WAKEUP_WAITER(NULL); + } else if (_PR_IS_NATIVE_THREAD(me)) { + _PR_MD_WAKEUP_WAITER(thread); + } + if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me) ) + _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) +{ + return _PR_CreateThread(type, start, arg, priority, scope, state, + stackSize, 0); +} + +/* +** 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 +** +** This can return NULL if some kind of error occurs, or if memory is +** tight. +** +** This call is not normally needed unless you create your own native +** thread. PR_Init does this automatically for the primordial thread. +*/ +PRThread* _PRI_AttachThread(PRThreadType type, + PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags) +{ + PRThread *thread; + + 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); + + thread = _PR_AttachThread(type, priority, stack); + if (thread) { + PRIntn is; + + _PR_MD_SET_CURRENT_THREAD(thread); + + thread->flags = flags | _PR_GLOBAL_SCOPE | _PR_ATTACHED; + + if (!stack) { + thread->stack = PR_NEWZAP(PRThreadStack); + if (!thread->stack) { + _PR_DestroyThread(thread); + return NULL; + } + thread->stack->stackSize = _MD_DEFAULT_STACK_SIZE; + } + PR_INIT_CLIST(&thread->links); + + if (_PR_MD_INIT_ATTACHED_THREAD(thread) == PR_FAILURE) { + PR_DELETE(thread->stack); + _PR_DestroyThread(thread); + return NULL; + } + + _PR_MD_SET_CURRENT_CPU(NULL); + + if (_PR_MD_CURRENT_CPU()) { + _PR_INTSOFF(is); + PR_Lock(_pr_activeLock); + } + if (type == PR_SYSTEM_THREAD) { + thread->flags |= _PR_SYSTEM; + _pr_systemActive++; + } else { + _pr_userActive++; + } + if (_PR_MD_CURRENT_CPU()) { + PR_Unlock(_pr_activeLock); + _PR_INTSON(is); + } + } + return thread; +} + +PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type, + PRThreadPriority priority, PRThreadStack *stack) +{ +#ifdef XP_MAC +#pragma unused( type, priority, stack ) +#endif + return PR_GetCurrentThread(); +} + +PR_IMPLEMENT(void) PR_DetachThread(void) +{ + /* + * On IRIX, Solaris, and Windows, foreign threads are detached when + * they terminate. + */ +#if !defined(IRIX) && !defined(WIN32) \ + && !(defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)) + PRThread *me; + if (_pr_initialized) { + me = _PR_MD_GET_ATTACHED_THREAD(); + if ((me != NULL) && (me->flags & _PR_ATTACHED)) + _PRI_DetachThread(); + } +#endif +} + +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_DecrActiveThreadCount(me); + + _PR_MD_CLEAN_THREAD(me); + _PR_MD_SET_CURRENT_THREAD(NULL); + if (!me->threadAllocatedOnStack) + PR_DELETE(me->stack); + _PR_MD_FREE_LOCK(&me->threadLock); + PR_DELETE(me); +} + +/* +** Wait for thread termination: +** "thread" is the target thread +** +** This can return PR_FAILURE if no joinable thread could be found +** corresponding to the specified target thread. +** +** The calling thread is suspended until the target thread completes. +** Several threads cannot wait for the same thread to complete; one thread +** will complete successfully and others will terminate with an error PR_FAILURE. +** The calling thread will not be blocked if the target thread has already +** terminated. +*/ +PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread) +{ + PRIntn is; + PRCondVar *term; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (!_PR_IS_NATIVE_THREAD(me)) + _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; + } + + /* multiple threads can't wait on the same joinable thread */ + if (term->condQ.next != &term->condQ) { + goto ErrorExit; + } + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + + /* wait for the target thread's termination cv invariant */ + PR_Lock (_pr_terminationCVLock); + while (thread->state != _PR_JOIN_WAIT) { + (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); + thread->state = _PR_RUNNABLE; + if ( !_PR_IS_NATIVE_THREAD(thread) ) { + _PR_THREAD_LOCK(thread); + + _PR_MISCQ_LOCK(thread->cpu); + _PR_DEL_JOINQ(thread); + _PR_MISCQ_UNLOCK(thread->cpu); + + _PR_AddThreadToRunQ(me, thread); + _PR_THREAD_UNLOCK(thread); + } + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + + _PR_MD_WAKEUP_WAITER(thread); + + return PR_SUCCESS; + +ErrorExit: + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); + return PR_FAILURE; +} + +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. + */ + if ((PRIntn)newPri > (PRIntn)PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } else if ((PRIntn)newPri < (PRIntn)PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } + + if ( _PR_IS_NATIVE_THREAD(thread) ) { + thread->priority = newPri; + _PR_MD_SET_PRIORITY(&(thread->md), newPri); + } else _PR_SetThreadPriority(thread, newPri); +} + + +/* +** This routine prevents all other threads from running. This call is needed by +** the garbage collector. +*/ +PR_IMPLEMENT(void) PR_SuspendAll(void) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRCList *qp; + + /* + * Stop all user and native threads which are marked GC able. + */ + PR_Lock(_pr_activeLock); + suspendAllOn = PR_TRUE; + 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_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) { + _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_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) + /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */ + _PR_MD_SUSPEND_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); + } + _PR_MD_END_SUSPEND_ALL(); +} + +/* +** This routine unblocks all other threads that were suspended from running by +** PR_SuspendAll(). This call is needed by the garbage collector. +*/ +PR_IMPLEMENT(void) PR_ResumeAll(void) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRCList *qp; + + /* + * Resume all user and native threads which are marked GC able. + */ + _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_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) + _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_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) + _PR_MD_RESUME_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); + } + _PR_MD_END_RESUME_ALL(); + suspendAllThread = NULL; + suspendAllOn = PR_FALSE; + PR_Unlock(_pr_activeLock); +} + +PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg) +{ + PRCList *qp, *qp_next; + PRIntn i = 0; + PRStatus rv = PR_SUCCESS; + PRThread* t; + + /* + ** Currently Enumerate threads happen only with suspension and + ** pr_activeLock held + */ + PR_ASSERT(suspendAllOn); + + /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking + * qp->next after applying the function "func". In particular, "func" + * might remove the thread from the queue and put it into another one in + * which case qp->next no longer points to the next entry in the original + * queue. + * + * To get around this problem, we save qp->next in qp_next before applying + * "func" and use that saved value as the next value after applying "func". + */ + + /* + * Traverse the list of local and global threads + */ + for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; + qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp_next) + { + qp_next = qp->next; + t = _PR_ACTIVE_THREAD_PTR(qp); + if (_PR_IS_GCABLE_THREAD(t)) + { + rv = (*func)(t, i, arg); + if (rv != PR_SUCCESS) + return rv; + i++; + } + } + for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; + qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp_next) + { + qp_next = qp->next; + t = _PR_ACTIVE_THREAD_PTR(qp); + if (_PR_IS_GCABLE_THREAD(t)) + { + rv = (*func)(t, i, arg); + if (rv != PR_SUCCESS) + return rv; + i++; + } + } + return rv; +} + +/* FUNCTION: _PR_AddSleepQ +** DESCRIPTION: +** Adds a thread to the sleep/pauseQ. +** RESTRICTIONS: +** Caller must have the RUNQ lock. +** Caller must be a user level thread +*/ +PR_IMPLEMENT(void) +_PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout) +{ + _PRCPU *cpu = thread->cpu; + + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + /* append the thread to the global pause Q */ + PR_APPEND_LINK(&thread->links, &_PR_PAUSEQ(thread->cpu)); + thread->flags |= _PR_ON_PAUSEQ; + } else { + PRIntervalTime sleep; + PRCList *q; + PRThread *t; + + /* sort onto global sleepQ */ + sleep = timeout; + + /* Check if we are longest timeout */ + if (timeout >= _PR_SLEEPQMAX(cpu)) { + PR_INSERT_BEFORE(&thread->links, &_PR_SLEEPQ(cpu)); + thread->sleep = timeout - _PR_SLEEPQMAX(cpu); + _PR_SLEEPQMAX(cpu) = timeout; + } else { + /* Sort thread into global sleepQ at appropriate point */ + q = _PR_SLEEPQ(cpu).next; + + /* Now scan the list for where to insert this entry */ + while (q != &_PR_SLEEPQ(cpu)) { + t = _PR_THREAD_PTR(q); + if (sleep < t->sleep) { + /* Found sleeper to insert in front of */ + break; + } + sleep -= t->sleep; + q = q->next; + } + thread->sleep = sleep; + PR_INSERT_BEFORE(&thread->links, q); + + /* + ** Subtract our sleep time from the sleeper that follows us (there + ** must be one) so that they remain relative to us. + */ + PR_ASSERT (thread->links.next != &_PR_SLEEPQ(cpu)); + + t = _PR_THREAD_PTR(thread->links.next); + PR_ASSERT(_PR_THREAD_PTR(t->links.prev) == thread); + t->sleep -= sleep; + } + + thread->flags |= _PR_ON_SLEEPQ; + } +} + +/* FUNCTION: _PR_DelSleepQ +** DESCRIPTION: +** Removes a thread from the sleep/pauseQ. +** INPUTS: +** If propogate_time is true, then the thread following the deleted +** thread will be get the time from the deleted thread. This is used +** when deleting a sleeper that has not timed out. +** RESTRICTIONS: +** Caller must have the RUNQ lock. +** Caller must be a user level thread +*/ +PR_IMPLEMENT(void) +_PR_DelSleepQ(PRThread *thread, PRBool propogate_time) +{ + _PRCPU *cpu = thread->cpu; + + /* Remove from pauseQ/sleepQ */ + if (thread->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + if (thread->flags & _PR_ON_SLEEPQ) { + PRCList *q = thread->links.next; + if (q != &_PR_SLEEPQ(cpu)) { + if (propogate_time == PR_TRUE) { + PRThread *after = _PR_THREAD_PTR(q); + after->sleep += thread->sleep; + } else + _PR_SLEEPQMAX(cpu) -= thread->sleep; + } else { + /* Check if prev is the beggining of the list; if so, + * we are the only element on the list. + */ + if (thread->links.prev != &_PR_SLEEPQ(cpu)) + _PR_SLEEPQMAX(cpu) -= thread->sleep; + else + _PR_SLEEPQMAX(cpu) = 0; + } + thread->flags &= ~_PR_ON_SLEEPQ; + } else { + thread->flags &= ~_PR_ON_PAUSEQ; + } + PR_REMOVE_LINK(&thread->links); + } else + PR_ASSERT(0); +} + +void +_PR_AddThreadToRunQ( + PRThread *me, /* the current thread */ + PRThread *thread) /* the local thread to be added to a run queue */ +{ + PRThreadPriority pri = thread->priority; + _PRCPU *cpu = thread->cpu; + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); + +#if defined(WINNT) + /* + * On NT, we can only reliably know that the current CPU + * is not idle. We add the awakened thread to the run + * queue of its CPU if its CPU is the current CPU. + * For any other CPU, we don't really know whether it + * is busy or idle. So in all other cases, we just + * "post" the awakened thread to the IO completion port + * for the next idle CPU to execute (this is done in + * _PR_MD_WAKEUP_WAITER). + * Threads with a suspended I/O operation remain bound to + * the same cpu until I/O is cancelled + * + * NOTE: the boolean expression below must be the exact + * opposite of the corresponding boolean expression in + * _PR_MD_WAKEUP_WAITER. + */ + if ((!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) || + (thread->md.thr_bound_cpu)) { + PR_ASSERT(!thread->md.thr_bound_cpu || + (thread->md.thr_bound_cpu == cpu)); + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thread, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + } +#else + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thread, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) { + if (pri > me->priority) { + _PR_SET_RESCHED_FLAG(); + } + } +#endif +} diff --git a/nsprpub/pr/src/threads/prcmon.c b/nsprpub/pr/src/threads/prcmon.c new file mode 100644 index 00000000000..67aee4cfa1c --- /dev/null +++ b/nsprpub/pr/src/threads/prcmon.c @@ -0,0 +1,463 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include +#include + +/* Lock used to lock the monitor cache */ +#ifdef _PR_NO_PREEMPT +#define _PR_NEW_LOCK_MCACHE() +#define _PR_DESTROY_LOCK_MCACHE() +#define _PR_LOCK_MCACHE() +#define _PR_UNLOCK_MCACHE() +#else +#ifdef _PR_LOCAL_THREADS_ONLY +#define _PR_NEW_LOCK_MCACHE() +#define _PR_DESTROY_LOCK_MCACHE() +#define _PR_LOCK_MCACHE() { PRIntn _is; _PR_INTSOFF(_is) +#define _PR_UNLOCK_MCACHE() _PR_INTSON(_is); } +#else +PRLock *_pr_mcacheLock; +#define _PR_NEW_LOCK_MCACHE() (_pr_mcacheLock = PR_NewLock()) +#define _PR_DESTROY_LOCK_MCACHE() \ + PR_BEGIN_MACRO \ + if (_pr_mcacheLock) { \ + PR_DestroyLock(_pr_mcacheLock); \ + _pr_mcacheLock = NULL; \ + } \ + PR_END_MACRO +#define _PR_LOCK_MCACHE() PR_Lock(_pr_mcacheLock) +#define _PR_UNLOCK_MCACHE() PR_Unlock(_pr_mcacheLock) +#endif +#endif + +/************************************************************************/ + +typedef struct MonitorCacheEntryStr MonitorCacheEntry; + +struct MonitorCacheEntryStr { + MonitorCacheEntry* next; + void* address; + PRMonitor* mon; + long cacheEntryCount; +}; + +/* +** An array of MonitorCacheEntry's, plus a pointer to link these +** arrays together. +*/ + +typedef struct MonitorCacheEntryBlockStr MonitorCacheEntryBlock; + +struct MonitorCacheEntryBlockStr { + MonitorCacheEntryBlock* next; + MonitorCacheEntry entries[1]; +}; + +static PRUint32 hash_mask; +static PRUintn num_hash_buckets; +static PRUintn num_hash_buckets_log2; +static MonitorCacheEntry **hash_buckets; +static MonitorCacheEntry *free_entries; +static PRUintn num_free_entries; +static PRBool expanding; +static MonitorCacheEntryBlock *mcache_blocks; + +static void (*OnMonitorRecycle)(void *address); + +#define HASH(address) \ + ((PRUint32) ( ((PRUptrdiff)(address) >> 2) ^ \ + ((PRUptrdiff)(address) >> 10) ) \ + & hash_mask) + +/* +** Expand the monitor cache. This grows the hash buckets and allocates a +** new chunk of cache entries and throws them on the free list. We keep +** as many hash buckets as there are entries. +** +** Because we call malloc and malloc may need the monitor cache, we must +** ensure that there are several free monitor cache entries available for +** malloc to get. FREE_THRESHOLD is used to prevent monitor cache +** starvation during monitor cache expansion. +*/ + +#define FREE_THRESHOLD 5 + +static PRStatus ExpandMonitorCache(PRUintn new_size_log2) +{ + MonitorCacheEntry **old_hash_buckets, *p; + PRUintn i, entries, old_num_hash_buckets, added; + MonitorCacheEntry **new_hash_buckets; + MonitorCacheEntryBlock *new_block; + + entries = 1L << new_size_log2; + + /* + ** Expand the monitor-cache-entry free list + */ + new_block = (MonitorCacheEntryBlock*) + PR_CALLOC(sizeof(MonitorCacheEntryBlock) + + (entries - 1) * sizeof(MonitorCacheEntry)); + if (NULL == new_block) return PR_FAILURE; + + /* + ** Allocate system monitors for the new monitor cache entries. If we + ** run out of system monitors, break out of the loop. + */ + for (i = 0, p = new_block->entries; i < entries; i++, p++) { + p->mon = PR_NewMonitor(); + if (!p->mon) + break; + } + added = i; + if (added != entries) { + MonitorCacheEntryBlock *realloc_block; + + if (added == 0) { + /* Totally out of system monitors. Lossage abounds */ + PR_DELETE(new_block); + return PR_FAILURE; + } + + /* + ** We were able to allocate some of the system monitors. Use + ** realloc to shrink down the new_block memory. If that fails, + ** carry on with the too-large new_block. + */ + realloc_block = (MonitorCacheEntryBlock*) + PR_REALLOC(new_block, sizeof(MonitorCacheEntryBlock) + + (added - 1) * sizeof(MonitorCacheEntry)); + if (realloc_block) + new_block = realloc_block; + } + + /* + ** Now that we have allocated all of the system monitors, build up + ** the new free list. We can just update the free_list because we own + ** the mcache-lock and we aren't calling anyone who might want to use + ** it. + */ + for (i = 0, p = new_block->entries; i < added - 1; i++, p++) + p->next = p + 1; + p->next = free_entries; + free_entries = new_block->entries; + num_free_entries += added; + new_block->next = mcache_blocks; + mcache_blocks = new_block; + + /* Try to expand the hash table */ + new_hash_buckets = (MonitorCacheEntry**) + PR_CALLOC(entries * sizeof(MonitorCacheEntry*)); + if (NULL == new_hash_buckets) { + /* + ** Partial lossage. In this situation we don't get any more hash + ** buckets, which just means that the table lookups will take + ** longer. This is bad, but not fatal + */ + PR_LOG(_pr_cmon_lm, PR_LOG_WARNING, + ("unable to grow monitor cache hash buckets")); + return PR_SUCCESS; + } + + /* + ** Compute new hash mask value. This value is used to mask an address + ** until it's bits are in the right spot for indexing into the hash + ** table. + */ + hash_mask = entries - 1; + + /* + ** Expand the hash table. We have to rehash everything in the old + ** table into the new table. + */ + old_hash_buckets = hash_buckets; + old_num_hash_buckets = num_hash_buckets; + for (i = 0; i < old_num_hash_buckets; i++) { + p = old_hash_buckets[i]; + while (p) { + MonitorCacheEntry *next = p->next; + + /* Hash based on new table size, and then put p in the new table */ + PRUintn hash = HASH(p->address); + p->next = new_hash_buckets[hash]; + new_hash_buckets[hash] = p; + + p = next; + } + } + + /* + ** Switch over to new hash table and THEN call free of the old + ** table. Since free might re-enter _pr_mcache_lock, things would + ** break terribly if it used the old hash table. + */ + hash_buckets = new_hash_buckets; + num_hash_buckets = entries; + num_hash_buckets_log2 = new_size_log2; + PR_DELETE(old_hash_buckets); + + PR_LOG(_pr_cmon_lm, PR_LOG_NOTICE, + ("expanded monitor cache to %d (buckets %d)", + num_free_entries, entries)); + + return PR_SUCCESS; +} /* ExpandMonitorCache */ + +/* +** Lookup a monitor cache entry by address. Return a pointer to the +** pointer to the monitor cache entry on success, null on failure. +*/ +static MonitorCacheEntry **LookupMonitorCacheEntry(void *address) +{ + PRUintn hash; + MonitorCacheEntry **pp, *p; + + hash = HASH(address); + pp = hash_buckets + hash; + while ((p = *pp) != 0) { + if (p->address == address) { + if (p->cacheEntryCount > 0) + return pp; + return NULL; + } + pp = &p->next; + } + return NULL; +} + +/* +** Try to create a new cached monitor. If it's already in the cache, +** great - return it. Otherwise get a new free cache entry and set it +** up. If the cache free space is getting low, expand the cache. +*/ +static PRMonitor *CreateMonitor(void *address) +{ + PRUintn hash; + MonitorCacheEntry **pp, *p; + + hash = HASH(address); + pp = hash_buckets + hash; + while ((p = *pp) != 0) { + if (p->address == address) goto gotit; + + pp = &p->next; + } + + /* Expand the monitor cache if we have run out of free slots in the table */ + if (num_free_entries < FREE_THRESHOLD) { + /* Expand monitor cache */ + + /* + ** This function is called with the lock held. So what's the 'expanding' + ** boolean all about? Seems a bit redundant. + */ + if (!expanding) { + PRStatus rv; + + expanding = PR_TRUE; + rv = ExpandMonitorCache(num_hash_buckets_log2 + 1); + expanding = PR_FALSE; + if (PR_FAILURE == rv) return NULL; + + /* redo the hash because it'll be different now */ + hash = HASH(address); + } else { + /* + ** We are in process of expanding and we need a cache + ** monitor. Make sure we have enough! + */ + PR_ASSERT(num_free_entries > 0); + } + } + + /* Make a new monitor */ + p = free_entries; + free_entries = p->next; + num_free_entries--; + if (OnMonitorRecycle && p->address) + OnMonitorRecycle(p->address); + p->address = address; + p->next = hash_buckets[hash]; + hash_buckets[hash] = p; + PR_ASSERT(p->cacheEntryCount == 0); + + gotit: + p->cacheEntryCount++; + return p->mon; +} + +/* +** Initialize the monitor cache +*/ +void _PR_InitCMon(void) +{ + _PR_NEW_LOCK_MCACHE(); + ExpandMonitorCache(3); +} + +/* +** Destroy the monitor cache +*/ +void _PR_CleanupCMon(void) +{ + _PR_DESTROY_LOCK_MCACHE(); + + while (free_entries) { + PR_DestroyMonitor(free_entries->mon); + free_entries = free_entries->next; + } + num_free_entries = 0; + + while (mcache_blocks) { + MonitorCacheEntryBlock *block; + + block = mcache_blocks; + mcache_blocks = block->next; + PR_DELETE(block); + } + + PR_DELETE(hash_buckets); + hash_mask = 0; + num_hash_buckets = 0; + num_hash_buckets_log2 = 0; + + expanding = PR_FALSE; + OnMonitorRecycle = NULL; +} + +/* +** Create monitor for address. Don't enter the monitor while we have the +** mcache locked because we might block! +*/ +PR_IMPLEMENT(PRMonitor*) PR_CEnterMonitor(void *address) +{ + PRMonitor *mon; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _PR_LOCK_MCACHE(); + mon = CreateMonitor(address); + _PR_UNLOCK_MCACHE(); + + if (!mon) return NULL; + + PR_EnterMonitor(mon); + return mon; +} + +PR_IMPLEMENT(PRStatus) PR_CExitMonitor(void *address) +{ + MonitorCacheEntry **pp, *p; + PRStatus status = PR_SUCCESS; + + _PR_LOCK_MCACHE(); + pp = LookupMonitorCacheEntry(address); + if (pp != NULL) { + p = *pp; + if (--p->cacheEntryCount == 0) { + /* + ** Nobody is using the system monitor. Put it on the cached free + ** list. We are safe from somebody trying to use it because we + ** have the mcache locked. + */ + p->address = 0; /* defensive move */ + *pp = p->next; /* unlink from hash_buckets */ + p->next = free_entries; /* link into free list */ + free_entries = p; + num_free_entries++; /* count it as free */ + } + status = PR_ExitMonitor(p->mon); + } else { + status = PR_FAILURE; + } + _PR_UNLOCK_MCACHE(); + + return status; +} + +PR_IMPLEMENT(PRStatus) PR_CWait(void *address, PRIntervalTime ticks) +{ + MonitorCacheEntry **pp; + PRMonitor *mon; + + _PR_LOCK_MCACHE(); + pp = LookupMonitorCacheEntry(address); + mon = pp ? ((*pp)->mon) : NULL; + _PR_UNLOCK_MCACHE(); + + if (mon == NULL) + return PR_FAILURE; + return PR_Wait(mon, ticks); +} + +PR_IMPLEMENT(PRStatus) PR_CNotify(void *address) +{ + MonitorCacheEntry **pp; + PRMonitor *mon; + + _PR_LOCK_MCACHE(); + pp = LookupMonitorCacheEntry(address); + mon = pp ? ((*pp)->mon) : NULL; + _PR_UNLOCK_MCACHE(); + + if (mon == NULL) + return PR_FAILURE; + return PR_Notify(mon); +} + +PR_IMPLEMENT(PRStatus) PR_CNotifyAll(void *address) +{ + MonitorCacheEntry **pp; + PRMonitor *mon; + + _PR_LOCK_MCACHE(); + pp = LookupMonitorCacheEntry(address); + mon = pp ? ((*pp)->mon) : NULL; + _PR_UNLOCK_MCACHE(); + + if (mon == NULL) + return PR_FAILURE; + return PR_NotifyAll(mon); +} + +PR_IMPLEMENT(void) +PR_CSetOnMonitorRecycle(void (*callback)(void *address)) +{ + OnMonitorRecycle = callback; +} diff --git a/nsprpub/pr/src/threads/prcthr.c b/nsprpub/pr/src/threads/prcthr.c new file mode 100644 index 00000000000..1e2f469c3a4 --- /dev/null +++ b/nsprpub/pr/src/threads/prcthr.c @@ -0,0 +1,446 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + + +extern PRLock *_pr_sleeplock; /* allocated and initialized in prinit */ +/* +** Routines common to both native and user threads. +** +** +** Clean up a thread object, releasing all of the attached data. Do not +** free the object itself (it may not have been malloc'd) +*/ +void _PR_CleanupThread(PRThread *thread) +{ + /* Free up per-thread-data */ + _PR_DestroyThreadPrivate(thread); + + /* Free any thread dump procs */ + if (thread->dumpArg) { + PR_DELETE(thread->dumpArg); + } + thread->dump = 0; + + PR_DELETE(thread->errorString); + thread->errorStringSize = 0; + thread->errorStringLength = 0; + thread->environment = NULL; +} + +PR_IMPLEMENT(PRStatus) PR_Yield() +{ + static PRBool warning = PR_TRUE; + if (warning) warning = _PR_Obsolete( + "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); + return (PR_Sleep(PR_INTERVAL_NO_WAIT)); +} + +/* +** Make the current thread sleep until "timeout" ticks amount of time +** has expired. If "timeout" is PR_INTERVAL_NO_WAIT then the call is +** equivalent to a yield. Waiting for an infinite amount of time is +** allowed in the expectation that another thread will interrupt(). +** +** A single lock is used for all threads calling sleep. Each caller +** does get its own condition variable since each is expected to have +** a unique 'timeout'. +*/ +PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout) +{ + PRStatus rv = PR_SUCCESS; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (PR_INTERVAL_NO_WAIT == timeout) + { + /* + ** This is a simple yield, nothing more, nothing less. + */ + PRIntn is; + PRThread *me = PR_GetCurrentThread(); + PRUintn pri = me->priority; + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + + if ( _PR_IS_NATIVE_THREAD(me) ) _PR_MD_YIELD(); + else + { + _PR_INTSOFF(is); + _PR_RUNQ_LOCK(cpu); + if (_PR_RUNQREADYMASK(cpu) >> pri) { + me->cpu = cpu; + me->state = _PR_RUNNABLE; + _PR_ADD_RUNQ(me, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: yielding")); + _PR_MD_SWITCH_CONTEXT(me); + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: done")); + + _PR_FAST_INTSON(is); + } + else + { + _PR_RUNQ_UNLOCK(cpu); + _PR_INTSON(is); + } + } + } + else + { + /* + ** This is waiting for some finite period of time. + ** A thread in this state is interruptible (PR_Interrupt()), + ** but the lock and cvar used are local to the implementation + ** and not visible to the caller, therefore not notifiable. + */ + PRCondVar *cv; + PRIntervalTime timein; + + timein = PR_IntervalNow(); + cv = PR_NewCondVar(_pr_sleeplock); + PR_ASSERT(cv != NULL); + PR_Lock(_pr_sleeplock); + 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); + } + return rv; +} + +PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thread) +{ + return thread->id; +} + +PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread) +{ + return (PRThreadPriority) thread->priority; +} + +PR_IMPLEMENT(PRThread *) PR_GetCurrentThread() +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return _PR_MD_CURRENT_THREAD(); +} + +/* +** Set the interrupt flag for a thread. The thread will be unable to +** block in i/o functions when this happens. Also, any PR_Wait's in +** progress will be undone. The interrupt remains in force until +** PR_ClearInterrupt is called. +*/ +PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thread) +{ +#ifdef _PR_GLOBAL_THREADS_ONLY + PRCondVar *victim; + + _PR_THREAD_LOCK(thread); + thread->flags |= _PR_INTERRUPT; + victim = thread->wait.cvar; + _PR_THREAD_UNLOCK(thread); + if ((NULL != victim) && (!(thread->flags & _PR_INTERRUPT_BLOCKED))) { + int haveLock = (victim->lock->owner == _PR_MD_CURRENT_THREAD()); + + if (!haveLock) PR_Lock(victim->lock); + PR_NotifyAllCondVar(victim); + if (!haveLock) PR_Unlock(victim->lock); + } + return PR_SUCCESS; +#else /* ! _PR_GLOBAL_THREADS_ONLY */ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + _PR_THREAD_LOCK(thread); + thread->flags |= _PR_INTERRUPT; + switch (thread->state) { + case _PR_COND_WAIT: + /* + * call is made with thread locked; + * on return lock is released + */ + if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) + _PR_NotifyLockedThread(thread); + break; + case _PR_IO_WAIT: + /* + * Need to hold the thread lock when calling + * _PR_Unblock_IO_Wait(). On return lock is + * released. + */ +#if defined(XP_UNIX) || defined(WINNT) || defined(WIN16) + if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) + _PR_Unblock_IO_Wait(thread); +#else + _PR_THREAD_UNLOCK(thread); +#endif + break; + case _PR_RUNNING: + case _PR_RUNNABLE: + case _PR_LOCK_WAIT: + default: + _PR_THREAD_UNLOCK(thread); + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + return PR_SUCCESS; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/* +** Clear the interrupt flag for self. +*/ +PR_IMPLEMENT(void) PR_ClearInterrupt() +{ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_THREAD_LOCK(me); + me->flags &= ~_PR_INTERRUPT; + _PR_THREAD_UNLOCK(me); + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); +} + +PR_IMPLEMENT(void) PR_BlockInterrupt() +{ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_THREAD_LOCK(me); + _PR_THREAD_BLOCK_INTERRUPT(me); + _PR_THREAD_UNLOCK(me); + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); +} /* PR_BlockInterrupt */ + +PR_IMPLEMENT(void) PR_UnblockInterrupt() +{ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_THREAD_LOCK(me); + _PR_THREAD_UNBLOCK_INTERRUPT(me); + _PR_THREAD_UNLOCK(me); + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); +} /* PR_UnblockInterrupt */ + +/* +** Return the thread stack pointer of the given thread. +*/ +PR_IMPLEMENT(void *) PR_GetSP(PRThread *thread) +{ + return (void *)_PR_MD_GET_SP(thread); +} + +PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thread) +{ + return thread->environment; +} + +PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thread, void *env) +{ + thread->environment = env; +} + + +PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask) +{ +#ifdef HAVE_THREAD_AFFINITY + return _PR_MD_GETTHREADAFFINITYMASK(thread, mask); +#else + +#if defined(XP_MAC) +#pragma unused (thread, mask) +#endif + + return 0; +#endif +} + +PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ) +{ +#ifdef HAVE_THREAD_AFFINITY +#ifndef IRIX + return _PR_MD_SETTHREADAFFINITYMASK(thread, mask); +#else + return 0; +#endif +#else + +#if defined(XP_MAC) +#pragma unused (thread, mask) +#endif + + return 0; +#endif +} + +/* This call is thread unsafe if another thread is calling SetConcurrency() + */ +PR_IMPLEMENT(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask) +{ +#ifdef HAVE_THREAD_AFFINITY + PRCList *qp; + extern PRUint32 _pr_cpu_affinity_mask; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _pr_cpu_affinity_mask = mask; + + qp = _PR_CPUQ().next; + while(qp != &_PR_CPUQ()) { + _PRCPU *cpu; + + cpu = _PR_CPU_PTR(qp); + PR_SetThreadAffinityMask(cpu->thread, mask); + + qp = qp->next; + } +#endif + +#if defined(XP_MAC) +#pragma unused (mask) +#endif + + return 0; +} + +PRUint32 _pr_recycleThreads = 0; +PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count) +{ + _pr_recycleThreads = count; +} + +PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + return _PR_CreateThread(type, start, arg, priority, scope, state, + stackSize, _PR_GCABLE_THREAD); +} + +#ifdef SOLARIS +PR_IMPLEMENT(PRThread*) PR_CreateThreadBound(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRUintn priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + return _PR_CreateThread(type, start, arg, priority, scope, state, + stackSize, _PR_BOUND_THREAD); +} +#endif + + +PR_IMPLEMENT(PRThread*) PR_AttachThreadGCAble( + PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) +{ +#ifdef XP_MAC +#pragma unused (type, priority, stack) +#endif + /* $$$$ not sure how to finese this one */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(void) PR_SetThreadGCAble() +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_Lock(_pr_activeLock); + _PR_MD_CURRENT_THREAD()->flags |= _PR_GCABLE_THREAD; + PR_Unlock(_pr_activeLock); +} + +PR_IMPLEMENT(void) PR_ClearThreadGCAble() +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_Lock(_pr_activeLock); + _PR_MD_CURRENT_THREAD()->flags &= (~_PR_GCABLE_THREAD); + PR_Unlock(_pr_activeLock); +} + +PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thread) +{ +#ifdef XP_MAC +#pragma unused( thread ) +#endif + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (_PR_IS_NATIVE_THREAD(thread)) { + return (thread->flags & _PR_BOUND_THREAD) ? PR_GLOBAL_BOUND_THREAD : + PR_GLOBAL_THREAD; + } else + return PR_LOCAL_THREAD; +} + +PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thread) +{ + return (thread->flags & _PR_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD; +} + +PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thread) +{ + return (NULL == thread->term) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD; +} /* PR_GetThreadState */ diff --git a/nsprpub/pr/src/threads/prdump.c b/nsprpub/pr/src/threads/prdump.c new file mode 100644 index 00000000000..3ea884d2a29 --- /dev/null +++ b/nsprpub/pr/src/threads/prdump.c @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + +/* XXX use unbuffered nspr stdio */ + +PRFileDesc *_pr_dumpOut; + +PRUint32 _PR_DumpPrintf(PRFileDesc *fd, const char *fmt, ...) +{ + char buf[100]; + PRUint32 nb; + va_list ap; + + va_start(ap, fmt); + nb = PR_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + PR_Write(fd, buf, nb); + + return nb; +} + +void _PR_DumpThread(PRFileDesc *fd, PRThread *thread) +{ + +#ifndef _PR_GLOBAL_THREADS_ONLY + _PR_DumpPrintf(fd, "%05d[%08p] pri=%2d flags=0x%02x", + thread->id, thread, thread->priority, thread->flags); + switch (thread->state) { + case _PR_RUNNABLE: + case _PR_RUNNING: + break; + case _PR_LOCK_WAIT: + _PR_DumpPrintf(fd, " lock=%p", thread->wait.lock); + break; + case _PR_COND_WAIT: + _PR_DumpPrintf(fd, " condvar=%p sleep=%lldms", + thread->wait.cvar, thread->sleep); + break; + case _PR_SUSPENDED: + _PR_DumpPrintf(fd, " suspended"); + break; + } + PR_Write(fd, "\n", 1); +#endif + + /* Now call dump routine */ + if (thread->dump) { + thread->dump(fd, thread, thread->dumpArg); + } +} + +static void DumpThreadQueue(PRFileDesc *fd, PRCList *list) +{ +#ifndef _PR_GLOBAL_THREADS_ONLY + PRCList *q; + + q = list->next; + while (q != list) { + PRThread *t = _PR_THREAD_PTR(q); + _PR_DumpThread(fd, t); + q = q->next; + } +#endif +} + +void _PR_DumpThreads(PRFileDesc *fd) +{ + PRThread *t; + PRIntn i; + + _PR_DumpPrintf(fd, "Current Thread:\n"); + t = _PR_MD_CURRENT_THREAD(); + _PR_DumpThread(fd, t); + + _PR_DumpPrintf(fd, "Runnable Threads:\n"); + for (i = 0; i < 32; i++) { + DumpThreadQueue(fd, &_PR_RUNQ(t->cpu)[i]); + } + + _PR_DumpPrintf(fd, "CondVar timed wait Threads:\n"); + DumpThreadQueue(fd, &_PR_SLEEPQ(t->cpu)); + + _PR_DumpPrintf(fd, "CondVar wait Threads:\n"); + DumpThreadQueue(fd, &_PR_PAUSEQ(t->cpu)); + + _PR_DumpPrintf(fd, "Suspended Threads:\n"); + DumpThreadQueue(fd, &_PR_SUSPENDQ(t->cpu)); +} + +PR_IMPLEMENT(void) PR_ShowStatus(void) +{ + PRIntn is; + + if ( _PR_MD_CURRENT_THREAD() + && !_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) _PR_INTSOFF(is); + _pr_dumpOut = _pr_stderr; + _PR_DumpThreads(_pr_dumpOut); + if ( _PR_MD_CURRENT_THREAD() + && !_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) _PR_FAST_INTSON(is); +} + +PR_IMPLEMENT(void) +PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg) +{ + thread->dump = dump; + thread->dumpArg = arg; +} diff --git a/nsprpub/pr/src/threads/prmon.c b/nsprpub/pr/src/threads/prmon.c new file mode 100644 index 00000000000..69d0f655298 --- /dev/null +++ b/nsprpub/pr/src/threads/prmon.c @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +/************************************************************************/ + +/* +** Create a new monitor. +*/ +PR_IMPLEMENT(PRMonitor*) PR_NewMonitor() +{ + PRMonitor *mon; + PRCondVar *cvar; + PRLock *lock; + + mon = PR_NEWZAP(PRMonitor); + if (mon) { + lock = PR_NewLock(); + if (!lock) { + PR_DELETE(mon); + return 0; + } + + cvar = PR_NewCondVar(lock); + if (!cvar) { + PR_DestroyLock(lock); + PR_DELETE(mon); + return 0; + } + mon->cvar = cvar; + mon->name = NULL; + } + return mon; +} + +PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) +{ + PRMonitor* mon = PR_NewMonitor(); + if (mon) + mon->name = name; + return mon; +} + +/* +** Destroy a monitor. There must be no thread waiting on the monitor's +** condition variable. The caller is responsible for guaranteeing that the +** monitor is no longer in use. +*/ +PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) +{ + PR_DestroyLock(mon->cvar->lock); + PR_DestroyCondVar(mon->cvar); + PR_DELETE(mon); +} + +/* +** Enter the lock associated with the monitor. +*/ +PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) +{ + if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) { + mon->entryCount++; + } else { + PR_Lock(mon->cvar->lock); + mon->entryCount = 1; + } +} + +/* +** Test and then enter the lock associated with the monitor if it's not +** already entered by some other thread. Return PR_FALSE if some other +** thread owned the lock at the time of the call. +*/ +PR_IMPLEMENT(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon) +{ + if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) { + mon->entryCount++; + return PR_TRUE; + } else { + if (PR_TestAndLock(mon->cvar->lock)) { + mon->entryCount = 1; + return PR_TRUE; + } + } + return PR_FALSE; +} + +/* +** Exit the lock associated with the monitor once. +*/ +PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) +{ + if (mon->cvar->lock->owner != _PR_MD_CURRENT_THREAD()) { + return PR_FAILURE; + } + if (--mon->entryCount == 0) { + return PR_Unlock(mon->cvar->lock); + } + return PR_SUCCESS; +} + +/* +** Return the number of times that the current thread has entered the +** lock. Returns zero if the current thread has not entered the lock. +*/ +PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) +{ + return (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) ? + mon->entryCount : 0; +} + +/* +** Wait for a notify on the condition variable. Sleep for "ticks" amount +** of time (if "tick" is 0 then the sleep is indefinite). While +** the thread is waiting it exits the monitors lock (as if it called +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When +** the wait has finished the thread regains control of the monitors lock +** with the same entry count as before the wait began. +** +** The thread waiting on the monitor will be resumed when the monitor is +** notified (assuming the thread is the next in line to receive the +** notify) or when the "ticks" elapses. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +** This routine can return PR_PENDING_INTERRUPT if the waiting thread +** has been interrupted. +*/ +PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks) +{ + PRUintn entryCount; + PRStatus status; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (mon->cvar->lock->owner != me) return PR_FAILURE; + + entryCount = mon->entryCount; + mon->entryCount = 0; + + status = _PR_WaitCondVar(me, mon->cvar, mon->cvar->lock, ticks); + + mon->entryCount = entryCount; + + return status; +} + +/* +** Notify the highest priority thread waiting on the condition +** variable. If a thread is waiting on the condition variable (using +** PR_Wait) then it is awakened and begins waiting on the monitor's lock. +*/ +PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + if (mon->cvar->lock->owner != me) return PR_FAILURE; + PR_NotifyCondVar(mon->cvar); + return PR_SUCCESS; +} + +/* +** Notify all of the threads waiting on the condition variable. All of +** threads are notified in turn. The highest priority thread will +** probably acquire the monitor first when the monitor is exited. +*/ +PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + if (mon->cvar->lock->owner != me) return PR_FAILURE; + PR_NotifyAllCondVar(mon->cvar); + return PR_SUCCESS; +} + +/************************************************************************/ + +PRUint32 _PR_MonitorToString(PRMonitor *mon, char *buf, PRUint32 buflen) +{ + PRUint32 nb; + + if (mon->cvar->lock->owner) { + nb = PR_snprintf(buf, buflen, "[%p] owner=%d[%p] count=%ld", + mon, mon->cvar->lock->owner->id, + mon->cvar->lock->owner, mon->entryCount); + } else { + nb = PR_snprintf(buf, buflen, "[%p]", mon); + } + return nb; +} diff --git a/nsprpub/pr/src/threads/prrwlock.c b/nsprpub/pr/src/threads/prrwlock.c new file mode 100644 index 00000000000..35e0e3e7237 --- /dev/null +++ b/nsprpub/pr/src/threads/prrwlock.c @@ -0,0 +1,512 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" + +#include + +#if defined(HPUX) && defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + +#include +#define HAVE_UNIX98_RWLOCK +#define RWLOCK_T pthread_rwlock_t +#define RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL) +#define RWLOCK_DESTROY(lock) pthread_rwlock_destroy(lock) +#define RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock) +#define RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock) +#define RWLOCK_UNLOCK(lock) pthread_rwlock_unlock(lock) + +#elif defined(SOLARIS) && (defined(_PR_PTHREADS) \ + || defined(_PR_GLOBAL_THREADS_ONLY)) + +#include +#define HAVE_UI_RWLOCK +#define RWLOCK_T rwlock_t +#define RWLOCK_INIT(lock) rwlock_init(lock, USYNC_THREAD, NULL) +#define RWLOCK_DESTROY(lock) rwlock_destroy(lock) +#define RWLOCK_RDLOCK(lock) rw_rdlock(lock) +#define RWLOCK_WRLOCK(lock) rw_wrlock(lock) +#define RWLOCK_UNLOCK(lock) rw_unlock(lock) + +#endif + +/* + * Reader-writer lock + */ +struct PRRWLock { + char *rw_name; /* lock name */ + PRUint32 rw_rank; /* rank of the lock */ + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + RWLOCK_T rw_lock; +#else + PRLock *rw_lock; + PRInt32 rw_lock_cnt; /* == 0, if unlocked */ + /* == -1, if write-locked */ + /* > 0 , # of read locks */ + PRUint32 rw_reader_cnt; /* number of waiting readers */ + PRUint32 rw_writer_cnt; /* number of waiting writers */ + PRCondVar *rw_reader_waitq; /* cvar for readers */ + PRCondVar *rw_writer_waitq; /* cvar for writers */ +#ifdef DEBUG + PRThread *rw_owner; /* lock owner for write-lock */ +#endif +#endif +}; + +#ifdef DEBUG +#define _PR_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using + rank-order for locks + */ +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + +static PRUintn pr_thread_rwlock_key; /* TPD key for lock stack */ +static PRUintn pr_thread_rwlock_alloc_failed; + +#define _PR_RWLOCK_RANK_ORDER_LIMIT 10 + +typedef struct thread_rwlock_stack { + PRInt32 trs_index; /* top of stack */ + PRRWLock *trs_stack[_PR_RWLOCK_RANK_ORDER_LIMIT]; /* stack of lock + pointers */ + +} thread_rwlock_stack; + +static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock); +static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void); +static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock); +static void _PR_RELEASE_LOCK_STACK(void *lock_stack); + +#endif + +/* + * Reader/Writer Locks + */ + +/* + * PR_NewRWLock + * Create a reader-writer lock, with the given lock rank and lock name + * + */ + +PR_IMPLEMENT(PRRWLock *) +PR_NewRWLock(PRUint32 lock_rank, const char *lock_name) +{ + PRRWLock *rwlock; +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + int err; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + rwlock = PR_NEWZAP(PRRWLock); + if (rwlock == NULL) + return NULL; + + rwlock->rw_rank = lock_rank; + if (lock_name != NULL) { + rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1); + if (rwlock->rw_name == NULL) { + PR_DELETE(rwlock); + return(NULL); + } + strcpy(rwlock->rw_name, lock_name); + } else { + rwlock->rw_name = NULL; + } + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + err = RWLOCK_INIT(&rwlock->rw_lock); + if (err != 0) { + PR_SetError(PR_UNKNOWN_ERROR, err); + PR_Free(rwlock->rw_name); + PR_DELETE(rwlock); + return NULL; + } + return rwlock; +#else + rwlock->rw_lock = PR_NewLock(); + if (rwlock->rw_lock == NULL) { + goto failed; + } + rwlock->rw_reader_waitq = PR_NewCondVar(rwlock->rw_lock); + if (rwlock->rw_reader_waitq == NULL) { + goto failed; + } + rwlock->rw_writer_waitq = PR_NewCondVar(rwlock->rw_lock); + if (rwlock->rw_writer_waitq == NULL) { + goto failed; + } + rwlock->rw_reader_cnt = 0; + rwlock->rw_writer_cnt = 0; + rwlock->rw_lock_cnt = 0; + return rwlock; + +failed: + if (rwlock->rw_reader_waitq != NULL) { + PR_DestroyCondVar(rwlock->rw_reader_waitq); + } + if (rwlock->rw_lock != NULL) { + PR_DestroyLock(rwlock->rw_lock); + } + PR_Free(rwlock->rw_name); + PR_DELETE(rwlock); + return NULL; +#endif +} + +/* +** Destroy the given RWLock "lock". +*/ +PR_IMPLEMENT(void) +PR_DestroyRWLock(PRRWLock *rwlock) +{ +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + int err; + err = RWLOCK_DESTROY(&rwlock->rw_lock); + PR_ASSERT(err == 0); +#else + PR_ASSERT(rwlock->rw_reader_cnt == 0); + PR_DestroyCondVar(rwlock->rw_reader_waitq); + PR_DestroyCondVar(rwlock->rw_writer_waitq); + PR_DestroyLock(rwlock->rw_lock); +#endif + if (rwlock->rw_name != NULL) + PR_Free(rwlock->rw_name); + PR_DELETE(rwlock); +} + +/* +** Read-lock the RWLock. +*/ +PR_IMPLEMENT(void) +PR_RWLock_Rlock(PRRWLock *rwlock) +{ +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) +int err; +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * assert that rank ordering is not violated; the rank of 'rwlock' should + * be equal to or greater than the highest rank of all the locks held by + * the thread. + */ + PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || + (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK())); +#endif + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + err = RWLOCK_RDLOCK(&rwlock->rw_lock); + PR_ASSERT(err == 0); +#else + PR_Lock(rwlock->rw_lock); + /* + * wait if write-locked or if a writer is waiting; preference for writers + */ + while ((rwlock->rw_lock_cnt < 0) || + (rwlock->rw_writer_cnt > 0)) { + rwlock->rw_reader_cnt++; + PR_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT); + rwlock->rw_reader_cnt--; + } + /* + * Increment read-lock count + */ + rwlock->rw_lock_cnt++; + + PR_Unlock(rwlock->rw_lock); +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * update thread's lock rank + */ + _PR_SET_THREAD_RWLOCK_RANK(rwlock); +#endif +} + +/* +** Write-lock the RWLock. +*/ +PR_IMPLEMENT(void) +PR_RWLock_Wlock(PRRWLock *rwlock) +{ +#if defined(DEBUG) +PRThread *me = PR_GetCurrentThread(); +#endif +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) +int err; +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * assert that rank ordering is not violated; the rank of 'rwlock' should + * be equal to or greater than the highest rank of all the locks held by + * the thread. + */ + PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || + (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK())); +#endif + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + err = RWLOCK_WRLOCK(&rwlock->rw_lock); + PR_ASSERT(err == 0); +#else + PR_Lock(rwlock->rw_lock); + /* + * wait if read locked + */ + while (rwlock->rw_lock_cnt != 0) { + rwlock->rw_writer_cnt++; + PR_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT); + rwlock->rw_writer_cnt--; + } + /* + * apply write lock + */ + rwlock->rw_lock_cnt--; + PR_ASSERT(rwlock->rw_lock_cnt == -1); +#ifdef DEBUG + PR_ASSERT(me != NULL); + rwlock->rw_owner = me; +#endif + PR_Unlock(rwlock->rw_lock); +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * update thread's lock rank + */ + _PR_SET_THREAD_RWLOCK_RANK(rwlock); +#endif +} + +/* +** Unlock the RW lock. +*/ +PR_IMPLEMENT(void) +PR_RWLock_Unlock(PRRWLock *rwlock) +{ +#if defined(DEBUG) +PRThread *me = PR_GetCurrentThread(); +#endif +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) +int err; +#endif + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + err = RWLOCK_UNLOCK(&rwlock->rw_lock); + PR_ASSERT(err == 0); +#else + PR_Lock(rwlock->rw_lock); + /* + * lock must be read or write-locked + */ + PR_ASSERT(rwlock->rw_lock_cnt != 0); + if (rwlock->rw_lock_cnt > 0) { + + /* + * decrement read-lock count + */ + rwlock->rw_lock_cnt--; + if (rwlock->rw_lock_cnt == 0) { + /* + * lock is not read-locked anymore; wakeup a waiting writer + */ + if (rwlock->rw_writer_cnt > 0) + PR_NotifyCondVar(rwlock->rw_writer_waitq); + } + } else { + PR_ASSERT(rwlock->rw_lock_cnt == -1); + + rwlock->rw_lock_cnt = 0; +#ifdef DEBUG + PR_ASSERT(rwlock->rw_owner == me); + rwlock->rw_owner = NULL; +#endif + /* + * wakeup a writer, if present; preference for writers + */ + if (rwlock->rw_writer_cnt > 0) + PR_NotifyCondVar(rwlock->rw_writer_waitq); + /* + * else, wakeup all readers, if any + */ + else if (rwlock->rw_reader_cnt > 0) + PR_NotifyAllCondVar(rwlock->rw_reader_waitq); + } + PR_Unlock(rwlock->rw_lock); +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * update thread's lock rank + */ + _PR_UNSET_THREAD_RWLOCK_RANK(rwlock); +#endif + return; +} + +#ifndef _PR_RWLOCK_RANK_ORDER_DEBUG + +void _PR_InitRWLocks(void) { } + +#else + +void _PR_InitRWLocks(void) +{ + /* + * allocated thread-private-data index for rwlock list + */ + if (PR_NewThreadPrivateIndex(&pr_thread_rwlock_key, + _PR_RELEASE_LOCK_STACK) == PR_FAILURE) { + pr_thread_rwlock_alloc_failed = 1; + return; + } +} + +/* + * _PR_SET_THREAD_RWLOCK_RANK + * Set a thread's lock rank, which is the highest of the ranks of all + * the locks held by the thread. Pointers to the locks are added to a + * per-thread list, which is anchored off a thread-private data key. + */ + +static void +_PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock) +{ +thread_rwlock_stack *lock_stack; +PRStatus rv; + + /* + * allocate a lock stack + */ + if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) { + lock_stack = (thread_rwlock_stack *) + PR_CALLOC(1 * sizeof(thread_rwlock_stack)); + if (lock_stack) { + rv = PR_SetThreadPrivate(pr_thread_rwlock_key, lock_stack); + if (rv == PR_FAILURE) { + PR_DELETE(lock_stack); + pr_thread_rwlock_alloc_failed = 1; + return; + } + } else { + pr_thread_rwlock_alloc_failed = 1; + return; + } + } + /* + * add rwlock to lock stack, if limit is not exceeded + */ + if (lock_stack) { + if (lock_stack->trs_index < _PR_RWLOCK_RANK_ORDER_LIMIT) + lock_stack->trs_stack[lock_stack->trs_index++] = rwlock; + } +} + +static void +_PR_RELEASE_LOCK_STACK(void *lock_stack) +{ + PR_ASSERT(lock_stack); + PR_DELETE(lock_stack); +} + +/* + * _PR_GET_THREAD_RWLOCK_RANK + * + * return thread's lock rank. If thread-private-data for the lock + * stack is not allocated, return PR_RWLOCK_RANK_NONE. + */ + +static PRUint32 +_PR_GET_THREAD_RWLOCK_RANK(void) +{ + thread_rwlock_stack *lock_stack; + + if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) + return (PR_RWLOCK_RANK_NONE); + else + return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank); +} + +/* + * _PR_UNSET_THREAD_RWLOCK_RANK + * + * remove the rwlock from the lock stack. Since locks may not be + * unlocked in a FIFO order, the entire lock stack is searched. + */ + +static void +_PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock) +{ + thread_rwlock_stack *lock_stack; + int new_index = 0, index, done = 0; + + lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key); + + PR_ASSERT(lock_stack != NULL); + + index = lock_stack->trs_index - 1; + while (index-- >= 0) { + if ((lock_stack->trs_stack[index] == rwlock) && !done) { + /* + * reset the slot for rwlock + */ + lock_stack->trs_stack[index] = NULL; + done = 1; + } + /* + * search for the lowest-numbered empty slot, above which there are + * no non-empty slots + */ + if ((lock_stack->trs_stack[index] != NULL) && !new_index) + new_index = index + 1; + if (done && new_index) + break; + } + /* + * set top of stack to highest numbered empty slot + */ + lock_stack->trs_index = new_index; + +} + +#endif /* _PR_RWLOCK_RANK_ORDER_DEBUG */ diff --git a/nsprpub/pr/src/threads/prsem.c b/nsprpub/pr/src/threads/prsem.c new file mode 100644 index 00000000000..692bc0e99b4 --- /dev/null +++ b/nsprpub/pr/src/threads/prsem.c @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "primpl.h" +#if defined(XP_MAC) +#include "prsem.h" +#else +#include "obsolete/prsem.h" +#endif + +/************************************************************************/ + +/* +** Create a new semaphore. +*/ +PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value) +{ + PRSemaphore *sem; + PRCondVar *cvar; + PRLock *lock; + + sem = PR_NEWZAP(PRSemaphore); + if (sem) { +#ifdef HAVE_CVAR_BUILT_ON_SEM + _PR_MD_NEW_SEM(&sem->md, value); +#else + lock = PR_NewLock(); + if (!lock) { + PR_DELETE(sem); + return NULL; + } + + cvar = PR_NewCondVar(lock); + if (!cvar) { + PR_DestroyLock(lock); + PR_DELETE(sem); + return NULL; + } + sem->cvar = cvar; + sem->count = value; +#endif + } + return sem; +} + +/* +** Destroy a semaphore. There must be no thread waiting on the semaphore. +** The caller is responsible for guaranteeing that the semaphore is +** no longer in use. +*/ +PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *sem) +{ +#ifdef HAVE_CVAR_BUILT_ON_SEM + _PR_MD_DESTROY_SEM(&sem->md); +#else + PR_ASSERT(sem->waiters == 0); + + PR_DestroyLock(sem->cvar->lock); + PR_DestroyCondVar(sem->cvar); +#endif + PR_DELETE(sem); +} + +/* +** Wait on a Semaphore. +** +** This routine allows a calling thread to wait or proceed depending upon the +** state of the semahore sem. The thread can proceed only if the counter value +** of the semaphore sem is currently greater than 0. If the value of semaphore +** sem is positive, it is decremented by one and the routine returns immediately +** allowing the calling thread to continue. If the value of semaphore sem is 0, +** the calling thread blocks awaiting the semaphore to be released by another +** thread. +** +** This routine can return PR_PENDING_INTERRUPT if the waiting thread +** has been interrupted. +*/ +PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *sem) +{ + PRStatus status = PR_SUCCESS; + +#ifdef HAVE_CVAR_BUILT_ON_SEM + return _PR_MD_WAIT_SEM(&sem->md); +#else + PR_Lock(sem->cvar->lock); + while (sem->count == 0) { + sem->waiters++; + status = PR_WaitCondVar(sem->cvar, PR_INTERVAL_NO_TIMEOUT); + sem->waiters--; + if (status != PR_SUCCESS) + break; + } + if (status == PR_SUCCESS) + sem->count--; + PR_Unlock(sem->cvar->lock); +#endif + + return (status); +} + +/* +** This routine increments the counter value of the semaphore. If other threads +** are blocked for the semaphore, then the scheduler will determine which ONE +** thread will be unblocked. +*/ +PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *sem) +{ +#ifdef HAVE_CVAR_BUILT_ON_SEM + _PR_MD_POST_SEM(&sem->md); +#else + PR_Lock(sem->cvar->lock); + if (sem->waiters) + PR_NotifyCondVar(sem->cvar); + sem->count++; + PR_Unlock(sem->cvar->lock); +#endif +} + +#if DEBUG +/* +** Returns the value of the semaphore referenced by sem without affecting +** the state of the semaphore. The value represents the semaphore vaule +** at the time of the call, but may not be the actual value when the +** caller inspects it. (FOR DEBUGGING ONLY) +*/ +PR_IMPLEMENT(PRUintn) PR_GetValueSem(PRSemaphore *sem) +{ + PRUintn rv; + +#ifdef HAVE_CVAR_BUILT_ON_SEM + rv = _PR_MD_GET_VALUE_SEM(&sem->md); +#else + PR_Lock(sem->cvar->lock); + rv = sem->count; + PR_Unlock(sem->cvar->lock); +#endif + + return rv; +} +#endif diff --git a/nsprpub/pr/src/threads/prtpd.c b/nsprpub/pr/src/threads/prtpd.c new file mode 100644 index 00000000000..168c6601887 --- /dev/null +++ b/nsprpub/pr/src/threads/prtpd.c @@ -0,0 +1,280 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Thread Private Data +** +** There is an aribitrary limit on the number of keys that will be allocated +** by the runtime. It's largish, so it is intended to be a sanity check, not +** an impediment. +** +** There is a counter, initialized to zero and incremented every time a +** client asks for a new key, that holds the high water mark for keys. All +** threads logically have the same high water mark and are permitted to +** ask for TPD up to that key value. +** +** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is +** called. The size of the vector will be some value greater than or equal +** to the current high water mark. Each thread has its own TPD length and +** vector. +** +** Threads that get private data for keys they have not set (or perhaps +** don't even exist for that thread) get a NULL return. If the key is +** beyond the high water mark, an error will be returned. +*/ + +/* +** As of this time, BeOS has its own TPD implementation. Integrating +** this standard one is a TODO for anyone with a bit of spare time on +** their hand. For now, we just #ifdef out this whole file and use +** the routines in pr/src/btthreads/ +*/ + +#ifndef XP_BEOS + +#include "primpl.h" + +#include + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + +#define _PR_TPD_LIMIT 128 /* arbitary limit on the TPD slots */ +static PRInt32 _pr_tpd_length = 0; /* current length of destructor vector */ +static PRInt32 _pr_tpd_highwater = 0; /* next TPD key to be assigned */ +static PRThreadPrivateDTOR *_pr_tpd_destructors = NULL; + /* the destructors are associated with + the keys, therefore asserting that + the TPD key depicts the data's 'type' */ + +/* +** Initialize the thread private data manipulation +*/ +void _PR_InitTPD(void) +{ + _pr_tpd_destructors = (PRThreadPrivateDTOR*) + PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*)); + PR_ASSERT(NULL != _pr_tpd_destructors); + _pr_tpd_length = _PR_TPD_LIMIT; +} + +/* +** Clean up the thread private data manipulation +*/ +void _PR_CleanupTPD(void) +{ +} /* _PR_CleanupTPD */ + +/* +** This routine returns a new index for per-thread-private data table. +** The index is visible to all threads within a process. This index can +** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines +** to save and retrieve data associated with the index for a thread. +** +** The index independently maintains specific values for each binding thread. +** A thread can only get access to its own thread-specific-data. +** +** Upon a new index return the value associated with the index for all threads +** 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 set or destroyed +** +** Returns PR_FAILURE if the total number of indices will exceed the maximun +** allowed. +*/ + +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); + + index = PR_AtomicIncrement(&_pr_tpd_highwater) - 1; /* allocate index */ + if (_PR_TPD_LIMIT <= index) + { + PR_SetError(PR_TPD_RANGE_ERROR, 0); + rv = PR_FAILURE; /* that's just wrong */ + } + else + { + _pr_tpd_destructors[index] = dtor; /* record destructor @index */ + *newIndex = (PRUintn)index; /* copy into client's location */ + rv = PR_SUCCESS; /* that's okay */ + } + + return rv; +} + +/* +** Define some 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, +** the destructor function is invoked. +** +** This can return PR_FAILURE if index is invalid (ie., beyond the current +** high water mark) or memory is insufficient to allocate an exanded vector. +*/ + +PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) +{ + PRThread *self = PR_GetCurrentThread(); + + /* + ** The index being set might not have a sufficient vector in this + ** thread. But if the index has been allocated, it's okay to go + ** ahead and extend this one now. + */ + if ((index >= _PR_TPD_LIMIT) || (index >= _pr_tpd_highwater)) + { + PR_SetError(PR_TPD_RANGE_ERROR, 0); + return PR_FAILURE; + } + + PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength)) + || ((NULL != self->privateData) && (0 != self->tpdLength))); + + if ((NULL == self->privateData) || (self->tpdLength <= index)) + { + void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*)); + if (NULL == extension) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_FAILURE; + } + if (self->privateData) { + (void)memcpy( + extension, self->privateData, + self->tpdLength * sizeof(void*)); + PR_DELETE(self->privateData); + } + self->tpdLength = _pr_tpd_length; + self->privateData = (void**)extension; + } + /* + ** There wasn't much chance of having to call the destructor + ** unless the slot already existed. + */ + else if (self->privateData[index] && _pr_tpd_destructors[index]) + { + void *data = self->privateData[index]; + self->privateData[index] = NULL; + (*_pr_tpd_destructors[index])(data); + } + + PR_ASSERT(index < self->tpdLength); + self->privateData[index] = priv; + + return PR_SUCCESS; +} + +/* +** Recover the per-thread-private data for the current thread. "index" is +** the index into the per-thread private data table. +** +** The returned value may be NULL which is indistinguishable from an error +** condition. +** +*/ + +PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index) +{ + PRThread *self = PR_GetCurrentThread(); + void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ? + NULL : self->privateData[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) +{ +#define _PR_TPD_DESTRUCTOR_ITERATIONS 4 + + if (NULL != self->privateData) /* we have some */ + { + PRBool clean; + PRUint32 index; + PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS; + PR_ASSERT(0 != self->tpdLength); + do + { + clean = PR_TRUE; + 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 */ + /* + ** We give up after a fixed number of passes. Any non-NULL + ** thread-private data value with a registered destructor + ** function is not destroyed. + */ + memset(self->privateData, 0, self->tpdLength * sizeof(void*)); + } +} /* _PR_DestroyThreadPrivate */ + +#endif /* !XP_BEOS */ diff --git a/nsprpub/pr/tests/.cvsignore b/nsprpub/pr/tests/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/tests/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/tests/Makefile.in b/nsprpub/pr/tests/Makefile.in new file mode 100644 index 00000000000..ca052f3a30c --- /dev/null +++ b/nsprpub/pr/tests/Makefile.in @@ -0,0 +1,573 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = dll + +CSRCS = \ + accept.c \ + acceptread.c \ + acceptreademu.c \ + addrstr.c \ + affinity.c \ + alarm.c \ + anonfm.c \ + append.c \ + atomic.c \ + attach.c \ + bigfile.c \ + bigfile2.c \ + bigfile3.c \ + cleanup.c \ + cltsrv.c \ + concur.c \ + cvar.c \ + cvar2.c \ + dceemu.c \ + dlltest.c \ + dtoa.c \ + env.c \ + errcodes.c \ + errset.c \ + exit.c \ + fdcach.c \ + fileio.c \ + foreign.c \ + forktest.c \ + formattm.c \ + fsync.c \ + getai.c \ + gethost.c \ + getproto.c \ + i2l.c \ + initclk.c \ + inrval.c \ + instrumt.c \ + intrio.c \ + intrupt.c \ + io_timeout.c \ + ioconthr.c \ + ipv6.c \ + join.c \ + joinkk.c \ + joinku.c \ + joinuk.c \ + joinuu.c \ + layer.c \ + lazyinit.c \ + libfilename.c \ + lltest.c \ + lock.c \ + lockfile.c \ + logger.c \ + makedir.c \ + mbcs.c \ + multiacc.c \ + multiwait.c \ + many_cv.c \ + nameshm1.c \ + nbconn.c \ + nblayer.c \ + nonblock.c \ + ntioto.c \ + ntoh.c \ + obsints.c \ + op_2long.c \ + op_excl.c \ + op_filnf.c \ + op_filok.c \ + op_noacc.c \ + op_nofil.c \ + openfile.c \ + parent.c \ + peek.c \ + perf.c \ + pipeping.c \ + pipeping2.c \ + pipepong.c \ + pipepong2.c \ + pipeself.c \ + poll_er.c \ + poll_nm.c \ + poll_to.c \ + pollable.c \ + prftest.c \ + prftest1.c \ + prftest2.c \ + primblok.c \ + priotest.c \ + provider.c \ + prpoll.c \ + prpollml.c \ + ranfile.c \ + randseed.c \ + rmdir.c \ + rwlocktest.c \ + sel_spd.c \ + selct_er.c \ + selct_nm.c \ + selct_to.c \ + select2.c \ + selintr.c \ + sem.c \ + sema.c \ + semaerr.c \ + semaerr1.c \ + semaping.c \ + semapong.c \ + sendzlf.c \ + server_test.c \ + servr_kk.c \ + servr_ku.c \ + servr_uk.c \ + servr_uu.c \ + short_thread.c \ + sigpipe.c \ + socket.c \ + sockopt.c \ + sockping.c \ + sockpong.c \ + sprintf.c \ + sproc_ch.c \ + sproc_p.c \ + stack.c \ + stdio.c \ + str2addr.c \ + strod.c \ + suspend.c \ + switch.c \ + system.c \ + testbit.c \ + testfile.c \ + thrpool_server.c \ + thrpool_client.c \ + threads.c \ + thruput.c \ + timemac.c \ + timetest.c \ + tmoacc.c \ + tmocon.c \ + tpd.c \ + vercheck.c \ + version.c \ + udpsrv.c \ + writev.c \ + xnotify.c \ + y2k.c \ + y2ktmo.c \ + zerolen.c \ + $(NULL) + +ifeq ($(OS_TARGET),OS2) +CSRCS += \ + sleep.c \ + stat.c \ + yield.c \ + $(NULL) +endif + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +ifeq ($(OS_ARCH), WINNT) +ifdef NS_USE_GCC + EXTRA_LIBS += -lwsock32 +else + EXTRA_LIBS += wsock32.lib + LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO + ifdef PROFILE + LDOPTS += -PROFILE -MAP + endif # profile +endif # NS_USE_GCC +endif + +ifeq ($(OS_ARCH),OS2) +ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO +else + EXTRA_LIBS = $(OS_LIBS) + LDOPTS = -Zomf -Zlinker /PM:VIO -Zlinker /ST:0x64000 +endif +endif + +ifneq ($(OS_ARCH), WINNT) +# Use an absolute pathname as the runtime library path (for the -R +# or -rpath linker option or the LD_RUN_PATH environment variable). +ifeq (,$(patsubst /%,,$(DIST))) +# $(DIST) is already an absolute pathname. +ABSOLUTE_LIB_DIR = $(dist_libdir) +else +# $(DIST) is a relative pathname: prepend the current directory. +PWD = $(shell pwd) +ABSOLUTE_LIB_DIR = $(PWD)/$(dist_libdir) +endif +endif + +ifeq ($(OS_ARCH), IRIX) + ifeq ($(USE_CPLUS), 1) + CC = CC + endif + LDOPTS += -rpath $(ABSOLUTE_LIB_DIR) + ifdef NS_USE_GCC + LDOPTS += -Wl,-rdata_shared + else + LDOPTS += -rdata_shared + endif +# For 6.x machines, include this flag + ifeq ($(basename $(OS_RELEASE)),6) + ifndef NS_USE_GCC + 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 +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 (,$(filter-out V2.0 V3.2,$(OS_RELEASE))) + LIBNSPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + LIBPLC = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).a + EXTRA_LIBS = -lc_r + else + LDOPTS += -rpath $(ABSOLUTE_LIB_DIR) + endif +endif + +ifeq ($(OS_ARCH), HP-UX) + LDOPTS += -z -Wl,+s,+b,$(ABSOLUTE_LIB_DIR) + ifeq ($(USE_64),1) + LDOPTS += +DD64 + endif + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = $(LIBPTHREAD) + endif +endif + +# AIX +ifeq ($(OS_ARCH),AIX) + LDOPTS += -blibpath:$(ABSOLUTE_LIB_DIR):/usr/lib:/lib + ifneq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) + 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 $(ABSOLUTE_LIB_DIR) + else + ifeq ($(USE_CPLUS), 1) + CC = CC + endif + LDOPTS += -R $(ABSOLUTE_LIB_DIR) + endif + endif + + ifneq ($(LOCAL_THREADS_ONLY),1) + ifdef USE_PTHREADS + EXTRA_LIBS = -lpthread + else + EXTRA_LIBS = -lthread + endif + endif # LOCAL_THREADS_ONLY +endif # SunOS + +ifeq ($(OS_ARCH), NEC) + 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 = $(ABSOLUTE_LIB_DIR) +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 +# 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 = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH), NEXTSTEP) +# balazs.pataki@sztaki.hu: linkage is done in a different pass in the `tests' +# modeul, so we have to pass the `-posix' flag by "hand" to `ld' +LDOPTS += -posix +endif + +ifeq ($(OS_ARCH), NEWS-OS) +# 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 = $(ABSOLUTE_LIB_DIR) + LIBNSPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + LIBPLC = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).a + EXTRA_LIBS = -lsocket -lnsl -lgen -lresolv +endif + +ifeq (,$(filter-out Linux GNU GNU_%,$(OS_ARCH))) + LDOPTS += -Xlinker -rpath $(ABSOLUTE_LIB_DIR) + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif +endif + +ifeq ($(OS_ARCH), SCOOS) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# 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 = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH),SINIX) +EXTRA_LIBS = -lsocket -lnsl -lresolv -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 = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH),OpenUNIX) +export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) +ifeq ($(USE_PTHREADS),1) +LDOPTS += -pthread +endif +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH),FreeBSD) +ifeq ($(USE_PTHREADS),1) +LDOPTS += -pthread +endif +LDOPTS += -Xlinker -R $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH),OpenBSD) +ifeq ($(USE_PTHREADS),1) +LDOPTS += -pthread +endif +endif + +ifeq ($(OS_ARCH),BSD_OS) +ifneq ($(OS_RELEASE),1.1) +EXTRA_LIBS = -ldl +endif +endif + +ifeq ($(USE_PTHREADS),1) +LIBPTHREAD = -lpthread +ifeq ($(OS_ARCH),AIX) +LIBPTHREAD = -lpthreads +endif +ifeq (,$(filter-out FreeBSD OpenBSD BSD_OS QNX Darwin OpenUNIX,$(OS_ARCH))) +LIBPTHREAD = +endif +ifeq ($(OS_ARCH)$(basename $(OS_RELEASE)),HP-UXB.10) +LIBPTHREAD = -ldce +endif +endif + + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifeq ($(OS_RELEASE),4.1) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + link $(LDOPTS) $(EXTRA_LDOPTS) $< $(LIBPLC) $(LIBNSPR) $(EXTRA_LIBS) -out:$@ +ifdef MT + @if test -f $@.manifest; then \ + $(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ + rm -f $@.manifest; \ + fi +endif +else +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(LD) $(EXEFLAGS) $(LDOPTS) $< $(LIBPLC) $(LIBNSPR) $(OS_LIBS) $(EXTRA_LIBS) +else + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(EXTRA_LIBS) -o $@ +endif # OS/2 +endif # WINNT +endif # AIX_PRE_4_2 + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + +# The following tests call BSD socket functions, so they need to link +# with -lsocket on some platforms. +ifeq ($(OS_ARCH),SunOS) +ifneq ($(OS_RELEASE),4.1.3_U1) +ifeq ($(USE_IPV6),1) +$(OBJDIR)/gethost: $(OBJDIR)/gethost.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) -lsocket $(EXTRA_LIBS) -o $@ +endif +$(OBJDIR)/prpoll: $(OBJDIR)/prpoll.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) -lsocket $(EXTRA_LIBS) -o $@ +endif +endif + +ifeq ($(USE_PTHREADS), 1) +$(OBJDIR)/attach: $(OBJDIR)/attach.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +$(OBJDIR)/foreign: $(OBJDIR)/foreign.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +$(OBJDIR)/provider: $(OBJDIR)/provider.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +$(OBJDIR)/socket: $(OBJDIR)/socket.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +$(OBJDIR)/testfile: $(OBJDIR)/testfile.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +endif + +# +# Run the test programs with no arguments +# +# Test output goes to the file pointed to by the environment variable +# NSPR_TEST_LOGFILE, if set, else to /dev/null +# +ECHO = echo +PROGRAMS = $(notdir $(PROGS)) +ifdef NSPR_TEST_LOGFILE +LOGFILE = $(NSPR_TEST_LOGFILE) +else +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +LOGFILE = nul +else +LOGFILE = /dev/null +endif +endif + +ifeq ($(OS_TARGET),Linux) +ECHO = /bin/echo +endif + +ALWAYS: + +runtests:: $(PROGS) ALWAYS + @$(ECHO) "\nNSPR Test Results - $(OBJDIR)\n" + @$(ECHO) "BEGIN\t\t\t`date`" + @$(ECHO) "NSPR_TEST_LOGFILE\t$(LOGFILE)\n" + @$(ECHO) "Test\t\t\tResult\n" + @cd $(OBJDIR); for i in $(PROGRAMS); do \ + $(ECHO) "$$i\c"; \ + ./$$i >> $(LOGFILE) 2>&1 ; \ + if [ 0 = $$? ] ; then \ + $(ECHO) "\t\t\tPassed"; \ + else \ + $(ECHO) "\t\t\tFAILED"; \ + fi; \ + done + @$(ECHO) "\nEND\t\t`date`\n" diff --git a/nsprpub/pr/tests/README.TXT b/nsprpub/pr/tests/README.TXT new file mode 100644 index 00000000000..685498a9773 --- /dev/null +++ b/nsprpub/pr/tests/README.TXT @@ -0,0 +1,407 @@ +File: pr/tests/readme + +This document describes the test cases in the NSPR directory +pr/tests. + +===================================================================== +There is a sub-directory here: + +dll + sources for the .dll(.so) used by test dlltest.c + +===================================================================== +The individual files are described here. + +The script 'runtests.ksh' enumerates and runs test cases that are +expected to run on all platforms. + + +accept.c + Tests PR_Accept() and related socket functions. + +acceptread.c + Tests PR_AcceptRead() + +alarm.c + Tests alarm functions declared in obsolete/pralarm.h. + The alarm functions are obsolete, so is this test. + +atomic.c + Tests Atomic operations defined in pratom.h + +attach.c + Test PR_AttachThread() + Note: This is an NSPR private function. + +bigfile.c + Test 64bit file offset functions declared in prio.h + +bug1test.c + Demonstrates a bug on NT. + +cleanup.c + Tests PR_Cleanup() declared in prinit.h + +cltsrv.c + Tests many socket functions. + +concur.c + Tests threading functions and concurrent operations. + +cvar.c + Tests condition variables. + +cvar2.c + Tests condition variables. A rather abusive test. + +dbmalloc.c + Obsolete. Originally for testing debug builds of NSPR's malloc. + +dbmalloc1.c + Obsolete. Originally for testing debug builds of NSPR's malloc. + +dceemu.c + Tests special functions for DCE emulation. + +depend.c + Obsoltet. Tests early spec for library dependency. + +dlltest.c + Tests dynamic library fucntions. Used with dll/my.c + +dtoa.c + Tests conversions of double to string. + +exit.c + Tests PR_ProcessExit() declared in prinit.h + +fileio.c + Tests NSPR semaphores a bit of file i/o and threading + functions. + +foreign.c + Test auto-attach of a thread created by something other than + NSPR. + +forktest.c + Limited use. Tests unix fork() and related functions. + +fsync.c + Tests use of PR_Sync() declared in prio.h + +getproto.c + Tests socket functions PR_GetProtoByName(), etc. + +i2l.c + Tests LongLong functions for converting 32bit integer to 64bit + integer. + +initclk.c + Tests timing on minimal use of condition variable + +inrval.c + Tests interval timing functions. + +instrumt.c + Tests instrumentation functions. prcountr.h prtrace.h + +intrupt.c + Tests PR_Interrupt() + +ioconthr.c + Tests i/o continuation mechanism in pthreads. + +io_timeout.c + Test socket i/o timeouts. + +io_timeoutk.c + Obsolete. Subsumed in io_timeout.c + +io_timeoutu.c + Obsolete. Subsumed in io_timeout.c + +ipv6.c + Tests IPv6. IPv6 is not used by NSPR clients. + +join.c + Tests PR_JoinThread() + +joinkk.c + Tests PR_JoinThread() + +joinku.c + Tests PR_JoinThread() + +joinuk.c + Tests PR_JoinThread() + +joinuu.c + Tests PR_JoinThread() + +layer.c + Tests layered I/O. + +lazyinit.c + Tests implicit initialization. + +lltest.c + Tests LongLong (64bit integer) arithmentic and conversions. + +lock.c + Tests PR_Lock() in heavily threaded environment. + +lockfile.c + Test PR_Lockfile(). + +logger.c + Tests PR_LOG() + +makefile + The makefile that builds all the tests + +many_cv.c + Tests aquiring a large number of condition variables. + +multiwait.c + ??? + +nbconn.c + Test non-blocking connect. + +nblayer.c + Tests NSPR's layered I/O capability. + +nonblock.c + Tests operations on non-blocking socket. + +op_2long.c + Tests PR_Open() where filename is too long. + +op_filnf.c + Tests PR_Open() where filename is NotFound. + +op_filok.c + Tests PR_Open() where filename is accessable. + +op_noacc.c + Tests PR_Open() where file permissions are wrong. + Limited use. Windows has no concept of Unix style file permissions. + +op_nofil.c + Tests PR_Open() where filename does not exist. + +parent.c + Test parent/child process capability + +perf.c + Tests and measures context switch times for various thread + syncronization functions. + +pipeping.c + Tests inter-process pipes. Run with pipepong.c + +pipepong.c + Tests inter-process pipes. Run with pipeping.c + +pipeself.c + Tests inter-thread pipes. + +pollable.c + Tests pollable events. prio.h + +poll_er.c + Tests PR_Poll() where an error is expected. + +poll_nm.c + Tests PR_Poll() where normal operation is expected. + +poll_to.c + Tests PR_Poll() where timeout is expected. + +prftest.c + Tests printf-like formatting. + +prftest1.c + Obsolete. Subsumed in prftest.c + +prftest2.c + Obsolete. Subsumed in prftest.c + +priotest.c + Limited use. Tests NSPR thread dispatching priority. + +provider.c + +prpoll.c + Tests PR_Poll(). + +prselect.c + Obsolete. PR_Select() is obsolete. + +prttools.h + Unused file. + +ranfile.c + Tests random file access. + +readme + This file. + +runtests.ksh + A korn shell script that runs a set of tests that should run + on any of the NSPR supported platforms. + +runtests.pl + A perl script to run the test cases. This srcipt runs tests + common to all platforms and runs tests applicable to specific + platforms. Uses file runtests.txt to control execution. + +runtests.txt + Control file for perl script: runtests.pl + +rwlocktest.c + Tests Reader/Writer lock + +selct_er.c + Obsolete. PR_Select() is obsolete. + +selct_nm.c + Obsolete. PR_Select() is obsolete. + +selct_to.c + Obsolete. PR_Select() is obsolete. + +select2.c + Obsolete. PR_Select() is obsolete. + +sel_spd.c + Obsolete. PR_Select() is obsolete. + +sem.c + Obsolete. Semaphores are not supported. + +server_test.c + Tests sockets by simulating a server in loopback mode. + Makes its own client threads. + +servr_kk.c + Tests client/server sockets, threads using system threads. + +servr_ku.c + Tests client/server sockets, threads using system and user threads. + +servr_uk.c + Tests client/server sockets, threads using system and user threads. + +servr_uu.c + Tests client/server sockets, threads user threads. + +short_thread.c + Tests short-running threads. Useful for testing for race conditions. + +sigpipe.c + Tests NSPR's SIGPIPE handler. Unix only. + +sleep.c + Limited use. Tests sleep capability of platform. + +socket.c + Tests many socket functions. + +sockopt.c + Tests setting and getting socket options. + +sprintf.c + Tests sprintf. + +sproc_ch.c + Obsolete. Tests IRIX sproc-based threads. + +sproc_p.c + Obsolete. Tests IRIX sproc-based threads. + +stack.c + Test atomic stack operations. + +stat.c + Tests performance of getfileinfo() vs. stat() + +stdio.c + Tests NSPR's handling of stdin, stdout, stderr. + +strod.c + Tests formatting of double precision floating point. + +suspend.c + Private interfaces PR_SuspendAll(), PR_ResumeAll(), etc. + +switch.c + Tests thread switching + +system.c + Tests PR_GetSystemInfo() + +testbit.c + Tests bit arrays. + +testfile.c + Tests many file I/O functions. + +threads.c + Tests thread caching. + +thruput.c + Tests socket thruput. Must be run by hand as client/server. + Does not self terminate. + +time.c + Incomplete. Limited use. + +timemac.c + Test time and date functions. Originally for Mac. + +timetest.c + Tests time conversion over a wide range of dates. + +tmoacc.c + Server to tmocon.c and writev.c + Do not run it by itself. + +tmocon.c + Client thread to tmoacc.c + +tpd.c + Tests thread private data. + +udpsrv.c + Tests UDP socket functions. + +ut_ttools.h + unused file. + +version.c + Extract and print library version data. + +vercheck.c + Test PR_VersionCheck(). + +writev.c + Tests gather-write on a socket. Requires tmoacc.c + +xnotify.c + Tests cached monitors. + +yield.c + Limited use + +y2k.c + Test to verify NSPR's date functions as Y2K compliant. + +dll\Makefile + makefile for mygetval.c, mysetval.c + +dll\mygetval.c + Dynamic library test. See also dlltest.c + +dll\mysetval.c + Dynamic library test. See also dlltest.c diff --git a/nsprpub/pr/tests/accept.c b/nsprpub/pr/tests/accept.c new file mode 100644 index 00000000000..4fada1aabe3 --- /dev/null +++ b/nsprpub/pr/tests/accept.c @@ -0,0 +1,524 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: accept.c +** +** Description: Run accept() sucessful connection tests. +** +** Modification History: +** 04-Jun-97 AGarcia - Reconvert test file to return a 0 for PASS and a 1 for FAIL +** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + +#include "nspr.h" +#include "prpriv.h" + +#include +#include + +#include "plgetopt.h" +#include "plerror.h" + +#define BASE_PORT 10000 + +#define CLIENT_DATA 128 + +#define ACCEPT_NORMAL 0x1 +#define ACCEPT_FAST 0x2 +#define ACCEPT_READ 0x3 +#define ACCEPT_READ_FAST 0x4 +#define ACCEPT_READ_FAST_CB 0x5 + +#define CLIENT_NORMAL 0x1 +#define CLIENT_TIMEOUT_ACCEPT 0x2 +#define CLIENT_TIMEOUT_SEND 0x3 + +#define SERVER_MAX_BIND_COUNT 100 + +#if defined(XP_MAC) || defined(XP_OS2) +#define TIMEOUTSECS 10 +#else +#define TIMEOUTSECS 2 +#endif +PRIntervalTime timeoutTime; + +static PRInt32 count = 1; +static PRFileDesc *output; +static PRNetAddr serverAddr; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; +static PRInt32 clientCommand; +static PRInt32 iterations; +static PRStatus rv; +static PRFileDesc *listenSock; +static PRFileDesc *clientSock = NULL; +static PRNetAddr listenAddr; +static PRNetAddr clientAddr; +static PRThread *clientThread; +static PRNetAddr *raddr; +static char buf[4096 + 2*sizeof(PRNetAddr) + 32]; +static PRInt32 status; +static PRInt32 bytesRead; + +PRIntn failed_already=0; +PRIntn debug_mode; + +void Test_Assert(const char *msg, const char *file, PRIntn line) +{ + failed_already=1; + if (debug_mode) { + PR_fprintf(output, "@%s:%d ", file, line); + PR_fprintf(output, msg); + } +} /* Test_Assert */ + +#define TEST_ASSERT(expr) \ + if (!(expr)) Test_Assert(#expr, __FILE__, __LINE__) + +#ifdef WINNT +#define CALLBACK_MAGIC 0x12345678 + +void timeout_callback(void *magic) +{ + TEST_ASSERT(magic == (void *)CALLBACK_MAGIC); + if (debug_mode) + PR_fprintf(output, "timeout callback called okay\n"); +} +#endif + + +static void PR_CALLBACK +ClientThread(void *_action) +{ + PRInt32 action = * (PRInt32 *) _action; + PRInt32 iterations = count; + PRFileDesc *sock = NULL; + + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = listenAddr.inet.port; + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + for (; iterations--;) { + PRInt32 rv; + char buf[CLIENT_DATA]; + + memset(buf, 0xaf, sizeof(buf)); /* initialize with arbitrary data */ + sock = PR_NewTCPSocket(); + if (!sock) { + if (!debug_mode) + failed_already=1; + else + PR_fprintf(output, "client: unable to create socket\n"); + return; + } + + if (action != CLIENT_TIMEOUT_ACCEPT) { + + if ((rv = PR_Connect(sock, &serverAddr, + timeoutTime)) < 0) { + if (!debug_mode) + failed_already=1; + else + PR_fprintf(output, + "client: unable to connect to server (%ld, %ld, %ld, %ld)\n", + iterations, rv, PR_GetError(), PR_GetOSError()); + goto ErrorExit; + } + + if (action != CLIENT_TIMEOUT_SEND) { + if ((rv = PR_Send(sock, buf, CLIENT_DATA, + 0, timeoutTime))< 0) { + if (!debug_mode) + failed_already=1; + else + 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)); + } + } else { + PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); + } + if (debug_mode) + PR_fprintf(output, "."); + PR_Close(sock); + sock = NULL; + } + if (debug_mode) + PR_fprintf(output, "\n"); + +ErrorExit: + if (sock != NULL) + PR_Close(sock); +} + + +static void +RunTest(PRInt32 acceptType, PRInt32 clientAction) +{ +int i; + + /* First bind to the socket */ + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + failed_already=1; + if (debug_mode) + PR_fprintf(output, "unable to create listen socket\n"); + return; + } + memset(&listenAddr, 0 , sizeof(listenAddr)); + listenAddr.inet.family = PR_AF_INET; + listenAddr.inet.port = PR_htons(BASE_PORT); + listenAddr.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(listenSock, &listenAddr) == PR_FAILURE) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + listenAddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + failed_already=1; + if (debug_mode) + PR_fprintf(output,"accept: ERROR - PR_Bind failed\n"); + return; + } + + + rv = PR_Listen(listenSock, 100); + if (rv == PR_FAILURE) { + failed_already=1; + if (debug_mode) + PR_fprintf(output, "unable to listen\n"); + return; + } + + clientCommand = clientAction; + clientThread = PR_CreateThread(PR_USER_THREAD, ClientThread, + (void *)&clientCommand, PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 0); + if (!clientThread) { + failed_already=1; + if (debug_mode) + PR_fprintf(output, "error creating client thread\n"); + return; + } + + iterations = count; + for (;iterations--;) { + switch (acceptType) { + case ACCEPT_NORMAL: + clientSock = PR_Accept(listenSock, &clientAddr, + timeoutTime); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + TEST_ASSERT(clientSock == 0); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + bytesRead = PR_Recv(clientSock, + buf, CLIENT_DATA, 0, timeoutTime); + TEST_ASSERT(bytesRead == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + TEST_ASSERT(clientSock); + bytesRead = PR_Recv(clientSock, + buf, CLIENT_DATA, 0, timeoutTime); + TEST_ASSERT(bytesRead == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; + case ACCEPT_READ: + status = PR_AcceptRead(listenSock, &clientSock, + &raddr, buf, CLIENT_DATA, timeoutTime); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + /* Invalid test case */ + TEST_ASSERT(0); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + TEST_ASSERT(status == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + TEST_ASSERT(status == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; +#ifdef WINNT + case ACCEPT_FAST: + clientSock = PR_NTFast_Accept(listenSock, + &clientAddr, timeoutTime); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + TEST_ASSERT(clientSock == 0); + if (debug_mode) + PR_fprintf(output, "PR_GetError is %ld\n", PR_GetError()); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + bytesRead = PR_Recv(clientSock, + buf, CLIENT_DATA, 0, timeoutTime); + TEST_ASSERT(bytesRead == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + TEST_ASSERT(clientSock); + bytesRead = PR_Recv(clientSock, + buf, CLIENT_DATA, 0, timeoutTime); + TEST_ASSERT(bytesRead == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; + break; + case ACCEPT_READ_FAST: + status = PR_NTFast_AcceptRead(listenSock, + &clientSock, &raddr, buf, 4096, timeoutTime); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + /* Invalid test case */ + TEST_ASSERT(0); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + TEST_ASSERT(status == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + TEST_ASSERT(clientSock == NULL); + TEST_ASSERT(status == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; + case ACCEPT_READ_FAST_CB: + status = PR_NTFast_AcceptRead_WithTimeoutCallback( + listenSock, &clientSock, &raddr, buf, 4096, + timeoutTime, timeout_callback, (void *)CALLBACK_MAGIC); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + /* Invalid test case */ + TEST_ASSERT(0); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + TEST_ASSERT(status == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + if (debug_mode) + PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock); + TEST_ASSERT(clientSock == NULL); + TEST_ASSERT(status == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; +#endif + } + if (clientSock != NULL) { + PR_Close(clientSock); + clientSock = NULL; + } + } + PR_Close(listenSock); + + PR_JoinThread(clientThread); +} + + +void AcceptUpdatedTest(void) +{ + RunTest(ACCEPT_NORMAL, CLIENT_NORMAL); +} +void AcceptNotUpdatedTest(void) +{ + RunTest(ACCEPT_FAST, CLIENT_NORMAL); +} +void AcceptReadTest(void) +{ + RunTest(ACCEPT_READ, CLIENT_NORMAL); +} +void AcceptReadNotUpdatedTest(void) +{ + RunTest(ACCEPT_READ_FAST, CLIENT_NORMAL); +} +void AcceptReadCallbackTest(void) +{ + RunTest(ACCEPT_READ_FAST_CB, CLIENT_NORMAL); +} + +void TimeoutAcceptUpdatedTest(void) +{ + RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_ACCEPT); +} +void TimeoutAcceptNotUpdatedTest(void) +{ + RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_ACCEPT); +} +void TimeoutAcceptReadCallbackTest(void) +{ + RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_ACCEPT); +} + +void TimeoutReadUpdatedTest(void) +{ + RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_SEND); +} +void TimeoutReadNotUpdatedTest(void) +{ + RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_SEND); +} +void TimeoutReadReadTest(void) +{ + RunTest(ACCEPT_READ, CLIENT_TIMEOUT_SEND); +} +void TimeoutReadReadNotUpdatedTest(void) +{ + RunTest(ACCEPT_READ_FAST, CLIENT_TIMEOUT_SEND); +} +void TimeoutReadReadCallbackTest(void) +{ + RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_SEND); +} + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + if (debug_mode) + PR_fprintf(output, "%40s: %6.2f usec\n", msg, d / count); + +} + +int main(int argc, char **argv) +{ + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name [-d] [-c n] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdc:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'c': /* loop counter */ + count = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + output = PR_STDERR; + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("accept.log"); + debug_mode = 1; +#endif + + timeoutTime = PR_SecondsToInterval(TIMEOUTSECS); + if (debug_mode) + PR_fprintf(output, "\nRun accept() sucessful connection tests\n"); + + Measure(AcceptUpdatedTest, "PR_Accept()"); + Measure(AcceptReadTest, "PR_AcceptRead()"); +#ifdef WINNT + Measure(AcceptNotUpdatedTest, "PR_NTFast_Accept()"); + Measure(AcceptReadNotUpdatedTest, "PR_NTFast_AcceptRead()"); + Measure(AcceptReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); +#endif + if (debug_mode) + 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) + 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 + PR_fprintf(output, "%s\n", (failed_already) ? "FAIL" : "PASS"); + return failed_already; +} diff --git a/nsprpub/pr/tests/acceptread.c b/nsprpub/pr/tests/acceptread.c new file mode 100644 index 00000000000..ceb445d024d --- /dev/null +++ b/nsprpub/pr/tests/acceptread.c @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define DEFAULT_PORT 12273 +#define GET "GET / HTTP/1.0\n\n" +static PRFileDesc *std_out, *err_out; +static PRIntervalTime write_dally, accept_timeout; + +static PRStatus PrintAddress(const PRNetAddr* address) +{ + char buffer[100]; + PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); + if (PR_FAILURE == rv) PL_FPrintError(err_out, "PR_NetAddrToString"); + else PR_fprintf( + std_out, "Accepted connection from (0x%p)%s:%d\n", + address, buffer, address->inet.port); + return rv; +} /* PrintAddress */ + +static void ConnectingThread(void *arg) +{ + PRInt32 nbytes; + char buf[1024]; + PRFileDesc *sock; + PRNetAddr peer_addr, *addr; + + addr = (PRNetAddr*)arg; + + sock = PR_NewTCPSocket(); + if (sock == NULL) + { + PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed"); + PR_ProcessExit(1); + } + + if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_Connect (client) failed"); + PR_ProcessExit(1); + } + if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_GetPeerName (client) failed"); + PR_ProcessExit(1); + } + + /* + ** Then wait between the connection coming up and sending the expected + ** data. At some point in time, the server should fail due to a timeou + ** on the AcceptRead() operation, which according to the document is + ** only due to the read() portion. + */ + PR_Sleep(write_dally); + + nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes == -1) PL_FPrintError(err_out, "PR_Send (client) failed"); + + nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes == -1) PL_FPrintError(err_out, "PR_Recv (client) failed"); + else + { + PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes); + buf[sizeof(buf) - 1] = '\0'; + PR_fprintf(std_out, "%s\n", buf); + } + + if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH)) + PL_FPrintError(err_out, "PR_Shutdown (client) failed"); + + if (PR_FAILURE == PR_Close(sock)) + PL_FPrintError(err_out, "PR_Close (client) failed"); + + return; +} /* ConnectingThread */ + +#define BUF_SIZE 117 +static void AcceptingThread(void *arg) +{ + PRStatus rv; + PRInt32 bytes; + PRSize buf_size = BUF_SIZE; + PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32]; + PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg; + PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket(); + PRSocketOptionData sock_opt; + + if (NULL == listen_sock) + { + PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed"); + PR_ProcessExit(1); + } + sock_opt.option = PR_SockOpt_Reuseaddr; + sock_opt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(listen_sock, &sock_opt); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_SetSocketOption (server) failed"); + PR_ProcessExit(1); + } + rv = PR_Bind(listen_sock, listen_addr); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_Bind (server) failed"); + PR_ProcessExit(1); + } + rv = PR_Listen(listen_sock, 10); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_Listen (server) failed"); + PR_ProcessExit(1); + } + bytes = PR_AcceptRead( + listen_sock, &accept_sock, &accept_addr, buf, buf_size, accept_timeout); + + if (-1 == bytes) PL_FPrintError(err_out, "PR_AcceptRead (server) failed"); + else + { + PrintAddress(accept_addr); + PR_fprintf( + std_out, "(Server) read [0x%p..0x%p) %s\n", + buf, &buf[BUF_SIZE], buf); + bytes = PR_Write(accept_sock, buf, bytes); + rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Shutdown (server) failed"); + } + + if (-1 != bytes) + { + rv = PR_Close(accept_sock); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Close (server) failed"); + } + + rv = PR_Close(listen_sock); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Close (server) failed"); +} /* AcceptingThread */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRHostEnt he; + PRStatus status; + PRIntn next_index; + PRUint16 port_number; + char netdb_buf[PR_NETDB_BUF_SIZE]; + PRNetAddr client_addr, server_addr; + PRThread *client_thread, *server_thread; + PRIntervalTime delta = PR_MillisecondsToInterval(500); + + err_out = PR_STDERR; + std_out = PR_STDOUT; + accept_timeout = PR_SecondsToInterval(2); + + if (argc != 2 && argc != 3) port_number = DEFAULT_PORT; + else port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]); + + status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr); + if (PR_SUCCESS != status) + { + PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); + PR_ProcessExit(1); + } + if (argc < 3) + { + status = PR_InitializeNetAddr( + PR_IpAddrLoopback, port_number, &client_addr); + if (PR_SUCCESS != status) + { + PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); + PR_ProcessExit(1); + } + } + else + { + status = PR_GetHostByName( + argv[1], netdb_buf, sizeof(netdb_buf), &he); + if (status == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_GetHostByName failed"); + PR_ProcessExit(1); + } + next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr); + if (next_index == -1) + { + PL_FPrintError(err_out, "PR_EnumerateHostEnt failed"); + PR_ProcessExit(1); + } + } + + for ( + write_dally = 0; + write_dally < accept_timeout + (2 * delta); + write_dally += delta) + { + PR_fprintf( + std_out, "Testing w/ write_dally = %d msec\n", + PR_IntervalToMilliseconds(write_dally)); + server_thread = PR_CreateThread( + PR_USER_THREAD, AcceptingThread, &server_addr, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (server_thread == NULL) + { + PL_FPrintError(err_out, "PR_CreateThread (server) failed"); + PR_ProcessExit(1); + } + + PR_Sleep(delta); /* let the server pot thicken */ + + client_thread = PR_CreateThread( + PR_USER_THREAD, ConnectingThread, &client_addr, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (client_thread == NULL) + { + PL_FPrintError(err_out, "PR_CreateThread (client) failed"); + PR_ProcessExit(1); + } + + if (PR_JoinThread(client_thread) == PR_FAILURE) + PL_FPrintError(err_out, "PR_JoinThread (client) failed"); + + if (PR_JoinThread(server_thread) == PR_FAILURE) + PL_FPrintError(err_out, "PR_JoinThread (server) failed"); + } + + return 0; +} diff --git a/nsprpub/pr/tests/acceptreademu.c b/nsprpub/pr/tests/acceptreademu.c new file mode 100644 index 00000000000..8d17f31ae2f --- /dev/null +++ b/nsprpub/pr/tests/acceptreademu.c @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This test is the same as acceptread.c except that it uses the + * emulated acceptread method instead of the regular acceptread. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define DEFAULT_PORT 12273 +#define GET "GET / HTTP/1.0\n\n" +static PRFileDesc *std_out, *err_out; +static PRIntervalTime write_dally, accept_timeout; +static PRDescIdentity emu_layer_ident; +static PRIOMethods emu_layer_methods; + +/* the acceptread method in emu_layer_methods */ +static PRInt32 PR_CALLBACK emu_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + return PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); +} + +static PRStatus PrintAddress(const PRNetAddr* address) +{ + char buffer[100]; + PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); + if (PR_FAILURE == rv) PL_FPrintError(err_out, "PR_NetAddrToString"); + else PR_fprintf( + std_out, "Accepted connection from (0x%p)%s:%d\n", + address, buffer, address->inet.port); + return rv; +} /* PrintAddress */ + +static void ConnectingThread(void *arg) +{ + PRInt32 nbytes; + char buf[1024]; + PRFileDesc *sock; + PRNetAddr peer_addr, *addr; + + addr = (PRNetAddr*)arg; + + sock = PR_NewTCPSocket(); + if (sock == NULL) + { + PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed"); + PR_ProcessExit(1); + } + + if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_Connect (client) failed"); + PR_ProcessExit(1); + } + if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_GetPeerName (client) failed"); + PR_ProcessExit(1); + } + + /* + ** Then wait between the connection coming up and sending the expected + ** data. At some point in time, the server should fail due to a timeou + ** on the AcceptRead() operation, which according to the document is + ** only due to the read() portion. + */ + PR_Sleep(write_dally); + + nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes == -1) PL_FPrintError(err_out, "PR_Send (client) failed"); + + nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes == -1) PL_FPrintError(err_out, "PR_Recv (client) failed"); + else + { + PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes); + buf[sizeof(buf) - 1] = '\0'; + PR_fprintf(std_out, "%s\n", buf); + } + + if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH)) + PL_FPrintError(err_out, "PR_Shutdown (client) failed"); + + if (PR_FAILURE == PR_Close(sock)) + PL_FPrintError(err_out, "PR_Close (client) failed"); + + return; +} /* ConnectingThread */ + +#define BUF_SIZE 117 +static void AcceptingThread(void *arg) +{ + PRStatus rv; + PRInt32 bytes; + PRSize buf_size = BUF_SIZE; + PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32]; + PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg; + PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket(); + PRFileDesc *layer; + PRSocketOptionData sock_opt; + + if (NULL == listen_sock) + { + PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed"); + PR_ProcessExit(1); + } + layer = PR_CreateIOLayerStub(emu_layer_ident, &emu_layer_methods); + if (NULL == layer) + { + PL_FPrintError(err_out, "PR_CreateIOLayerStub (server) failed"); + PR_ProcessExit(1); + } + if (PR_PushIOLayer(listen_sock, PR_TOP_IO_LAYER, layer) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_PushIOLayer (server) failed"); + PR_ProcessExit(1); + } + sock_opt.option = PR_SockOpt_Reuseaddr; + sock_opt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(listen_sock, &sock_opt); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_SetSocketOption (server) failed"); + PR_ProcessExit(1); + } + rv = PR_Bind(listen_sock, listen_addr); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_Bind (server) failed"); + PR_ProcessExit(1); + } + rv = PR_Listen(listen_sock, 10); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_Listen (server) failed"); + PR_ProcessExit(1); + } + bytes = PR_AcceptRead( + listen_sock, &accept_sock, &accept_addr, buf, buf_size, accept_timeout); + + if (-1 == bytes) PL_FPrintError(err_out, "PR_AcceptRead (server) failed"); + else + { + PrintAddress(accept_addr); + PR_fprintf( + std_out, "(Server) read [0x%p..0x%p) %s\n", + buf, &buf[BUF_SIZE], buf); + bytes = PR_Write(accept_sock, buf, bytes); + rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Shutdown (server) failed"); + } + + if (-1 != bytes) + { + rv = PR_Close(accept_sock); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Close (server) failed"); + } + + rv = PR_Close(listen_sock); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Close (server) failed"); +} /* AcceptingThread */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRHostEnt he; + PRStatus status; + PRIntn next_index; + PRUint16 port_number; + char netdb_buf[PR_NETDB_BUF_SIZE]; + PRNetAddr client_addr, server_addr; + PRThread *client_thread, *server_thread; + PRIntervalTime delta = PR_MillisecondsToInterval(500); + + err_out = PR_STDERR; + std_out = PR_STDOUT; + accept_timeout = PR_SecondsToInterval(2); + emu_layer_ident = PR_GetUniqueIdentity("Emulated AcceptRead"); + emu_layer_methods = *PR_GetDefaultIOMethods(); + emu_layer_methods.acceptread = emu_AcceptRead; + + if (argc != 2 && argc != 3) port_number = DEFAULT_PORT; + else port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]); + + status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr); + if (PR_SUCCESS != status) + { + PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); + PR_ProcessExit(1); + } + if (argc < 3) + { + status = PR_InitializeNetAddr( + PR_IpAddrLoopback, port_number, &client_addr); + if (PR_SUCCESS != status) + { + PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); + PR_ProcessExit(1); + } + } + else + { + status = PR_GetHostByName( + argv[1], netdb_buf, sizeof(netdb_buf), &he); + if (status == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_GetHostByName failed"); + PR_ProcessExit(1); + } + next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr); + if (next_index == -1) + { + PL_FPrintError(err_out, "PR_EnumerateHostEnt failed"); + PR_ProcessExit(1); + } + } + + for ( + write_dally = 0; + write_dally < accept_timeout + (2 * delta); + write_dally += delta) + { + PR_fprintf( + std_out, "Testing w/ write_dally = %d msec\n", + PR_IntervalToMilliseconds(write_dally)); + server_thread = PR_CreateThread( + PR_USER_THREAD, AcceptingThread, &server_addr, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (server_thread == NULL) + { + PL_FPrintError(err_out, "PR_CreateThread (server) failed"); + PR_ProcessExit(1); + } + + PR_Sleep(delta); /* let the server pot thicken */ + + client_thread = PR_CreateThread( + PR_USER_THREAD, ConnectingThread, &client_addr, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (client_thread == NULL) + { + PL_FPrintError(err_out, "PR_CreateThread (client) failed"); + PR_ProcessExit(1); + } + + if (PR_JoinThread(client_thread) == PR_FAILURE) + PL_FPrintError(err_out, "PR_JoinThread (client) failed"); + + if (PR_JoinThread(server_thread) == PR_FAILURE) + PL_FPrintError(err_out, "PR_JoinThread (server) failed"); + } + + return 0; +} diff --git a/nsprpub/pr/tests/addrstr.c b/nsprpub/pr/tests/addrstr.c new file mode 100644 index 00000000000..a18f9a8ccfd --- /dev/null +++ b/nsprpub/pr/tests/addrstr.c @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prnetdb.h" + +#include +#include +#include + +const char *testaddrs[] = { + "::", "::", + "::1", "::1", + "::ffff", "::ffff", + "::1:0", "::0.1.0.0", + "::127.0.0.1", "::127.0.0.1", + "::FFFF:127.0.0.1", "::ffff:127.0.0.1", + "::FFFE:9504:3501", "::fffe:9504:3501", + "0:0:1:0:35c:0:0:0", "0:0:1:0:35c::", + "0:0:3f4c:0:0:4552:0:0", "::3f4c:0:0:4552:0:0", + "0:0:1245:0:0:0:0567:0", "0:0:1245::567:0", + "0:1:2:3:4:5:6:7", "0:1:2:3:4:5:6:7", + "1:2:3:0:4:5:6:7", "1:2:3:0:4:5:6:7", + "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:0", + "1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8", + "1:2:3:4:5:6::7", "1:2:3:4:5:6:0:7", + 0 +}; + +const char *badaddrs[] = { + "::.1.2.3", + "ffff::.1.2.3", + "1:2:3:4:5:6:7::8", + "1:2:3:4:5:6::7:8", + "::ff99.2.3.4", + 0 +}; + +int failed_already = 0; + +int main() +{ + const char **nexttestaddr = testaddrs; + const char **nextbadaddr = badaddrs; + const char *in, *expected_out; + PRNetAddr addr; + char buf[256]; + PRStatus rv; + + while ((in = *nexttestaddr++) != 0) { + expected_out = *nexttestaddr++; + rv = PR_StringToNetAddr(in, &addr); + if (rv) { + printf("cannot convert %s to addr: %d\n", in, rv); + failed_already = 1; + continue; + } + rv = PR_NetAddrToString(&addr, buf, sizeof(buf)); + if (rv) { + printf("cannot convert %s back to string: %d\n", in, rv); + failed_already = 1; + continue; + } + if (strcmp(buf, expected_out)) { + /* This is not necessarily an error */ + printf("%s expected %s got %s\n", in, expected_out, buf); + } + } + while ((in = *nextbadaddr++) != 0) { + if (PR_StringToNetAddr(in, &addr) == PR_SUCCESS) { + printf("converted bad addr %s\n", in); + failed_already = 1; + } + } + if (failed_already) { + printf("FAIL\n"); + return 1; + } + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/affinity.c b/nsprpub/pr/tests/affinity.c new file mode 100644 index 00000000000..46f159bf1e5 --- /dev/null +++ b/nsprpub/pr/tests/affinity.c @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "pprthred.h" +#include "plgetopt.h" + +#include +#include +#include + +#ifndef XP_BEOS + +/* + * Test PR_GetThreadAffinityMask + * The function is called by each of local, global and global bound threads + * The test should be run on both single and multi-cpu systems + */ +static void PR_CALLBACK thread_start(void *arg) +{ +PRUint32 mask = 0; + + if (PR_GetThreadAffinityMask(PR_GetCurrentThread(), &mask)) + printf("\tthread_start: PR_GetCurrentThreadAffinityMask failed\n"); + else + printf("\tthread_start: AffinityMask = 0x%x\n",mask); + +} + +int main(int argc, char **argv) +{ + PRThread *t; + + printf("main: creating local thread\n"); + + t = PR_CreateThread(PR_USER_THREAD, + thread_start, 0, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + if (NULL == t) { + printf("main: cannot create local thread\n"); + exit(1); + } + + PR_JoinThread(t); + + printf("main: creating global thread\n"); + t = PR_CreateThread(PR_USER_THREAD, + thread_start, 0, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + if (NULL == t) { + printf("main: cannot create global thread\n"); + exit(1); + } + + PR_JoinThread(t); + + printf("main: creating global bound thread\n"); + t = PR_CreateThread(PR_USER_THREAD, + thread_start, 0, + PR_PRIORITY_NORMAL, + PR_GLOBAL_BOUND_THREAD, + PR_JOINABLE_THREAD, + 0); + + if (NULL == t) { + printf("main: cannot create global bound thread\n"); + exit(1); + } + + PR_JoinThread(t); + + return 0; +} + +#else /* !XP_BEOS */ + +int main() +{ + printf( "This test is not supported on the BeOS\n" ); + return 0; +} +#endif /* !XP_BEOS */ diff --git a/nsprpub/pr/tests/alarm.c b/nsprpub/pr/tests/alarm.c new file mode 100644 index 00000000000..7af2ed4c03c --- /dev/null +++ b/nsprpub/pr/tests/alarm.c @@ -0,0 +1,569 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: alarmtst.c +** +** Description: Test alarms +** +** Modification History: +** 13-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + +#include "prlog.h" +#include "prinit.h" +#ifdef XP_MAC +#include "pralarm.h" +#else +#include "obsolete/pralarm.h" +#endif +#include "prlock.h" +#include "prlong.h" +#include "prcvar.h" +#include "prinrval.h" +#include "prtime.h" + +/* Used to get the command line option */ +#include "plgetopt.h" +#include +#include + +#if defined(XP_UNIX) +#include +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static PRIntn debug_mode; +static PRIntn failed_already=0; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +typedef struct notifyData { + PRLock *ml; + PRCondVar *child; + PRCondVar *parent; + PRBool pending; + PRUint32 counter; +} NotifyData; + +static void Notifier(void *arg) +{ + NotifyData *notifyData = (NotifyData*)arg; + PR_Lock(notifyData->ml); + while (notifyData->counter > 0) + { + while (!notifyData->pending) + PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT); + notifyData->counter -= 1; + notifyData->pending = PR_FALSE; + PR_NotifyCondVar(notifyData->parent); + } + PR_Unlock(notifyData->ml); +} /* Notifier */ +/*********************************************************************** +** PRIVATE FUNCTION: ConditionNotify +** DESCRIPTION: +** +** INPUTS: loops +** OUTPUTS: None +** RETURN: overhead +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: +** +***********************************************************************/ + + +static PRIntervalTime ConditionNotify(PRUint32 loops) +{ + PRThread *thread; + NotifyData notifyData; + PRIntervalTime timein, overhead; + + timein = PR_IntervalNow(); + + notifyData.counter = loops; + notifyData.ml = PR_NewLock(); + notifyData.child = PR_NewCondVar(notifyData.ml); + notifyData.parent = PR_NewCondVar(notifyData.ml); + thread = PR_CreateThread( + PR_USER_THREAD, Notifier, ¬ifyData, + PR_GetThreadPriority(PR_GetCurrentThread()), + thread_scope, PR_JOINABLE_THREAD, 0); + + overhead = PR_IntervalNow() - timein; /* elapsed so far */ + + PR_Lock(notifyData.ml); + while (notifyData.counter > 0) + { + notifyData.pending = PR_TRUE; + PR_NotifyCondVar(notifyData.child); + while (notifyData.pending) + PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(notifyData.ml); + + timein = PR_IntervalNow(); + + (void)PR_JoinThread(thread); + PR_DestroyCondVar(notifyData.child); + PR_DestroyCondVar(notifyData.parent); + PR_DestroyLock(notifyData.ml); + + overhead += (PR_IntervalNow() - timein); /* more overhead */ + + return overhead; +} /* ConditionNotify */ + +static PRIntervalTime ConditionTimeout(PRUint32 loops) +{ + PRUintn count; + PRIntervalTime overhead, timein = PR_IntervalNow(); + + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + PRIntervalTime interval = PR_MillisecondsToInterval(50); + + overhead = PR_IntervalNow() - timein; + + PR_Lock(ml); + for (count = 0; count < loops; ++count) + { + overhead += interval; + PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS); + } + PR_Unlock(ml); + + timein = PR_IntervalNow(); + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + overhead += (PR_IntervalNow() - timein); + + return overhead; +} /* ConditionTimeout */ + +typedef struct AlarmData { + PRLock *ml; + PRCondVar *cv; + PRUint32 rate, late, times; + PRIntervalTime duration, timein, period; +} AlarmData; + +static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late) +{ + PRStatus rv = PR_SUCCESS; + PRBool keepGoing, resetAlarm; + PRIntervalTime interval, now = PR_IntervalNow(); + AlarmData *ad = (AlarmData*)clientData; + + PR_Lock(ad->ml); + ad->late += late; + ad->times += 1; + keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ? + PR_TRUE : PR_FALSE; + if (!keepGoing) + rv = PR_NotifyCondVar(ad->cv); + resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE; + + interval = (ad->period + ad->rate - 1) / ad->rate; + if (!late && (interval > 10)) + { + interval &= (now & 0x03) + 1; + PR_WaitCondVar(ad->cv, interval); + } + + PR_Unlock(ad->ml); + + if (rv != PR_SUCCESS) + { + if (!debug_mode) failed_already=1; + else + printf("AlarmFn: notify status: FAIL\n"); + + } + + if (resetAlarm) + { + ad->rate += 3; + ad->late = ad->times = 0; + if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS) + { + if (!debug_mode) + failed_already=1; + else + printf("AlarmFn: Resetting alarm status: FAIL\n"); + + keepGoing = PR_FALSE; + } + + } + + return keepGoing; +} /* AlarmFn1 */ + +static PRIntervalTime Alarms1(PRUint32 loops) +{ + PRAlarm *alarm; + AlarmData ad; + PRIntervalTime overhead, timein = PR_IntervalNow(); + PRIntervalTime duration = PR_SecondsToInterval(3); + + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + + ad.ml = ml; + ad.cv = cv; + ad.rate = 1; + ad.times = loops; + ad.late = ad.times = 0; + ad.duration = duration; + ad.timein = PR_IntervalNow(); + ad.period = PR_SecondsToInterval(1); + + alarm = PR_CreateAlarm(); + + (void)PR_SetAlarm( + alarm, ad.period, ad.rate, AlarmFn1, &ad); + + overhead = PR_IntervalNow() - timein; + + PR_Lock(ml); + while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(ml); + + timein = PR_IntervalNow(); + (void)PR_DestroyAlarm(alarm); + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + overhead += (PR_IntervalNow() - timein); + + return duration + overhead; +} /* Alarms1 */ + +static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late) +{ +#if defined(XP_MAC) +#pragma unused (id) +#endif + + PRBool keepGoing; + PRStatus rv = PR_SUCCESS; + AlarmData *ad = (AlarmData*)clientData; + PRIntervalTime interval, now = PR_IntervalNow(); + + PR_Lock(ad->ml); + ad->times += 1; + keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ? + PR_TRUE : PR_FALSE; + interval = (ad->period + ad->rate - 1) / ad->rate; + + if (!late && (interval > 10)) + { + interval &= (now & 0x03) + 1; + PR_WaitCondVar(ad->cv, interval); + } + + if (!keepGoing) rv = PR_NotifyCondVar(ad->cv); + + PR_Unlock(ad->ml); + + + if (rv != PR_SUCCESS) + failed_already=1;; + + return keepGoing; +} /* AlarmFn2 */ + +static PRIntervalTime Alarms2(PRUint32 loops) +{ + PRStatus rv; + PRAlarm *alarm; + PRIntervalTime overhead, timein = PR_IntervalNow(); + AlarmData ad; + PRIntervalTime duration = PR_SecondsToInterval(30); + + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + + ad.ml = ml; + ad.cv = cv; + ad.rate = 1; + ad.times = loops; + ad.late = ad.times = 0; + ad.duration = duration; + ad.timein = PR_IntervalNow(); + ad.period = PR_SecondsToInterval(1); + + alarm = PR_CreateAlarm(); + + (void)PR_SetAlarm( + alarm, ad.period, ad.rate, AlarmFn2, &ad); + + overhead = PR_IntervalNow() - timein; + + PR_Lock(ml); + while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(ml); + + timein = PR_IntervalNow(); + + rv = PR_DestroyAlarm(alarm); + if (rv != PR_SUCCESS) + { + if (!debug_mode) + failed_already=1; + else + printf("***Destroying alarm status: FAIL\n"); + } + + + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + + overhead += (PR_IntervalNow() - timein); + + return duration + overhead; +} /* Alarms2 */ + +static PRIntervalTime Alarms3(PRUint32 loops) +{ + PRIntn i; + PRStatus rv; + PRAlarm *alarm; + AlarmData ad[3]; + PRIntervalTime duration = PR_SecondsToInterval(30); + PRIntervalTime overhead, timein = PR_IntervalNow(); + + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + + for (i = 0; i < 3; ++i) + { + ad[i].ml = ml; + ad[i].cv = cv; + ad[i].rate = 1; + ad[i].times = loops; + ad[i].duration = duration; + ad[i].late = ad[i].times = 0; + ad[i].timein = PR_IntervalNow(); + ad[i].period = PR_SecondsToInterval(1); + + /* more loops, faster rate => same elapsed time */ + ad[i].times = (i + 1) * loops; + ad[i].rate = (i + 1) * 10; + } + + alarm = PR_CreateAlarm(); + + for (i = 0; i < 3; ++i) + { + (void)PR_SetAlarm( + alarm, ad[i].period, ad[i].rate, + AlarmFn2, &ad[i]); + } + + overhead = PR_IntervalNow() - timein; + + PR_Lock(ml); + for (i = 0; i < 3; ++i) + { + while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration) + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(ml); + + timein = PR_IntervalNow(); + + if (debug_mode) + printf + ("Alarms3 finished at %u, %u, %u\n", + ad[0].timein, ad[1].timein, ad[2].timein); + + rv = PR_DestroyAlarm(alarm); + if (rv != PR_SUCCESS) + { + if (!debug_mode) + failed_already=1; + else + printf("***Destroying alarm status: FAIL\n"); + } + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + + overhead += (duration / 3); + overhead += (PR_IntervalNow() - timein); + + return overhead; +} /* Alarms3 */ + +static PRUint32 TimeThis( + const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops) +{ + PRUint32 overhead, usecs; + PRIntervalTime predicted, timein, timeout, ticks; + + if (debug_mode) + printf("Testing %s ...", msg); + + timein = PR_IntervalNow(); + predicted = func(loops); + timeout = PR_IntervalNow(); + + if (debug_mode) + printf(" done\n"); + + ticks = timeout - timein; + usecs = PR_IntervalToMicroseconds(ticks); + overhead = PR_IntervalToMicroseconds(predicted); + + if(ticks < predicted) + { + if (debug_mode) { + printf("\tFinished in negative time\n"); + printf("\tpredicted overhead was %d usecs\n", overhead); + printf("\ttest completed in %d usecs\n\n", usecs); + } + } + else + { + if (debug_mode) + printf( + "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n", + usecs, overhead, ((double)(usecs - overhead) / (double)loops)); + } + + return overhead; +} /* TimeThis */ + +int prmain(int argc, char** argv) +{ + PRUint32 cpu, cpus = 0, loops = 0; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name [-d] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* GLOBAL threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'l': /* loop count */ + loops = atoi(opt->value); + break; + case 'c': /* concurrency limit */ + cpus = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + + if (cpus == 0) cpus = 1; + if (loops == 0) loops = 4; + + if (debug_mode) + printf("Alarm: Using %d loops\n", loops); + + if (debug_mode) + printf("Alarm: Using %d cpu(s)\n", cpus); +#ifdef XP_MAC + SetupMacPrintfLog("alarm.log"); + debug_mode = 1; +#endif + + for (cpu = 1; cpu <= cpus; ++cpu) + { + if (debug_mode) + printf("\nAlarm: Using %d CPU(s)\n", cpu); + + PR_SetConcurrency(cpu); + + /* some basic time test */ + (void)TimeThis("ConditionNotify", ConditionNotify, loops); + (void)TimeThis("ConditionTimeout", ConditionTimeout, loops); + (void)TimeThis("Alarms1", Alarms1, loops); + (void)TimeThis("Alarms2", Alarms2, loops); + (void)TimeThis("Alarms3", Alarms3, loops); + } + return 0; +} + +int main(int argc, char** argv) +{ + PR_Initialize(prmain, argc, argv, 0); + PR_STDIO_INIT(); + if (failed_already) return 1; + else return 0; + +} /* main */ + + +/* alarmtst.c */ diff --git a/nsprpub/pr/tests/anonfm.c b/nsprpub/pr/tests/anonfm.c new file mode 100644 index 00000000000..aeab86b14a1 --- /dev/null +++ b/nsprpub/pr/tests/anonfm.c @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: anonfm.c +** Description: Test anonymous file map +** +** Synopsis: anonfm [options] [dirName] +** +** Options: +** -d enable debug mode +** -h display a help message +** -s size of the anonymous memory map, in KBytes. default: 100KBytes. +** -C 1 Operate this process as ClientOne() +** -C 2 Operate this process as ClientTwo() +** +** anonfn.c contains two tests, corresponding to the two protocols for +** passing an anonymous file map to a child process. +** +** ServerOne()/ClientOne() tests the passing of "raw" file map; it uses +** PR_CreateProcess() [for portability of the test case] to create the +** child process, but does not use the PRProcessAttr structure for +** passing the file map data. +** +** ServerTwo()/ClientTwo() tests the passing of the file map using the +** PRProcessAttr structure. +** +*/ +#include +#include +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRUint32 failed_already = 0; + +PRIntn debug = 0; +PRIntn client = 0; /* invoke client, style */ +char dirName[512] = "."; /* directory name to contain anon mapped file */ +PRSize fmSize = (100 * 1024 ); +PRUint32 fmMode = 0600; +PRFileMapProtect fmProt = PR_PROT_READWRITE; +const char *fmEnvName = "nsprFileMapEnvVariable"; + +/* +** Emit help text for this test +*/ +static void Help( void ) +{ + printf("anonfm [options] [dirName]\n"); + printf("-d -- enable debug mode\n"); + printf("dirName is alternate directory name. Default: . (current directory)\n"); + exit(1); +} /* end Help() */ + + +/* +** ClientOne() -- +*/ +static void ClientOne( void ) +{ + PRFileMap *fm; + char *fmString; + char *addr; + PRStatus rc; + + PR_LOG(lm, msgLevel, + ("ClientOne() starting")); + + fmString = PR_GetEnv( fmEnvName ); + if ( NULL == fmString ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_Getenv() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_Getenv(): found: %s", fmString)); + + fm = PR_ImportFileMapFromString( fmString ); + if ( NULL == fm ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_ImportFileMapFromString() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_ImportFileMapFromString(): fm: %p", fm )); + + addr = PR_MemMap( fm, LL_ZERO, fmSize ); + if ( NULL == addr ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_MemMap() failed, OSError: %d", PR_GetOSError() )); + return; + } + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_MemMap(): addr: %p", addr )); + + /* write to memory map to release server */ + *addr = 1; + + rc = PR_MemUnmap( addr, fmSize ); + PR_ASSERT( rc == PR_SUCCESS ); + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_MemUnap(): success" )); + + rc = PR_CloseFileMap( fm ); + if ( PR_FAILURE == rc ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_MemUnap() failed, OSError: %d", PR_GetOSError() )); + return; + } + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_CloseFileMap(): success" )); + + return; +} /* end ClientOne() */ + +/* +** ClientTwo() -- +*/ +static void ClientTwo( void ) +{ + failed_already = 1; +} /* end ClientTwo() */ + +/* +** ServerOne() -- +*/ +static void ServerOne( void ) +{ + PRFileMap *fm; + PRStatus rc; + PRIntn i; + char *addr; + char fmString[256]; + char envBuf[256]; + char *child_argv[8]; + PRProcess *proc; + PRInt32 exit_status; + + PR_LOG(lm, msgLevel, + ("ServerOne() starting")); + + fm = PR_OpenAnonFileMap( dirName, fmSize, fmProt ); + if ( NULL == fm ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_OpenAnonFileMap() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ServerOne(): FileMap: %p", fm )); + + rc = PR_ExportFileMapAsString( fm, sizeof(fmString), fmString ); + if ( PR_FAILURE == rc ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_ExportFileMap() failed")); + return; + } + + /* + ** put the string into the environment + */ + PR_snprintf( envBuf, sizeof(envBuf), "%s=%s", fmEnvName, fmString); + putenv( envBuf ); + + addr = PR_MemMap( fm, LL_ZERO, fmSize ); + if ( NULL == addr ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_MemMap() failed")); + return; + } + + /* set initial value for client */ + for (i = 0; i < (PRIntn)fmSize ; i++ ) + *(addr+i) = 0x00; + + PR_LOG(lm, msgLevel, + ("ServerOne(): PR_MemMap(): addr: %p", addr )); + + /* + ** set arguments for child process + */ + child_argv[0] = "anonfm"; + child_argv[1] = "-C"; + child_argv[2] = "1"; + child_argv[3] = NULL; + + proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); + PR_ASSERT( proc ); + PR_LOG(lm, msgLevel, + ("ServerOne(): PR_CreateProcess(): proc: %x", proc )); + + /* + ** ClientOne() will set the memory to 1 + */ + PR_LOG(lm, msgLevel, + ("ServerOne(): waiting on Client, *addr: %x", *addr )); + while( *addr == 0x00 ) { + if ( debug ) + fprintf(stderr, "."); + PR_Sleep(PR_MillisecondsToInterval(300)); + } + if ( debug ) + fprintf(stderr, "\n"); + PR_LOG(lm, msgLevel, + ("ServerOne(): Client responded" )); + + rc = PR_WaitProcess( proc, &exit_status ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_MemUnmap( addr, fmSize); + if ( PR_FAILURE == rc ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_MemUnmap() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ServerOne(): PR_MemUnmap(): success" )); + + rc = PR_CloseFileMap(fm); + if ( PR_FAILURE == rc ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_CloseFileMap() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ServerOne(): PR_CloseFileMap() success" )); + + return; +} /* end ServerOne() */ + +/* +** ServerTwo() -- +*/ +static void ServerTwo( void ) +{ + PR_LOG(lm, msgLevel, + ("ServerTwo(): Not implemented yet" )); +} /* end ServerTwo() */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdC:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'C': /* Client style */ + client = atol(opt->value); + break; + case 's': /* file size */ + fmSize = atol( opt->value ) * 1024; + break; + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_DEBUG; + break; + case 'h': /* help message */ + Help(); + break; + default: + strcpy(dirName, opt->value); + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + if ( client == 1 ) { + ClientOne(); + } else if ( client == 2 ) { + ClientTwo(); + } else { + ServerOne(); + if ( failed_already ) goto Finished; + ServerTwo(); + } + +Finished: + if ( debug ) + printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end anonfm.c */ + diff --git a/nsprpub/pr/tests/append.c b/nsprpub/pr/tests/append.c new file mode 100644 index 00000000000..3800e2fbcee --- /dev/null +++ b/nsprpub/pr/tests/append.c @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: append.c +** Description: Testing File writes where PR_APPEND was used on open +** +** append attempts to verify that a file opened with PR_APPEND +** will always append to the end of file, regardless where the +** current file pointer is positioned. To do this, PR_Seek() is +** called before each write with the position set to beginning of +** file. Subsequent writes should always append. +** The file is read back, summing the integer data written to the +** file. If the expected result is equal, the test passes. +** +** See BugSplat: 4090 +*/ +#include "plgetopt.h" +#include "nspr.h" + +#include +#include + +PRIntn debug = 0; +PRIntn verbose = 0; +PRBool failedAlready = PR_FALSE; +const PRInt32 addedBytes = 1000; +const PRInt32 buf = 1; /* constant written to fd, addedBytes times */ +PRInt32 inBuf; /* read it back into here */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRStatus rc; + PRInt32 rv; + PRFileDesc *fd; + PRIntn i; + PRInt32 sum = 0; + + { /* Get command line options */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "vd"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + break; + case 'v': /* verbose */ + verbose = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } /* end block "Get command line options" */ +/* ---------------------------------------------------------------------- */ + fd = PR_Open( "/tmp/nsprAppend", (PR_APPEND | PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY), 0666 ); + if ( NULL == fd ) { + if (debug) printf("PR_Open() failed for writing: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + + for ( i = 0; i < addedBytes ; i++ ) { + rv = PR_Write( fd, &buf, sizeof(buf)); + if ( sizeof(buf) != rv ) { + if (debug) printf("PR_Write() failed: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + rv = PR_Seek( fd, 0 , PR_SEEK_SET ); + if ( -1 == rv ) { + if (debug) printf("PR_Seek() failed: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + } + rc = PR_Close( fd ); + if ( PR_FAILURE == rc ) { + if (debug) printf("PR_Close() failed after writing: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } +/* ---------------------------------------------------------------------- */ + fd = PR_Open( "/tmp/nsprAppend", PR_RDONLY, 0 ); + if ( NULL == fd ) { + if (debug) printf("PR_Open() failed for reading: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + + for ( i = 0; i < addedBytes ; i++ ) { + rv = PR_Read( fd, &inBuf, sizeof(inBuf)); + if ( sizeof(inBuf) != rv) { + if (debug) printf("PR_Write() failed: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + sum += inBuf; + } + + rc = PR_Close( fd ); + if ( PR_FAILURE == rc ) { + if (debug) printf("PR_Close() failed after reading: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + if ( sum != addedBytes ) { + if (debug) printf("Uh Oh! addedBytes: %d. Sum: %d\n", addedBytes, sum); + failedAlready = PR_TRUE; + goto Finished; + } + +/* ---------------------------------------------------------------------- */ +Finished: + if (debug || verbose) printf("%s\n", (failedAlready)? "FAILED" : "PASSED" ); + return( (failedAlready)? 1 : 0 ); +} /* main() */ + +/* append.c */ diff --git a/nsprpub/pr/tests/atomic.c b/nsprpub/pr/tests/atomic.c new file mode 100644 index 00000000000..5970fe0c62c --- /dev/null +++ b/nsprpub/pr/tests/atomic.c @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prprf.h" +#include "pratom.h" + +/* + * TODO: create a macro to generate the six lines of code that are repeated + * for every test. Also rewrite the statement + * result = result | ((EXPRESSION) ? 0 : 1); + * as + * result |= !(EXPRESSION); + */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRInt32 rv, oldval, test, result = 0; + PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); + + /***********************/ + /* Test the functions. */ + /***********************/ + + oldval = test = -2; + rv = PR_AtomicIncrement(&test); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicIncrement(%d) == %d: %s\n", + oldval, rv, (rv == -1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicIncrement(&test); + result = result | ((rv == 0) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicIncrement(%d) == %d: %s\n", + oldval, rv, (rv == 0) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicIncrement(&test); + result = result | ((rv == 1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicIncrement(%d) == %d: %s\n", + oldval, rv, (rv == 1) ? "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"); + + oldval = test = 2; + rv = PR_AtomicDecrement(&test); + result = result | ((rv == 1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicDecrement(%d) == %d: %s\n", + oldval, rv, (rv == 1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicDecrement(&test); + result = result | ((rv == 0) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicDecrement(%d) == %d: %s\n", + oldval, rv, (rv == 0) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicDecrement(&test); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicDecrement(%d) == %d: %s\n", + oldval, rv, (rv == -1) ? "PASSED" : "FAILED"); + + /* set to a different value */ + oldval = test = -2; + rv = PR_AtomicSet(&test, 2); + result = result | (((rv == -2) && (test == 2)) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicSet(%d, %d) == %d: %s\n", + oldval, 2, rv, ((rv == -2) && (test == 2)) ? "PASSED" : "FAILED"); + + /* set to the same value */ + oldval = test = -2; + rv = PR_AtomicSet(&test, -2); + result = result | (((rv == -2) && (test == -2)) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicSet(%d, %d) == %d: %s\n", + oldval, -2, rv, ((rv == -2) && (test == -2)) ? "PASSED" : "FAILED"); + + /***********************/ + /* Test the macros. */ + /***********************/ + + oldval = test = -2; + rv = PR_ATOMIC_INCREMENT(&test); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n", + oldval, rv, (rv == -1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_INCREMENT(&test); + result = result | ((rv == 0) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n", + oldval, rv, (rv == 0) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_INCREMENT(&test); + result = result | ((rv == 1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n", + oldval, rv, (rv == 1) ? "PASSED" : "FAILED"); + + oldval = test = -2; + rv = PR_ATOMIC_ADD(&test,1); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n", + oldval, 1, rv, (rv == -1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_ADD(&test, 4); + result = result | ((rv == 3) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n", + oldval, 4, rv, (rv == 3) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_ADD(&test, -6); + result = result | ((rv == -3) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n", + oldval, -6, rv, (rv == -3) ? "PASSED" : "FAILED"); + + oldval = test = 2; + rv = PR_ATOMIC_DECREMENT(&test); + result = result | ((rv == 1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n", + oldval, rv, (rv == 1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_DECREMENT(&test); + result = result | ((rv == 0) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n", + oldval, rv, (rv == 0) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_ATOMIC_DECREMENT(&test); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n", + oldval, rv, (rv == -1) ? "PASSED" : "FAILED"); + + /* set to a different value */ + oldval = test = -2; + rv = PR_ATOMIC_SET(&test, 2); + result = result | (((rv == -2) && (test == 2)) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_SET(%d, %d) == %d: %s\n", + oldval, 2, rv, ((rv == -2) && (test == 2)) ? "PASSED" : "FAILED"); + + /* set to the same value */ + oldval = test = -2; + rv = PR_ATOMIC_SET(&test, -2); + result = result | (((rv == -2) && (test == -2)) ? 0 : 1); + PR_fprintf( + output, "PR_ATOMIC_SET(%d, %d) == %d: %s\n", + oldval, -2, rv, ((rv == -2) && (test == -2)) ? "PASSED" : "FAILED"); + + PR_fprintf( + output, "Atomic operations test %s\n", + (result == 0) ? "PASSED" : "FAILED"); + return result; +} /* main */ + +/* atomic.c */ diff --git a/nsprpub/pr/tests/attach.c b/nsprpub/pr/tests/attach.c new file mode 100644 index 00000000000..20da8ec316c --- /dev/null +++ b/nsprpub/pr/tests/attach.c @@ -0,0 +1,392 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: attach.c +** +** Description: Platform-specific code to create a native thread. The native thread will +** repeatedly call PR_AttachThread and PR_DetachThread. The +** primordial thread waits for this new thread to finish. +** +** Modification History: +** 13-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + +/* Used to get the command line option */ +#include "nspr.h" +#include "pprthred.h" +#include "plgetopt.h" + +#include + +#ifdef WIN32 +#include +#include +#elif defined(_PR_PTHREADS) +#include +#include "md/_pth.h" +#elif defined(IRIX) +#include +#include +#include +#include +#elif defined(SOLARIS) +#include +#elif defined(OS2) +#define INCL_DOS +#define INCL_ERRORS +#include +#include +#elif defined(XP_BEOS) +#include +#endif + +#define DEFAULT_COUNT 1000 +PRIntn failed_already=0; +PRIntn debug_mode; + + +int count; + + +static void +AttachDetach(void) +{ + PRThread *me; + PRInt32 index; + + for (index=0;indexoption) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'c': /* loop count */ + count = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + +#if defined(WIN16) + printf("attach: This test is not valid for Win16\n"); + goto exit_now; +#endif + + if(0 == count) count = DEFAULT_COUNT; + + /* + * To force the implicit initialization of nspr20 + */ + PR_SetError(0, 0); + PR_STDIO_INIT(); + + /* + * Platform-specific code to create a native thread. The native + * thread will repeatedly call PR_AttachThread and PR_DetachThread. + * The primordial thread waits for this new thread to finish. + */ + +#ifdef _PR_PTHREADS + + rv = _PT_PTHREAD_ATTR_INIT(&attr); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) { + failed_already=1; + goto exit_now; + } + +#ifndef _PR_DCETHREADS + rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) { + failed_already=1; + goto exit_now; + } +#endif /* !_PR_DCETHREADS */ + rv = _PT_PTHREAD_CREATE(&threadID, attr, threadStartFunc, NULL); + if (rv != 0) { + fprintf(stderr, "thread creation failed: error code %d\n", rv); + failed_already=1; + goto exit_now; + } + else { + if (debug_mode) + printf ("thread creation succeeded \n"); + + } + rv = _PT_PTHREAD_ATTR_DESTROY(&attr); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) { + failed_already=1; + goto exit_now; + } + rv = pthread_join(threadID, NULL); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) { + failed_already=1; + goto exit_now; + } + +#elif defined(SOLARIS) + + rv = thr_create(NULL, 0, threadStartFunc, NULL, 0, &threadID); + if (rv != 0) { + if(!debug_mode) { + failed_already=1; + goto exit_now; + } else + fprintf(stderr, "thread creation failed: error code %d\n", rv); + } + rv = thr_join(threadID, NULL, NULL); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) + { + failed_already=1; + goto exit_now; + } + + +#elif defined(WIN32) + + hThread = (HANDLE) _beginthreadex(NULL, 0, threadStartFunc, NULL, + 0, &threadID); + if (hThread == 0) { + fprintf(stderr, "thread creation failed: error code %d\n", + GetLastError()); + failed_already=1; + goto exit_now; + } + rv = WaitForSingleObject(hThread, INFINITE); + if (debug_mode)PR_ASSERT(rv != WAIT_FAILED); + else if (rv == WAIT_FAILED) { + failed_already=1; + goto exit_now; + } + +#elif defined(IRIX) + + threadID = sproc(threadStartFunc, PR_SALL, NULL); + if (threadID == -1) { + + fprintf(stderr, "thread creation failed: error code %d\n", + errno); + failed_already=1; + goto exit_now; + + } + else { + if (debug_mode) + printf ("thread creation succeeded \n"); + sleep(3); + goto exit_now; + } + rv = waitpid(threadID, NULL, 0); + if (debug_mode) PR_ASSERT(rv != -1); + else if (rv != -1) { + failed_already=1; + goto exit_now; + } + +#elif defined(OS2) + +# ifdef __EMX__ + threadID = (TID) _beginthread((void *)threadStartFunc, NULL, + 32768, NULL); +# else + threadID = (TID) _beginthread((void(* _Optlink)(void*))threadStartFunc, NULL, + 32768, NULL); +# endif + if (threadID == -1) { + fprintf(stderr, "thread creation failed: error code %d\n", errno); + failed_already=1; + goto exit_now; + } + rv = DosWaitThread(&threadID, DCWW_WAIT); + if (debug_mode) { + PR_ASSERT(rv == NO_ERROR); + } else if (rv != NO_ERROR) { + failed_already=1; + goto exit_now; + } + +#elif defined(XP_BEOS) + + threadID = spawn_thread(threadStartFunc, NULL, B_NORMAL_PRIORITY, NULL); + if (threadID <= B_ERROR) { + fprintf(stderr, "thread creation failed: error code %08lx\n", threadID); + failed_already = 1; + goto exit_now; + } + if (resume_thread(threadID) != B_OK) { + fprintf(stderr, "failed starting thread: error code %08lx\n", threadID); + failed_already = 1; + goto exit_now; + } + + waitRV = wait_for_thread(threadID, &threadRV); + if (debug_mode) + PR_ASSERT(waitRV == B_OK); + else if (waitRV != B_OK) { + failed_already = 1; + goto exit_now; + } + +#else + if (!debug_mode) + failed_already=1; + else + printf("The attach test does not apply to this platform because\n" + "either this platform does not have native threads or the\n" + "test needs to be written for this platform.\n"); + goto exit_now; +#endif + +exit_now: + if(failed_already) + return 1; + else + return 0; +} diff --git a/nsprpub/pr/tests/bigfile.c b/nsprpub/pr/tests/bigfile.c new file mode 100644 index 00000000000..19c0a7f9d6b --- /dev/null +++ b/nsprpub/pr/tests/bigfile.c @@ -0,0 +1,318 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prmem.h" +#include "prprf.h" +#include "prinit.h" +#include "prerror.h" +#include "prthread.h" + +#include "plerror.h" +#include "plgetopt.h" + +#define DEFAULT_COUNT 10 +#define DEFAULT_FILESIZE 1 +#define BUFFER_SIZE 1000000 + +typedef enum {v_silent, v_whisper, v_shout} Verbosity; +static void Verbose(Verbosity, const char*, const char*, PRIntn); + +#define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__) + +static PRIntn test_result = 2; +static PRFileDesc *output = NULL; +static PRIntn verbose = v_silent; +static PRIntn filesize = DEFAULT_FILESIZE; + +static PRIntn Usage(void) +{ + PR_fprintf(output, "Bigfile test usage:\n"); + PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s ] \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 \tFile size in megabytes\t\t(1 megabyte)\n"); + PR_fprintf(output, "\t\tName of test file\t(none)\n"); + return 2; /* nothing happened */ +} /* Usage */ + +static PRStatus DeleteIfFound(const char *filename) +{ + PRStatus rv; + VERBOSE(v_shout, "Checking for existing file"); + rv = PR_Access(filename, PR_ACCESS_WRITE_OK); + if (PR_SUCCESS == rv) + { + VERBOSE(v_shout, "Deleting existing file"); + rv = PR_Delete(filename); + if (PR_FAILURE == rv) VERBOSE(v_shout, "Cannot delete big file"); + } + else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) + VERBOSE(v_shout, "Cannot access big file"); + else rv = PR_SUCCESS; + return rv; +} /* DeleteIfFound */ + +static PRIntn Error(const char *msg, const char *filename) +{ + PRInt32 error = PR_GetError(); + if (NULL != msg) + { + if (0 == error) PR_fprintf(output, msg); + else PL_FPrintError(output, msg); + } + (void)DeleteIfFound(filename); + if (v_shout == verbose) PR_Abort(); + return 1; +} /* Error */ + +static void Verbose( + Verbosity level, const char *msg, const char *file, PRIntn line) +{ + if (level <= 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; + PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment; + PRInt64 sevenFox = LL_INIT(0,0x7fffffff); + + PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:"); + + output = PR_GetSpecialFD(PR_StandardError); + PR_STDIO_INIT(); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + filename = opt->value; + break; + 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; + case 'c': /* loop counter */ + count = atoi(opt->value); + break; + case 's': /* filesize */ + filesize = atoi(opt->value); + break; + case 'h': /* confused */ + default: + return Usage(); + } + } + PL_DestroyOptState(opt); + + if (0 == count) count = DEFAULT_COUNT; + if (0 == filesize) filesize = DEFAULT_FILESIZE; + if (NULL == filename) + { + if (DEFAULT_FILESIZE != filesize) return Usage(); + else filename = "bigfile.dat"; + } + + if (PR_FAILURE == DeleteIfFound(filename)) return 1; + + test_result = 0; + + LL_I2L(zero_meg, 0); + LL_I2L(one_meg, 1000000); + LL_I2L(filesize64, filesize); + buffer = (char*)PR_MALLOC(BUFFER_SIZE); + LL_I2L(big_fragment, BUFFER_SIZE); + LL_MUL(filesize64, filesize64, one_meg); + + for (loop = 0; loop < BUFFER_SIZE; ++loop) buffer[loop] = (char)loop; + + VERBOSE(v_whisper, "Creating big file"); + file = PR_Open(filename, PR_CREATE_FILE | PR_WRONLY, 0666); + if (NULL == file) return Error("PR_Open()", filename); + + VERBOSE(v_whisper, "Testing available space in empty file"); + big_answer = file->methods->available64(file); + if (!LL_IS_ZERO(big_answer)) return Error("empty available64()", filename); + + LL_SUB(big_size, filesize64, one_meg); + VERBOSE(v_whisper, "Creating sparse 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 sparse file"); + bytes = file->methods->write(file, buffer, BUFFER_SIZE); + if (bytes != BUFFER_SIZE) return Error("write", filename); + + VERBOSE(v_whisper, "Testing available space at end of sparse file"); + big_answer = file->methods->available64(file); + if (!LL_IS_ZERO(big_answer)) return Error("eof available64()", filename); + + VERBOSE(v_whisper, "Getting big info on sparse 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 sparse 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_IS_ZERO(big_answer)) return Error("rewind seek64()", filename); + + VERBOSE(v_whisper, "Establishing available space in rewound file"); + 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); + if (PR_FAILURE == rv) return Error("close()", filename); + + VERBOSE(v_whisper, "Reopening big file"); + file = PR_Open(filename, PR_RDWR, 0666); + 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(filesize64, big_answer)) + return Error("reopened available64()", filename); + + big_answer = zero_meg; + 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); + 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_IS_ZERO(big_answer)) + return Error("eof available64()", filename); + + VERBOSE(v_whisper, "Rewinding full file"); + big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); + 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, filesize64)) return Error("bof available64()", filename); + + VERBOSE(v_whisper, "Seeking to end of big file"); + 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 while it's open"); + 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, "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); + + PR_DELETE(buffer); + return test_result; +} /* main */ + +/* bigfile.c */ diff --git a/nsprpub/pr/tests/bigfile2.c b/nsprpub/pr/tests/bigfile2.c new file mode 100644 index 00000000000..3e8beeeb369 --- /dev/null +++ b/nsprpub/pr/tests/bigfile2.c @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" + +#include +#include +#include +#ifdef _WIN32 +#include +#endif + +#define TEST_FILE_NAME "bigfile2.txt" + +#define MESSAGE "Hello world!" +#define MESSAGE_SIZE 13 + +int main(int argc, char **argv) +{ + PRFileDesc *fd; + PRInt64 offset, position; + PRInt32 nbytes; + char buf[MESSAGE_SIZE]; +#ifdef _WIN32 + HANDLE hFile; + LARGE_INTEGER li; +#endif /* _WIN32 */ + + LL_I2L(offset, 1); + LL_SHL(offset, offset, 32); + + fd = PR_Open(TEST_FILE_NAME, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666); + if (fd == NULL) { + fprintf(stderr, "PR_Open failed\n"); + exit(1); + } + position = PR_Seek64(fd, offset, PR_SEEK_SET); + if (!LL_GE_ZERO(position)) { + fprintf(stderr, "PR_Seek64 failed\n"); + exit(1); + } + PR_ASSERT(LL_EQ(position, offset)); + strcpy(buf, MESSAGE); + nbytes = PR_Write(fd, buf, sizeof(buf)); + if (nbytes != sizeof(buf)) { + fprintf(stderr, "PR_Write failed\n"); + exit(1); + } + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + memset(buf, 0, sizeof(buf)); + +#ifdef _WIN32 + hFile = CreateFile(TEST_FILE_NAME, GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "CreateFile failed\n"); + exit(1); + } + li.QuadPart = offset; + li.LowPart = SetFilePointer(hFile, li.LowPart, &li.HighPart, FILE_BEGIN); + if (li.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR) { + fprintf(stderr, "SetFilePointer failed\n"); + exit(1); + } + PR_ASSERT(li.QuadPart == offset); + if (ReadFile(hFile, buf, sizeof(buf), &nbytes, NULL) == 0) { + fprintf(stderr, "ReadFile failed\n"); + exit(1); + } + PR_ASSERT(nbytes == sizeof(buf)); + if (strcmp(buf, MESSAGE)) { + fprintf(stderr, "corrupt data:$%s$\n", buf); + exit(1); + } + if (CloseHandle(hFile) == 0) { + fprintf(stderr, "CloseHandle failed\n"); + exit(1); + } +#endif /* _WIN32 */ + + if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_Delete failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/bigfile3.c b/nsprpub/pr/tests/bigfile3.c new file mode 100644 index 00000000000..3cb806ffc11 --- /dev/null +++ b/nsprpub/pr/tests/bigfile3.c @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" + +#include +#include +#include +#ifdef _WIN32 +#include +#endif + +#define TEST_FILE_NAME "bigfile3.txt" + +#define MESSAGE "Hello world!" +#define MESSAGE_SIZE 13 + +int main(int argc, char **argv) +{ + PRFileDesc *fd; + PRInt64 offset, position; + PRInt32 nbytes; + char buf[MESSAGE_SIZE]; +#ifdef _WIN32 + HANDLE hFile; + LARGE_INTEGER li; +#endif /* _WIN32 */ + + LL_I2L(offset, 1); + LL_SHL(offset, offset, 32); + +#ifdef _WIN32 + hFile = CreateFile(TEST_FILE_NAME, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "CreateFile failed\n"); + exit(1); + } + li.QuadPart = offset; + li.LowPart = SetFilePointer(hFile, li.LowPart, &li.HighPart, FILE_BEGIN); + if (li.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR) { + fprintf(stderr, "SetFilePointer failed\n"); + exit(1); + } + PR_ASSERT(li.QuadPart == offset); + strcpy(buf, MESSAGE); + if (WriteFile(hFile, buf, sizeof(buf), &nbytes, NULL) == 0) { + fprintf(stderr, "WriteFile failed\n"); + exit(1); + } + PR_ASSERT(nbytes == sizeof(buf)); + if (CloseHandle(hFile) == 0) { + fprintf(stderr, "CloseHandle failed\n"); + exit(1); + } +#endif /* _WIN32 */ + + memset(buf, 0, sizeof(buf)); + + fd = PR_Open(TEST_FILE_NAME, PR_RDONLY, 0666); + if (fd == NULL) { + fprintf(stderr, "PR_Open failed\n"); + exit(1); + } + position = PR_Seek64(fd, offset, PR_SEEK_SET); + if (!LL_GE_ZERO(position)) { + fprintf(stderr, "PR_Seek64 failed\n"); + exit(1); + } + PR_ASSERT(LL_EQ(position, offset)); + nbytes = PR_Read(fd, buf, sizeof(buf)); + if (nbytes != sizeof(buf)) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + if (strcmp(buf, MESSAGE)) { + fprintf(stderr, "corrupt data:$%s$\n", buf); + exit(1); + } + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_Delete failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/bug1test.c b/nsprpub/pr/tests/bug1test.c new file mode 100644 index 00000000000..fa7d591fcf6 --- /dev/null +++ b/nsprpub/pr/tests/bug1test.c @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +Attached is a test program that uses the nspr1 to demonstrate a bug +under NT4.0. The fix has already been mentioned (add a ResetEvent just +before leaving the critical section in _PR_CondWait in hwmon.c). +*/ + +#include "prthread.h" +#include "prtypes.h" +#include "prinit.h" +#include "prmon.h" +#include "prlog.h" + +typedef struct Arg_s +{ + PRInt32 a, b; +} Arg_t; + +PRMonitor* gMonitor; // the monitor +PRInt32 gReading; // number of read locks +PRInt32 gWriteWaiting; // number of threads waiting for write lock +PRInt32 gReadWaiting; // number of threads waiting for read lock + +PRInt32 gCounter; // a counter + + // stats +PRInt32 gReads; // number of successful reads +PRInt32 gMaxReads; // max number of simultaneous reads +PRInt32 gMaxWriteWaits; // max number of writes that waited for read +PRInt32 gMaxReadWaits; // max number of reads that waited for write wait + + +void spin (PRInt32 aDelay) +{ + PRInt32 index; + PRInt32 delay = aDelay * 1000; + + PR_Sleep(0); + + // randomize delay a bit + delay = (delay / 2) + (PRInt32)((float)delay * + ((float)rand () / (float)RAND_MAX)); + + for (index = 0; index < delay * 10; index++) + // consume a bunch of cpu cycles + ; + PR_Sleep(0); +} + +void doWriteThread (void* arg) +{ + PRInt32 last; + Arg_t *args = (Arg_t*)arg; + PRInt32 aWorkDelay = args->a, aWaitDelay = args->b; + PR_Sleep(0); + + while (1) + { + // -- enter write lock + PR_EnterMonitor (gMonitor); + + if (0 < gReading) // wait for read locks to go away + { + PRIntervalTime fiveSecs = PR_SecondsToInterval(5); + + gWriteWaiting++; + if (gWriteWaiting > gMaxWriteWaits) // stats + gMaxWriteWaits = gWriteWaiting; + while (0 < gReading) + PR_Wait (gMonitor, fiveSecs); + gWriteWaiting--; + } + // -- write lock entered + + last = gCounter; + gCounter++; + + spin (aWorkDelay); + + PR_ASSERT (gCounter == (last + 1)); // test invariance + + // -- exit write lock +// if (0 < gReadWaiting) // notify waiting reads (do it anyway to show off the CondWait bug) + PR_NotifyAll (gMonitor); + + PR_ExitMonitor (gMonitor); + // -- write lock exited + + spin (aWaitDelay); + } +} + +void doReadThread (void* arg) +{ + PRInt32 last; + Arg_t *args = (Arg_t*)arg; + PRInt32 aWorkDelay = args->a, aWaitDelay = args->b; + PR_Sleep(0); + + while (1) + { + // -- enter read lock + PR_EnterMonitor (gMonitor); + + if (0 < gWriteWaiting) // give up the monitor to waiting writes + { + PRIntervalTime fiveSecs = PR_SecondsToInterval(5); + + gReadWaiting++; + if (gReadWaiting > gMaxReadWaits) // stats + gMaxReadWaits = gReadWaiting; + while (0 < gWriteWaiting) + PR_Wait (gMonitor, fiveSecs); + gReadWaiting--; + } + + gReading++; + + gReads++; // stats + if (gReading > gMaxReads) // stats + gMaxReads = gReading; + + PR_ExitMonitor (gMonitor); + // -- read lock entered + + last = gCounter; + + spin (aWorkDelay); + + PR_ASSERT (gCounter == last); // test invariance + + // -- exit read lock + PR_EnterMonitor (gMonitor); // read unlock + gReading--; + +// if ((0 == gReading) && (0 < gWriteWaiting)) // notify waiting writes (do it anyway to show off the CondWait bug) + PR_NotifyAll (gMonitor); + PR_ExitMonitor (gMonitor); + // -- read lock exited + + spin (aWaitDelay); + } +} + + +void fireThread ( + char* aName, void (*aProc)(void *arg), Arg_t *aArg) +{ + PRThread *thread = PR_CreateThread( + PR_USER_THREAD, aProc, aArg, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); +} + +int pseudoMain (int argc, char** argv, char *pad) +{ + PRInt32 lastWriteCount = gCounter; + PRInt32 lastReadCount = gReads; + Arg_t a1 = {500, 250}; + Arg_t a2 = {500, 500}; + Arg_t a3 = {250, 500}; + Arg_t a4 = {750, 250}; + Arg_t a5 = {100, 750}; + Arg_t a6 = {100, 500}; + Arg_t a7 = {100, 750}; + + gMonitor = PR_NewMonitor (); + + fireThread ("R1", doReadThread, &a1); + fireThread ("R2", doReadThread, &a2); + fireThread ("R3", doReadThread, &a3); + fireThread ("R4", doReadThread, &a4); + + fireThread ("W1", doWriteThread, &a5); + fireThread ("W2", doWriteThread, &a6); + fireThread ("W3", doWriteThread, &a7); + + fireThread ("R5", doReadThread, &a1); + fireThread ("R6", doReadThread, &a2); + fireThread ("R7", doReadThread, &a3); + fireThread ("R8", doReadThread, &a4); + + fireThread ("W4", doWriteThread, &a5); + fireThread ("W5", doWriteThread, &a6); + fireThread ("W6", doWriteThread, &a7); + + while (1) + { + PRInt32 writeCount, readCount; + PRIntervalTime fiveSecs = PR_SecondsToInterval(5); + PR_Sleep (fiveSecs); // get out of the way + + // print some stats, not threadsafe, informative only + writeCount = gCounter; + readCount = gReads; + printf ("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]", + writeCount, writeCount - lastWriteCount, + readCount, readCount - lastReadCount, + gMaxReads, gMaxWriteWaits, gMaxReadWaits); + lastWriteCount = writeCount; + lastReadCount = readCount; + gMaxReads = gMaxWriteWaits = gMaxReadWaits = 0; + } + return 0; +} + + +static void padStack (int argc, char** argv) +{ + char pad[512]; /* Work around bug in nspr on windoze */ + pseudoMain (argc, argv, pad); +} + +void main (int argc, char **argv) +{ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + padStack (argc, argv); +} + + +/* bug1test.c */ diff --git a/nsprpub/pr/tests/cleanup.c b/nsprpub/pr/tests/cleanup.c new file mode 100644 index 00000000000..e94979e979b --- /dev/null +++ b/nsprpub/pr/tests/cleanup.c @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prprf.h" +#include "prio.h" +#include "prinit.h" +#include "prthread.h" +#include "prinrval.h" + +#include "plgetopt.h" + +#include + +static void PR_CALLBACK Thread(void *sleep) +{ + PR_Sleep(PR_SecondsToInterval((PRUint32)sleep)); + printf("Thread exiting\n"); +} + +static void Help(void) +{ + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PR_fprintf(err, "Cleanup usage: [-g] [-s n] [-t n] [-c n] [-h]\n"); + PR_fprintf(err, "\t-c Call cleanup before exiting (default: false)\n"); + PR_fprintf(err, "\t-G Use global threads only (default: local)\n"); + PR_fprintf(err, "\t-t n Number of threads involved (default: 1)\n"); + PR_fprintf(err, "\t-s n Seconds thread(s) should dally (defaut: 10)\n"); + PR_fprintf(err, "\t-S n Seconds main() should dally (defaut: 5)\n"); + PR_fprintf(err, "\t-C n Value to set concurrency (default 1)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRBool cleanup = PR_FALSE; + PRThreadScope type = PR_LOCAL_THREAD; + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PLOptState *opt = PL_CreateOptState(argc, argv, "Ghs:S:t:cC:"); + PRIntn concurrency = 1, child_sleep = 10, main_sleep = 5, threads = 1; + + PR_STDIO_INIT(); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'c': /* call PR_Cleanup() before exiting */ + cleanup = PR_TRUE; + break; + case 'G': /* local vs global threads */ + type = PR_GLOBAL_THREAD; + break; + case 's': /* time to sleep */ + child_sleep = atoi(opt->value); + break; + case 'S': /* time to sleep */ + main_sleep = atoi(opt->value); + break; + case 'C': /* number of cpus to create */ + concurrency = atoi(opt->value); + break; + case 't': /* number of threads to create */ + threads = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_fprintf(err, "Cleanup settings\n"); + PR_fprintf(err, "\tThread type: %s\n", + (PR_LOCAL_THREAD == type) ? "LOCAL" : "GLOBAL"); + PR_fprintf(err, "\tConcurrency: %d\n", concurrency); + PR_fprintf(err, "\tNumber of threads: %d\n", threads); + PR_fprintf(err, "\tThread sleep: %d\n", child_sleep); + PR_fprintf(err, "\tMain sleep: %d\n", main_sleep); + PR_fprintf(err, "\tCleanup will %sbe called\n\n", (cleanup) ? "" : "NOT "); + + PR_SetConcurrency(concurrency); + + while (threads-- > 0) + (void)PR_CreateThread( + PR_USER_THREAD, Thread, (void*)child_sleep, PR_PRIORITY_NORMAL, + type, PR_UNJOINABLE_THREAD, 0); + PR_Sleep(PR_SecondsToInterval(main_sleep)); + + if (cleanup) PR_Cleanup(); + + PR_fprintf(err, "main() exiting\n"); + return 0; +} /* main */ diff --git a/nsprpub/pr/tests/cltsrv.c b/nsprpub/pr/tests/cltsrv.c new file mode 100644 index 00000000000..e1f8293944a --- /dev/null +++ b/nsprpub/pr/tests/cltsrv.c @@ -0,0 +1,1224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * + * 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 +#include + + +#if defined(XP_UNIX) +#include +#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 DEFAULT_LOW 0 +#define DEFAULT_HIGH 0 +#define BUFFER_SIZE 1024 +#define DEFAULT_BACKLOG 5 +#define DEFAULT_PORT 12849 +#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 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); + PR_Assert(s, file, ln); +} /* _MY_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), "%H:%M:%S", &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; + PRThread *me = PR_GetCurrentThread(); + CSClient_t *client = (CSClient_t*)arg; + 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 (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + 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_GetCurrentThread())); + 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_GetCurrentThread(), 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_GetCurrentThread(); + 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); + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); + file = NULL; + + 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_GetCurrentThread())); + 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); + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); + file = NULL; + +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 */ + +static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool) +{ + CSWorker_t *worker = PR_NEWZAP(CSWorker_t); + worker->server = server; + PR_INIT_CLIST(&worker->element); + worker->thread = PR_CreateThread( + PR_USER_THREAD, Worker, worker, + DEFAULT_SERVER_PRIORITY, thread_scope, + PR_UNJOINABLE_THREAD, 0); + if (NULL == worker->thread) + { + PR_DELETE(worker); + return PR_FAILURE; + } + + TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, + ("\tCreateWorker(0x%p): create new worker (0x%p)\n", + PR_GetCurrentThread(), worker->thread)); + + return PR_SUCCESS; +} /* CreateWorker */ + +static void PR_CALLBACK Worker(void *arg) +{ + PRStatus rv; + PRNetAddr from; + PRFileDesc *fd = NULL; + PRThread *me = PR_GetCurrentThread(); + CSWorker_t *worker = (CSWorker_t*)arg; + CSServer_t *server = worker->server; + CSPool_t *pool = &server->pool; + + 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_GetCurrentThread(), 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; + PRThread *me = PR_GetCurrentThread(); + CSServer_t *server = (CSServer_t*)arg; + PRSocketOptionData sockOpt; + + server->listener = PR_Socket(domain, SOCK_STREAM, protocol); + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(server->listener, &sockOpt); + TEST_ASSERT(PR_SUCCESS == rv); + + memset(&serverAddress, 0, sizeof(serverAddress)); + if (PR_AF_INET6 != domain) + rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress); + else + rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 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 threads allowed in accept (5)\n"); + PR_fprintf(debug_out, "\t-b backlock for listen (5)\n"); + PR_fprintf(debug_out, "\t-c number of clients to create (1)\n"); + PR_fprintf(debug_out, "\t-f low water mark for fd caching (0)\n"); + PR_fprintf(debug_out, "\t-F high water mark for fd caching (0)\n"); + PR_fprintf(debug_out, "\t-w minimal number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-W maximum number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-e duration of the test in seconds (10)\n"); + PR_fprintf(debug_out, "\t-s dsn name of server (localhost)\n"); + PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n"); + PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n"); + PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n"); + 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; + PRIntn low = DEFAULT_LOW, high = DEFAULT_HIGH; + + /* + * -G use global threads + * -a threads allowed in accept + * -b backlock for listen + * -c number of clients to create + * -f low water mark for caching FDs + * -F high water mark for caching FDs + * -w minimal number of server threads + * -W maximum number of server threads + * -e duration of the test in seconds + * -s dsn name of server (implies no server here) + * -v verbosity + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:f:F:w:W:e:s: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; + case '6': /* Use IPv6 */ + domain = PR_AF_INET6; + break; + case 'a': /* the value for accepting */ + accepting = atoi(opt->value); + break; + case 'b': /* the value for backlock */ + backlog = atoi(opt->value); + break; + 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; + 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_GetCurrentThread()); + + 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 + + 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%p): starting server\n", PR_GetCurrentThread())); + + 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_GetCurrentThread())); + + server->thread = PR_CreateThread( + PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH, + thread_scope, PR_JOINABLE_THREAD, 0); + TEST_ASSERT(NULL != server->thread); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): waiting for server init\n", PR_GetCurrentThread())); + + 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_GetCurrentThread(), 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_GetCurrentThread(), 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) + { + if (PR_AF_INET6 != domain) + (void)PR_InitializeNetAddr( + PR_IpAddrLoopback, DEFAULT_PORT, + &client[index].serverAddress); + else + rv = PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, + 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_GetCurrentThread())); + client[index].thread = PR_CreateThread( + PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + TEST_ASSERT(NULL != client[index].thread); + 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_GetCurrentThread(), execution)); + + WaitForCompletion(execution); + + TimeOfDayMessage("Shutting down", PR_GetCurrentThread()); + + 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_GetCurrentThread(), 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_GetCurrentThread(), client[index].thread)); + + joinStatus = PR_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_GetCurrentThread(), 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_GetCurrentThread(), server->thread)); + joinStatus = PR_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_GetCurrentThread())); + + PT_FPrintStats(debug_out, "\nPThread Statistics\n"); + + TimeOfDayMessage("Test exiting at", PR_GetCurrentThread()); + PR_Cleanup(); + return 0; +} /* main */ + +/* cltsrv.c */ diff --git a/nsprpub/pr/tests/concur.c b/nsprpub/pr/tests/concur.c new file mode 100644 index 00000000000..225b2d28d06 --- /dev/null +++ b/nsprpub/pr/tests/concur.c @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: concur.c +** Description: test of adding and removing concurrency options +*/ + +#include "prcvar.h" +#include "prinit.h" +#include "prinrval.h" +#include "prlock.h" +#include "prprf.h" +#include "prmem.h" +#include "prlog.h" + +#include "plgetopt.h" + +#if defined(XP_MAC) +#include "pprio.h" +#else +#include "private/pprio.h" +#endif + +#include + +#define DEFAULT_RANGE 10 +#define DEFAULT_LOOPS 100 + +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +typedef struct Context +{ + PRLock *ml; + PRCondVar *cv; + PRIntn want, have; +} Context; + + +/* +** Make the instance of 'context' static (not on the stack) +** for Win16 threads +*/ +static Context context = {NULL, NULL, 0, 0}; + +static void PR_CALLBACK Dull(void *arg) +{ + Context *context = (Context*)arg; + PR_Lock(context->ml); + context->have += 1; + while (context->want >= context->have) + PR_WaitCondVar(context->cv, PR_INTERVAL_NO_TIMEOUT); + context->have -= 1; + PR_Unlock(context->ml); +} /* Dull */ + +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:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* GLOBAL threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'd': /* debug mode */ + debug = PR_TRUE; + break; + case 'r': /* range limit */ + range = atoi(opt->value); + break; + case 'l': /* loop counter */ + loops = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == range) range = DEFAULT_RANGE; + if (0 == loops) loops = DEFAULT_LOOPS; + + context.ml = PR_NewLock(); + context.cv = PR_NewCondVar(context.ml); + + if (debug) + 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) + { + PR_SetConcurrency(cpus); + context.want = cpus; + + threads[cpus - 1] = PR_CreateThread( + PR_USER_THREAD, Dull, &context, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + } + + PR_Sleep(hundredMills); + + for (cpus = range; cpus > 0; cpus--) + { + PR_SetConcurrency(cpus); + context.want = cpus - 1; + + PR_Lock(context.ml); + PR_NotifyCondVar(context.cv); + PR_Unlock(context.ml); + } + for(cnt = 0; cnt < range; cnt++) { + rc = PR_JoinThread(threads[cnt]); + PR_ASSERT(rc == PR_SUCCESS); + } + } + + + if (debug) + PR_fprintf( + PR_STDERR, "Waiting for %d thread(s) to exit\n", context.have); + + while (context.have > 0) PR_Sleep(hundredMills); + + if (debug) + PR_fprintf( + PR_STDERR, "Finished [want: %d, have: %d]\n", + context.want, context.have); + + PR_DestroyLock(context.ml); + PR_DestroyCondVar(context.cv); + PR_DELETE(threads); + + PR_fprintf(PR_STDERR, "PASSED\n"); + + return 0; +} /* Concur */ + +PRIntn main(PRIntn argc, char **argv) +{ + PR_STDIO_INIT(); + return PR_Initialize(Concur, argc, argv, 0); +} /* main */ + +/* concur.c */ diff --git a/nsprpub/pr/tests/cvar.c b/nsprpub/pr/tests/cvar.c new file mode 100644 index 00000000000..32d9f1be503 --- /dev/null +++ b/nsprpub/pr/tests/cvar.c @@ -0,0 +1,334 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: cvar.c +** +** Description: Tests Condition Variable Operations +** +** Modification History: +** 13-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + +#include "nspr.h" + +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRMonitor *mon; +#define DEFAULT_COUNT 1000 +PRInt32 count = 0; +PRIntn debug_mode; + +#define kQSIZE 1 + +typedef struct { + PRLock *bufLock; + int startIdx; + int numFull; + PRCondVar *notFull; + PRCondVar *notEmpty; + void *data[kQSIZE]; +} CircBuf; + +static PRBool failed = PR_FALSE; + +/* +** NewCB creates and initializes a new circular buffer. +*/ +static CircBuf* NewCB(void) +{ + CircBuf *cbp; + + cbp = PR_NEW(CircBuf); + if (cbp == NULL) + return (NULL); + + cbp->bufLock = PR_NewLock(); + cbp->startIdx = 0; + cbp->numFull = 0; + cbp->notFull = PR_NewCondVar(cbp->bufLock); + cbp->notEmpty = PR_NewCondVar(cbp->bufLock); + + return (cbp); +} + +/* +** DeleteCB frees a circular buffer. +*/ +static void DeleteCB(CircBuf *cbp) +{ + PR_DestroyLock(cbp->bufLock); + PR_DestroyCondVar(cbp->notFull); + PR_DestroyCondVar(cbp->notEmpty); + PR_DELETE(cbp); +} + + +/* +** PutCBData puts new data on the queue. If the queue is full, it waits +** until there is room. +*/ +static void PutCBData(CircBuf *cbp, void *data) +{ + PR_Lock(cbp->bufLock); + /* wait while the buffer is full */ + while (cbp->numFull == kQSIZE) + PR_WaitCondVar(cbp->notFull,PR_INTERVAL_NO_TIMEOUT); + cbp->data[(cbp->startIdx + cbp->numFull) % kQSIZE] = data; + cbp->numFull += 1; + + /* let a waiting reader know that there is data */ + PR_NotifyCondVar(cbp->notEmpty); + PR_Unlock(cbp->bufLock); + +} + + +/* +** GetCBData gets the oldest data on the queue. If the queue is empty, it waits +** until new data appears. +*/ +static void* GetCBData(CircBuf *cbp) +{ + void *data; + + PR_Lock(cbp->bufLock); + /* wait while the buffer is empty */ + while (cbp->numFull == 0) + PR_WaitCondVar(cbp->notEmpty,PR_INTERVAL_NO_TIMEOUT); + data = cbp->data[cbp->startIdx]; + cbp->startIdx =(cbp->startIdx + 1) % kQSIZE; + cbp->numFull -= 1; + + /* let a waiting writer know that there is room */ + PR_NotifyCondVar(cbp->notFull); + PR_Unlock(cbp->bufLock); + + return (data); +} + + +/************************************************************************/ + +static int alive; + +static void PR_CALLBACK CXReader(void *arg) +{ + CircBuf *cbp = (CircBuf *)arg; + PRInt32 i, n; + void *data; + + n = count / 2; + for (i = 0; i < n; i++) { + data = GetCBData(cbp); + if ((int)data != i) + if (debug_mode) printf("data mismatch at for i = %d usec\n", i); + } + + PR_EnterMonitor(mon); + --alive; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +static void PR_CALLBACK CXWriter(void *arg) +{ + CircBuf *cbp = (CircBuf *)arg; + PRInt32 i, n; + + n = count / 2; + for (i = 0; i < n; i++) + PutCBData(cbp, (void *)i); + + PR_EnterMonitor(mon); + --alive; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +static void CondWaitContextSwitch(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *t1, *t2; + CircBuf *cbp; + + PR_EnterMonitor(mon); + + alive = 2; + + cbp = NewCB(); + + t1 = PR_CreateThread(PR_USER_THREAD, + CXReader, cbp, + PR_PRIORITY_NORMAL, + scope1, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t1); + t2 = PR_CreateThread(PR_USER_THREAD, + CXWriter, cbp, + PR_PRIORITY_NORMAL, + scope2, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t2); + + /* Wait for both of the threads to exit */ + while (alive) { + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + + DeleteCB(cbp); + + PR_ExitMonitor(mon); +} + +static void CondWaitContextSwitchUU(void) +{ + CondWaitContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); +} + +static void CondWaitContextSwitchUK(void) +{ + CondWaitContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); +} + +static void CondWaitContextSwitchKK(void) +{ + CondWaitContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); +} + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("%40s: %6.2f usec\n", msg, d / count); + + if (0 == d) failed = PR_TRUE; +} + +static PRIntn PR_CALLBACK RealMain(int argc, char **argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name [-d] [-c n] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'c': /* loop count */ + count = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == count) count = DEFAULT_COUNT; + +#ifdef XP_MAC + SetupMacPrintfLog("cvar.log"); + debug_mode = 1; +#endif + + mon = PR_NewMonitor(); + + Measure(CondWaitContextSwitchUU, "cond var wait context switch- user/user"); + Measure(CondWaitContextSwitchUK, "cond var wait context switch- user/kernel"); + Measure(CondWaitContextSwitchKK, "cond var wait context switch- kernel/kernel"); + + PR_DestroyMonitor(mon); + + if (debug_mode) printf("%s\n", (failed) ? "FAILED" : "PASSED"); + + if(failed) + return 1; + else + return 0; +} + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/cvar2.c b/nsprpub/pr/tests/cvar2.c new file mode 100644 index 00000000000..4b01cb4bff3 --- /dev/null +++ b/nsprpub/pr/tests/cvar2.c @@ -0,0 +1,1008 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: cvar2.c +** +** Description: Simple test creates several local and global threads; +** half use a single,shared condvar, and the +** other half have their own condvar. The main thread then loops +** notifying them to wakeup. +** +** 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 "nspr.h" +#include "plerror.h" +#include "plgetopt.h" + +#include +#include +#include + +int _debug_on = 0; +#define DPRINTF(arg) if (_debug_on) printf arg + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define DEFAULT_COUNT 100 +#define DEFAULT_THREADS 5 +PRInt32 count = DEFAULT_COUNT; + +typedef struct threadinfo { + PRThread *thread; + PRInt32 id; + PRBool internal; + PRInt32 *tcount; + PRLock *lock; + PRCondVar *cvar; + PRIntervalTime timeout; + PRInt32 loops; + + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *exitcount; +} threadinfo; + +/* +** Make exitcount, tcount static. for Win16. +*/ +static PRInt32 exitcount=0; +static PRInt32 tcount=0; + + +/* Thread that gets notified; many threads share the same condvar */ +void PR_CALLBACK +SharedCondVarThread(void *_info) +{ + threadinfo *info = (threadinfo *)_info; + PRInt32 index; + + for (index=0; indexloops; index++) { + PR_Lock(info->lock); + if (*info->tcount == 0) + PR_WaitCondVar(info->cvar, info->timeout); +#if 0 + printf("shared thread %ld notified in loop %ld\n", info->id, index); +#endif + (*info->tcount)--; + PR_Unlock(info->lock); + + PR_Lock(info->exitlock); + (*info->exitcount)++; + PR_NotifyCondVar(info->exitcvar); + PR_Unlock(info->exitlock); + } +#if 0 + printf("shared thread %ld terminating\n", info->id); +#endif +} + +/* Thread that gets notified; no other threads use the same condvar */ +void PR_CALLBACK +PrivateCondVarThread(void *_info) +{ + threadinfo *info = (threadinfo *)_info; + PRInt32 index; + + for (index=0; indexloops; index++) { + PR_Lock(info->lock); + if (*info->tcount == 0) { + DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n", + PR_GetCurrentThread(), info->cvar)); + PR_WaitCondVar(info->cvar, info->timeout); + } +#if 0 + printf("solo thread %ld notified in loop %ld\n", info->id, index); +#endif + (*info->tcount)--; + PR_Unlock(info->lock); + + PR_Lock(info->exitlock); + (*info->exitcount)++; + PR_NotifyCondVar(info->exitcvar); +DPRINTF(("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = %ld\n", + PR_GetCurrentThread(), info->exitcvar,(*info->exitcount))); + PR_Unlock(info->exitlock); + } +#if 0 + printf("solo thread %ld terminating\n", info->id); +#endif +} + +void +CreateTestThread(threadinfo *info, + PRInt32 id, + PRLock *lock, + PRCondVar *cvar, + PRInt32 loops, + PRIntervalTime timeout, + PRInt32 *tcount, + PRLock *exitlock, + PRCondVar *exitcvar, + PRInt32 *exitcount, + PRBool shared, + PRThreadScope scope) +{ + info->id = id; + info->internal = (shared) ? PR_FALSE : PR_TRUE; + info->lock = lock; + info->cvar = cvar; + info->loops = loops; + info->timeout = timeout; + info->tcount = tcount; + info->exitlock = exitlock; + info->exitcvar = exitcvar; + info->exitcount = exitcount; + info->thread = PR_CreateThread( + PR_USER_THREAD, + shared?SharedCondVarThread:PrivateCondVarThread, + info, + PR_PRIORITY_NORMAL, + scope, + PR_JOINABLE_THREAD, + 0); + if (!info->thread) + PL_PrintError("error creating thread\n"); +} + + +void +CondVarTestSUU(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + + exitcount=0; + tcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg); + exitcount -= arg; + PR_Unlock(exitlock); + } + + /* Join all the threads */ + for(index=0; index<(arg); index++) + PR_JoinThread(list[index].thread); + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); +} + +void +CondVarTestSUK(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + exitcount=0; + tcount=0; + + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg); + exitcount -= arg; + PR_Unlock(exitlock); +#if 0 + printf("threads ready\n"); +#endif + } + + /* Join all the threads */ + for(index=0; index<(arg); index++) + PR_JoinThread(list[index].thread); + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); +} + +void +CondVarTestPUU(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *tcount, *saved_tcount; + + exitcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg); + exitcount -= arg; + PR_Unlock(exitlock); + } + + /* Join all the threads */ + for(index=0; index<(arg); index++) { + DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n",list[index].thread)); + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); + PR_DELETE(saved_tcount); +} + +void +CondVarTestPUK(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *tcount, *saved_tcount; + + exitcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg); + exitcount -= arg; + PR_Unlock(exitlock); + } + + /* Join all the threads */ + for(index=0; index<(arg); index++) { + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); + PR_DELETE(saved_tcount); +} + +void +CondVarTest(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *ptcount, *saved_ptcount; + + exitcount=0; + tcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + saved_ptcount = ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg*4); + exitcount -= arg*4; + PR_Unlock(exitlock); +#if 0 + printf("threads ready\n"); +#endif + } + + /* Join all the threads */ + for(index=0; index<(arg*4); index++) { + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); + PR_DELETE(saved_ptcount); +} + +void +CondVarTimeoutTest(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg*4); + exitcount -= arg*4; + PR_Unlock(exitlock); + } + + + /* Join all the threads */ + for(index=0; index<(arg*4); index++) { + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); +} + +void +CondVarMixedTest(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *ptcount; + + exitcount=0; + tcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg*4); + exitcount -= arg*4; + PR_Unlock(exitlock); + } + + /* Join all the threads */ + for(index=0; index<(arg*4); index++) { + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + + PR_DELETE(list); +} + +void +CondVarCombinedTest(void *arg) +{ + PRThread *threads[3]; + + threads[0] = PR_CreateThread(PR_USER_THREAD, + CondVarTest, + (void *)arg, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + threads[1] = PR_CreateThread(PR_USER_THREAD, + CondVarTimeoutTest, + (void *)arg, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + threads[2] = PR_CreateThread(PR_USER_THREAD, + CondVarMixedTest, + (void *)arg, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + PR_JoinThread(threads[0]); + PR_JoinThread(threads[1]); + PR_JoinThread(threads[2]); +} + +/************************************************************************/ + +static void Measure(void (*func)(void *), PRInt32 arg, const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)((void *)arg); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + printf("%40s: %6.2f usec\n", msg, d / count); +} + +static PRIntn PR_CALLBACK RealMain(int argc, char **argv) +{ + PRInt32 threads, default_threads = DEFAULT_THREADS; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "vc:t:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'v': /* debug mode */ + _debug_on = 1; + break; + case 'c': /* loop counter */ + count = atoi(opt->value); + break; + case 't': /* number of threads involved */ + default_threads = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == count) count = DEFAULT_COUNT; + if (0 == default_threads) default_threads = DEFAULT_THREADS; + +#ifdef XP_MAC + SetupMacPrintfLog("cvar2.log"); +#endif + + printf("\n\ +CondVar Test: \n\ + \n\ +Simple test creates several local and global threads; half use a single,\n\ +shared condvar, and the other half have their own condvar. The main \n\ +thread then loops notifying them to wakeup. \n\ + \n\ +The timeout test is very similar except that the threads are not \n\ +notified. They will all wakeup on a 1 second timeout. \n\ + \n\ +The mixed test combines the simple test and the timeout test; every \n\ +third thread is notified, the other threads are expected to timeout \n\ +correctly. \n\ + \n\ +Lastly, the combined test creates a thread for each of the above three \n\ +cases and they all run simultaneously. \n\ + \n\ +This test is run with %d, %d, %d, and %d threads of each type.\n\n", +default_threads, default_threads*2, default_threads*3, default_threads*4); + + PR_SetConcurrency(2); + + for (threads = default_threads; threads < default_threads*5; threads+=default_threads) { + printf("\n%ld Thread tests\n", threads); + Measure(CondVarTestSUU, threads, "Condvar simple test shared UU"); + Measure(CondVarTestSUK, threads, "Condvar simple test shared UK"); + Measure(CondVarTestPUU, threads, "Condvar simple test priv UU"); + Measure(CondVarTestPUK, threads, "Condvar simple test priv UK"); +#ifdef XP_MAC + /* Mac heaps can't handle thread*4 stack allocations at a time for (10, 15, 20)*4 */ + Measure(CondVarTest, 5, "Condvar simple test All"); + Measure(CondVarTimeoutTest, 5, "Condvar timeout test"); +#else + Measure(CondVarTest, threads, "Condvar simple test All"); + Measure(CondVarTimeoutTest, threads, "Condvar timeout test"); +#endif +#if 0 + Measure(CondVarMixedTest, threads, "Condvar mixed timeout test"); + Measure(CondVarCombinedTest, threads, "Combined condvar test"); +#endif + } + + printf("PASS\n"); + + return 0; +} + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/dbmalloc.c b/nsprpub/pr/tests/dbmalloc.c new file mode 100644 index 00000000000..4295d0c0e4a --- /dev/null +++ b/nsprpub/pr/tests/dbmalloc.c @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: dbmalloc.c +** +** Description: Testing malloc (OBSOLETE) +** +** 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 +#include +#include +#include +#include "nspr.h" + +void +usage +( + void +) +{ + fprintf(stderr, "Usage: dbmalloc ('-m'|'-s') '-f' num_fails ('-d'|'-n') filename [...]\n"); + exit(0); +} + +typedef struct node_struct +{ + struct node_struct *next, *prev; + int line; + char value[4]; +} + node_t, + *node_pt; + +node_pt get_node(const char *line) +{ + node_pt rv; + int l = strlen(line); + rv = (node_pt)PR_MALLOC(sizeof(node_t) + l + 1 - 4); + if( (node_pt)0 == rv ) return (node_pt)0; + memcpy(&rv->value[0], line, l+1); + rv->next = rv->prev = (node_pt)0; + return rv; +} + +void +dump +( + const char *name, + node_pt node, + int mf, + int debug +) +{ + if( (node_pt)0 != node->prev ) dump(name, node->prev, mf, debug); + if( 0 != debug ) printf("[%s]: %6d: %s", name, node->line, node->value); + if( node->line == mf ) fprintf(stderr, "[%s]: Line %d was allocated!\n", name, node->line); + if( (node_pt)0 != node->next ) dump(name, node->next, mf, debug); + return; +} + +void +release +( + node_pt node +) +{ + if( (node_pt)0 != node->prev ) release(node->prev); + if( (node_pt)0 != node->next ) release(node->next); + PR_DELETE(node); +} + +int +t2 +( + const char *name, + int mf, + int debug +) +{ + int rv; + FILE *fp; + int l = 0; + node_pt head = (node_pt)0; + char buffer[ BUFSIZ ]; + + fp = fopen(name, "r"); + if( (FILE *)0 == fp ) + { + fprintf(stderr, "[%s]: Cannot open \"%s.\"\n", name, name); + return -1; + } + + /* fgets mallocs a buffer, first time through. */ + if( (char *)0 == fgets(buffer, BUFSIZ, fp) ) + { + fprintf(stderr, "[%s]: \"%s\" is empty.\n", name, name); + (void)fclose(fp); + return -1; + } + + rewind(fp); + + if( PR_SUCCESS != PR_ClearMallocCount() ) + { + fprintf(stderr, "[%s]: Cannot clear malloc count.\n", name); + (void)fclose(fp); + return -1; + } + + if( PR_SUCCESS != PR_SetMallocCountdown(mf) ) + { + fprintf(stderr, "[%s]: Cannot set malloc countdown to %d\n", name, mf); + (void)fclose(fp); + return -1; + } + + while( fgets(buffer, BUFSIZ, fp) ) + { + node_pt n; + node_pt *w = &head; + + if( (strlen(buffer) == (BUFSIZ-1)) && (buffer[BUFSIZ-2] != '\n') ) + buffer[BUFSIZ-2] == '\n'; + + l++; + + n = get_node(buffer); + if( (node_pt)0 == n ) + { + printf("[%s]: Line %d: malloc failure!\n", name, l); + continue; + } + + n->line = l; + + while( 1 ) + { + int comp; + + if( (node_pt)0 == *w ) + { + *w = n; + break; + } + + comp = strcmp((*w)->value, n->value); + if( comp < 0 ) w = &(*w)->next; + else w = &(*w)->prev; + } + } + + (void)fclose(fp); + + dump(name, head, mf, debug); + + rv = PR_GetMallocCount(); + PR_ClearMallocCountdown(); + + release(head); + + return rv; +} + +int nf = 0; +int debug = 0; + +void +test +( + const char *name +) +{ + int n, i; + + extern int nf, debug; + + printf("[%s]: starting test 0\n", name); + n = t2(name, 0, debug); + if( -1 == n ) return; + printf("[%s]: test 0 had %ld allocations.\n", name, n); + + if( 0 >= n ) return; + + for( i = 0; i < nf; i++ ) + { + int which = rand() % n; + if( 0 == which ) printf("[%s]: starting test %d -- no allocation should fail\n", name, i+1); + else printf("[%s]: starting test %d -- allocation %d should fail\n", name, i+1, which); + (void)t2(name, which, debug); + printf("[%s]: test %d done.\n", name, i+1); + } + + return; +} + +int +main +( + int argc, + char *argv[] +) +{ + int okay = 0; + int multithread = 0; + + struct threadlist + { + struct threadlist *next; + PRThread *thread; + } + *threadhead = (struct threadlist *)0; + + extern int nf, debug; + + srand(time(0)); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + printf("[main]: We %s using the debugging malloc.\n", + PR_IsDebuggingMalloc() ? "ARE" : "ARE NOT"); + + while( argv++, --argc ) + { + if( '-' == argv[0][0] ) + { + switch( argv[0][1] ) + { + case 'f': + nf = atoi(argv[0][2] ? &argv[0][2] : + --argc ? *++argv : "0"); + break; + case 'd': + debug = 1; + break; + case 'n': + debug = 0; + break; + case 'm': + multithread = 1; + break; + case 's': + multithread = 0; + break; + default: + usage(); + break; + } + } + else + { + FILE *fp = fopen(*argv, "r"); + if( (FILE *)0 == fp ) + { + fprintf(stderr, "Cannot open \"%s.\"\n", *argv); + continue; + } + + okay++; + (void)fclose(fp); + if( multithread ) + { + struct threadlist *n; + + n = (struct threadlist *)malloc(sizeof(struct threadlist)); + if( (struct threadlist *)0 == n ) + { + fprintf(stderr, "This is getting tedious. \"%s\"\n", *argv); + continue; + } + + n->next = threadhead; + n->thread = PR_CreateThread(PR_USER_THREAD, (void (*)(void *))test, + *argv, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, + 0); + if( (PRThread *)0 == n->thread ) + { + fprintf(stderr, "Can't create thread for \"%s.\"\n", *argv); + continue; + } + else + { + threadhead = n; + } + } + else + { + test(*argv); + } + } + } + + if( okay == 0 ) usage(); + else while( (struct threadlist *)0 != threadhead ) + { + struct threadlist *x = threadhead->next; + (void)PR_JoinThread(threadhead->thread); + PR_DELETE(threadhead); + threadhead = x; + } + + return 0; +} + diff --git a/nsprpub/pr/tests/dbmalloc1.c b/nsprpub/pr/tests/dbmalloc1.c new file mode 100644 index 00000000000..ca1b4cb1d03 --- /dev/null +++ b/nsprpub/pr/tests/dbmalloc1.c @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c (OBSOLETE) +** +** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions. +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** +** 12-June-97 AGarcia Revert to return code 0 and 1, remove debug option (obsolete). +***********************************************************************/ + + +/*********************************************************************** +** Includes +***********************************************************************/ +#include +#include +#include "nspr.h" + +PRIntn failed_already=0; +PRIntn debug_mode; + +/* variable used for both r1 and r2 tests */ +int should_fail =0; +int actually_failed=0; + + +void +r1 +( + void +) +{ + int i; + actually_failed=0; + for( i = 0; i < 5; i++ ) + { + void *x = PR_MALLOC(128); + if( (void *)0 == x ) { + if (debug_mode) printf("\tMalloc %d failed.\n", i+1); + actually_failed = 1; + } + PR_DELETE(x); + } + + if (((should_fail != actually_failed) & (!debug_mode))) failed_already=1; + + + return; +} + +void +r2 +( + void +) +{ + int i; + + for( i = 0; i <= 5; i++ ) + { + should_fail =0; + if( 0 == i ) { + if (debug_mode) printf("No malloc should fail:\n"); + } + else { + if (debug_mode) printf("Malloc %d should fail:\n", i); + should_fail = 1; + } + PR_SetMallocCountdown(i); + r1(); + PR_ClearMallocCountdown(); + } +} + +int +main +( + int argc, + char *argv[] +) +{ + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + r2(); + + if(failed_already) + return 1; + else + return 0; + + +} + diff --git a/nsprpub/pr/tests/dceemu.c b/nsprpub/pr/tests/dceemu.c new file mode 100644 index 00000000000..bc037c83bce --- /dev/null +++ b/nsprpub/pr/tests/dceemu.c @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: dceemu.c +** Description: testing the DCE emulation api +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1, remove debug option (obsolete). +**/ + +/*********************************************************************** +** Includes +***********************************************************************/ + + +#if defined(_PR_DCETHREADS) + +#include "prlog.h" +#include "prinit.h" +#include "prpdce.h" + +#include +#include +PRIntn failed_already=0; +PRIntn debug_mode=0; + +static PRIntn prmain(PRIntn argc, char **argv) +{ + PRStatus rv; + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PRP_NewNakedCondVar(); + PRIntervalTime tenmsecs = PR_MillisecondsToInterval(10); + + rv = PRP_TryLock(ml); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + rv = PRP_TryLock(ml); + PR_ASSERT(PR_FAILURE == rv); + if ((rv != PR_FAILURE) & (!debug_mode)) failed_already=1; + + rv = PRP_NakedNotify(cv); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + rv = PRP_NakedBroadcast(cv); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + rv = PRP_NakedWait(cv, ml, tenmsecs); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + PR_Unlock(ml); + + rv = PRP_NakedNotify(cv); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + rv = PRP_NakedBroadcast(cv); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + PRP_DestroyNakedCondVar(cv); + PR_DestroyLock(ml); + + if (debug_mode) printf("Test succeeded\n"); + + return 0; + +} /* prmain */ + +#endif /* #if defined(_PR_DCETHREADS) */ + +int main(int argc, char **argv) +{ + +#if defined(_PR_DCETHREADS) + PR_Initialize(prmain, argc, argv, 0); + if(failed_already) + return 1; + else + return 0; +#else + return 0; +#endif +} /* main */ + + +/* decemu.c */ diff --git a/nsprpub/pr/tests/depend.c b/nsprpub/pr/tests/depend.c new file mode 100644 index 00000000000..e3fb691e51e --- /dev/null +++ b/nsprpub/pr/tests/depend.c @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** +** Name: depend.c +** Description: Test to enumerate the dependencies +* +** 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 "prinit.h" + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include + +static void PrintVersion( + const char *msg, const PRVersion* info, PRIntn tab) +{ + static const len = 20; + static const char *tabs = {" "}; + + tab *= 2; + if (tab > len) tab = len; + printf("%s", &tabs[len - tab]); + printf("%s ", msg); + printf("%s ", info->id); + printf("%d.%d", info->major, info->minor); + if (0 != info->patch) + printf(".p%d", info->patch); + printf("\n"); +} /* PrintDependency */ + +static void ChaseDependents(const PRVersionInfo *info, PRIntn tab) +{ + PrintVersion("exports", &info->selfExport, tab); + if (NULL != info->importEnumerator) + { + const PRDependencyInfo *dependent = NULL; + while (NULL != (dependent = info->importEnumerator(dependent))) + { + const PRVersionInfo *import = dependent->exportInfoFn(); + PrintVersion("imports", &dependent->importNeeded, tab); + ChaseDependents(import, tab + 1); + } + } +} /* ChaseDependents */ + +static PRVersionInfo hack_export; +static PRVersionInfo dummy_export; +static PRDependencyInfo dummy_imports[2]; + +static const PRVersionInfo *HackExportInfo(void) +{ + hack_export.selfExport.major = 11; + hack_export.selfExport.minor = 10; + hack_export.selfExport.patch = 200; + hack_export.selfExport.id = "Hack"; + hack_export.importEnumerator = NULL; + return &hack_export; +} + +static const PRDependencyInfo *DummyImports( + const PRDependencyInfo *previous) +{ + if (NULL == previous) return &dummy_imports[0]; + else if (&dummy_imports[0] == previous) return &dummy_imports[1]; + else if (&dummy_imports[1] == previous) return NULL; +} /* DummyImports */ + +static const PRVersionInfo *DummyLibVersion(void) +{ + dummy_export.selfExport.major = 1; + dummy_export.selfExport.minor = 0; + dummy_export.selfExport.patch = 0; + dummy_export.selfExport.id = "Dumbass application"; + dummy_export.importEnumerator = DummyImports; + + dummy_imports[0].importNeeded.major = 2; + dummy_imports[0].importNeeded.minor = 0; + dummy_imports[0].importNeeded.patch = 0; + dummy_imports[0].importNeeded.id = "Netscape Portable Runtime"; + dummy_imports[0].exportInfoFn = PR_ExportInfo; + + dummy_imports[1].importNeeded.major = 5; + dummy_imports[1].importNeeded.minor = 1; + dummy_imports[1].importNeeded.patch = 2; + dummy_imports[1].importNeeded.id = "Hack Library"; + dummy_imports[1].exportInfoFn = HackExportInfo; + + return &dummy_export; +} /* DummyLibVersion */ + +int main(int argc, char **argv) +{ + PRIntn tab = 0; + const PRVersionInfo *info = DummyLibVersion(); + const char *buildDate = __DATE__, *buildTime = __TIME__; + + printf("Depend.c build time is %s %s\n", buildDate, buildTime); + + if (NULL != info) ChaseDependents(info, tab); + + return 0; +} /* main */ + +/* depend.c */ diff --git a/nsprpub/pr/tests/dll/.cvsignore b/nsprpub/pr/tests/dll/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/pr/tests/dll/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/pr/tests/dll/Makefile.in b/nsprpub/pr/tests/dll/Makefile.in new file mode 100644 index 00000000000..da2ae5a9241 --- /dev/null +++ b/nsprpub/pr/tests/dll/Makefile.in @@ -0,0 +1,116 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +CSRCS = mygetval.c mysetval.c + +INCLUDES = -I$(dist_includedir) + +OBJS = $(OBJDIR)/mygetval.$(OBJ_SUFFIX) \ + $(OBJDIR)/mysetval.$(OBJ_SUFFIX) + +ifeq ($(OS_TARGET), WIN16) +W16OBJS = $(subst $(space),$(comma)$(space),$(OBJS)) +endif + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) +# do nothing +else +RES=$(OBJDIR)/my.res +RESNAME=../../../pr/src/nspr.rc +endif +endif + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +IMPORT_LIBRARY = $(OBJDIR)/my.$(LIB_SUFFIX) +SHARED_LIBRARY = $(OBJDIR)/my.dll +ifeq ($(OS_ARCH), OS2) +MAPFILE = $(OBJDIR)/my.def +GARBAGE += $(MAPFILE) +MKSHLIB += $(MAPFILE) +endif +TARGETS = $(SHARED_LIBRARY) $(IMPORT_LIBRARY) +else +ifdef MKSHLIB +SHARED_LIBRARY = $(OBJDIR)/libmy.$(DLL_SUFFIX) +endif +TARGETS = $(SHARED_LIBRARY) +endif + +# +# To create a loadable module on Darwin, we must override +# -dynamiclib with -bundle. +# +ifeq ($(OS_ARCH),Darwin) +DSO_LDOPTS = -bundle +endif + +include $(topsrcdir)/config/rules.mk + +ifeq ($(OS_TARGET), WIN16) +# Note: The Win16 target: my.dll requires these macros +# to be overridden to build the test .dll +# default values in win16...mk are for release targets. +# +OS_DLL_OPTION = NOCASEEXACT +OS_LIB_FLAGS = -irn +endif + +ifdef SHARED_LIBRARY +export:: $(TARGETS) + +clean:: + rm -rf $(TARGETS) +endif diff --git a/nsprpub/pr/tests/dll/my.def b/nsprpub/pr/tests/dll/my.def new file mode 100644 index 00000000000..76cdfd96f0b --- /dev/null +++ b/nsprpub/pr/tests/dll/my.def @@ -0,0 +1,58 @@ +;+# +;+# ***** BEGIN LICENSE BLOCK ***** +;+# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +;+# +;+# The contents of this file are subject to the Mozilla Public License Version +;+# 1.1 (the "License"); you may not use this file except in compliance with +;+# the License. You may obtain a copy of the License at +;+# http://www.mozilla.org/MPL/ +;+# +;+# Software distributed under the License is distributed on an "AS IS" basis, +;+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +;+# for the specific language governing rights and limitations under the +;+# License. +;+# +;+# The Original Code is the Netscape Portable Runtime (NSPR). +;+# +;+# The Initial Developer of the Original Code is +;+# Netscape Communications Corporation. +;+# Portions created by the Initial Developer are Copyright (C) 2002-2003 +;+# the Initial Developer. All Rights Reserved. +;+# +;+# Contributor(s): +;+# +;+# Alternatively, the contents of this file may be used under the terms of +;+# either the GNU General Public License Version 2 or later (the "GPL"), or +;+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +;+# in which case the provisions of the GPL or the LGPL are applicable instead +;+# of those above. If you wish to allow use of your version of this file only +;+# under the terms of either the GPL or the LGPL, and not to allow others to +;+# use your version of this file under the terms of the MPL, indicate your +;+# decision by deleting the provisions above and replace them with the notice +;+# and other provisions required by the GPL or the LGPL. If you do not delete +;+# the provisions above, a recipient may use your version of this file under +;+# the terms of any one of the MPL, the GPL or the LGPL. +;+# +;+# ***** END LICENSE BLOCK ***** +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+# +;+MY_1.0 { +;+ global: +LIBRARY my ;- +EXPORTS ;- + My_GetValue; + My_SetValue; +;+ local: *; +;+}; diff --git a/nsprpub/pr/tests/dll/mygetval.c b/nsprpub/pr/tests/dll/mygetval.c new file mode 100644 index 00000000000..17f36792837 --- /dev/null +++ b/nsprpub/pr/tests/dll/mygetval.c @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#if defined(WIN16) +#include +#endif +#include "prtypes.h" + +extern PRIntn my_global; + +PR_IMPLEMENT(PRIntn) My_GetValue() +{ + return my_global; +} + +#if defined(WIN16) +int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpszCmdLine ) +{ + return TRUE; +} +#endif /* WIN16 */ + diff --git a/nsprpub/pr/tests/dll/mysetval.c b/nsprpub/pr/tests/dll/mysetval.c new file mode 100644 index 00000000000..982f0776541 --- /dev/null +++ b/nsprpub/pr/tests/dll/mysetval.c @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prtypes.h" + +PRIntn my_global = 0; + +PR_IMPLEMENT(void) My_SetValue(PRIntn val) +{ + my_global = val; +} diff --git a/nsprpub/pr/tests/dlltest.c b/nsprpub/pr/tests/dlltest.c new file mode 100644 index 00000000000..f8a5f53b8b2 --- /dev/null +++ b/nsprpub/pr/tests/dlltest.c @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: dlltest.c +** +** Description: test dll functionality. +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +#include "prinit.h" +#include "prlink.h" +#include "prmem.h" +#include "prerror.h" + +#include "plstr.h" + +#include +#include + +typedef PRIntn (PR_CALLBACK *GetFcnType)(void); +typedef void (PR_CALLBACK *SetFcnType)(PRIntn); + +PRIntn failed_already=0; +PRIntn debug_mode; + +int main(int argc, char** argv) +{ + PRLibrary *lib, *lib2; /* two handles to the same library */ + GetFcnType getFcn; + SetFcnType setFcn; + PRIntn value; + PRStatus status; + char *libName; + + if (argc >= 2 && PL_strcmp(argv[1], "-d") == 0) { + debug_mode = 1; + } + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + /* + * Test 1: load the library, look up the symbols, call the functions, + * and check the results. + */ + + libName = PR_GetLibraryName("dll", "my"); + if (debug_mode) printf("Loading library %s\n", libName); + lib = PR_LoadLibrary(libName); + PR_FreeLibraryName(libName); + if (lib == NULL) { + PRInt32 textLength = PR_GetErrorTextLength(); + char *text = (char*)PR_MALLOC(textLength); + (void)PR_GetErrorText(text); + fprintf( + stderr, "PR_LoadLibrary failed (%d, %d, %s)\n", + PR_GetError(), PR_GetOSError(), text); + if (!debug_mode) failed_already=1; + } + getFcn = (GetFcnType) PR_FindSymbol(lib, "My_GetValue"); + setFcn = (SetFcnType) PR_FindFunctionSymbol(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; + } + if (debug_mode) printf("Test 1 passed\n"); + + /* + * Test 2: get a second handle to the same library (this should increment + * the reference count), look up the symbols, call the functions, and + * check the results. + */ + + getFcn = (GetFcnType) PR_FindSymbolAndLibrary("My_GetValue", &lib2); + 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; + } + (*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; + } + if (debug_mode) printf("Test 2 passed\n"); + + /* + * Test 3: unload the library. The library should still be accessible + * via the second handle. do the same things as above. + */ + + 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; + } + getFcn = (GetFcnType) PR_FindFunctionSymbol(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; + } + if (debug_mode) printf("Test 3 passed\n"); + + /* + * Test 4: unload the library, testing the reference count mechanism. + */ + + 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; + } + getFcn = (GetFcnType) PR_FindFunctionSymbolAndLibrary("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"); + } + + /* + ** Test 5: LoadStaticLibrary() + */ + { + PRStaticLinkTable slt[10]; + PRLibrary *lib; + + lib = PR_LoadStaticLibrary( "my.dll", slt ); + if ( lib == NULL ) + { + fprintf(stderr, "Test 5: LoadStatiLibrary() failed\n" ); + goto exit_now; + } + if (debug_mode) + { + printf("Test 5 passed\n"); + } + } + + goto exit_now; +exit_now: + PR_Cleanup(); + + if (failed_already) { + printf("FAILED\n"); + return 1; + } else { + printf("PASSED\n"); + return 0; + } +} diff --git a/nsprpub/pr/tests/dtoa.c b/nsprpub/pr/tests/dtoa.c new file mode 100644 index 00000000000..a9258c02799 --- /dev/null +++ b/nsprpub/pr/tests/dtoa.c @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/****************************************************************************** + * + * This file contains a test program for the function conversion functions + * for double precision code: + * PR_strtod + * PR_dtoa + * PR_cnvtf + * + * This file was ns/nspr/tests/dtoa.c, created by rrj on 1996/06/22. + * + *****************************************************************************/ +#include +#include +#include +#include +#include "prprf.h" +#include "prdtoa.h" + +static int failed_already = 0; + +int main( int argc, char* argv[] ) +{ + double num; + double num1; + double zero = 0.0; + char cnvt[50]; + + num = 1e24; + num1 = PR_strtod("1e24",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","1e24"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("1e+24",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = 0.001e7; + num1 = PR_strtod("0.001e7",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","0.001e7"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("10000",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = 0.0000000000000753; + num1 = PR_strtod("0.0000000000000753",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n", + "0.0000000000000753"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("7.53e-14",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = 1.867e73; + num1 = PR_strtod("1.867e73",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","1.867e73"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("1.867e+73",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + + num = -1.867e73; + num1 = PR_strtod("-1.867e73",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e73"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("-1.867e+73",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = -1.867e-73; + num1 = PR_strtod("-1.867e-73",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e-73"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("-1.867e-73",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + /* Testing for infinity */ + num = 1.0 / zero; + num1 = PR_strtod("1.867e765",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","1.867e765"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("Infinity",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = -1.0 / zero; + num1 = PR_strtod("-1.867e765",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e765"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("-Infinity",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + /* Testing for NaN. PR_strtod can't parse "NaN" and "Infinity" */ + num = zero / zero; + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("NaN",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = - zero / zero; + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("NaN",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = 1.0000000001e21; + num1 = PR_strtod("1.0000000001e21",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n", + "1.0000000001e21"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("1.0000000001e+21",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + + num = -1.0000000001e-21; + num1 = PR_strtod("-1.0000000001e-21",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n", + "-1.0000000001e-21"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("-1.0000000001e-21",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + if (failed_already) { + printf("FAILED\n"); + } else { + printf("PASSED\n"); + } + return failed_already; +} diff --git a/nsprpub/pr/tests/env.c b/nsprpub/pr/tests/env.c new file mode 100644 index 00000000000..ff2ba93702a --- /dev/null +++ b/nsprpub/pr/tests/env.c @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: env.c +** Description: Testing environment variable operations +** +*/ +#include "prenv.h" +#include "plgetopt.h" + +#include +#include +#include + +PRIntn debug = 0; +PRIntn verbose = 0; +PRBool failedAlready = PR_FALSE; + +#define ENVNAME "NSPR_ENVIRONMENT_TEST_VARIABLE" +#define ENVVALUE "The expected result" +#define ENVBUFSIZE 256 + +char *envBuf; /* buffer pointer. We leak memory here on purpose! */ + +static char * NewBuffer( size_t size ) +{ + char *buf = malloc( size ); + if ( NULL == buf ) { + printf("env: NewBuffer() failed\n"); + exit(1); + } + return(buf); +} /* end NewBuffer() */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + char *value; + PRStatus rc; + + { /* Get command line options */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "vd"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + break; + case 'v': /* verbose */ + verbose = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } /* end block "Get command line options" */ + +#if 0 + { + /* + ** This uses Windows native environment manipulation + ** as an experiment. Note the separation of namespace! + */ + BOOL rv; + DWORD size; + rv = SetEnvironmentVariable( ENVNAME, ENVVALUE ); + if ( rv == 0 ) { + if (debug) printf("env: Shit! SetEnvironmentVariable() failed\n"); + failedAlready = PR_TRUE; + } + if (verbose) printf("env: SetEnvironmentVariable() worked\n"); + + size = GetEnvironmentVariable( ENVNAME, envBuf, ENVBUFSIZE ); + if ( size == 0 ) { + if (debug) printf("env: Shit! GetEnvironmentVariable() failed. Found: %s\n", envBuf ); + failedAlready = PR_TRUE; + } + if (verbose) printf("env: GetEnvironmentVariable() worked. Found: %s\n", envBuf); + + value = PR_GetEnv( ENVNAME ); + if ( (NULL == value ) || (strcmp( value, ENVVALUE))) { + if (debug) printf( "env: PR_GetEnv() failed retrieving WinNative. Found: %s\n", value); + failedAlready = PR_TRUE; + } + if (verbose) printf("env: PR_GetEnv() worked. Found: %s\n", value); + } +#endif + + /* set an environment variable, read it back */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME "=" ENVVALUE ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (debug) printf( "env: PR_SetEnv() failed setting\n"); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_SetEnv() worked.\n"); + } + + value = PR_GetEnv( ENVNAME ); + if ( (NULL == value ) || (strcmp( value, ENVVALUE))) { + if (debug) printf( "env: PR_GetEnv() Failed after setting\n" ); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_GetEnv() worked after setting it. Found: %s\n", value ); + } + +/* ---------------------------------------------------------------------- */ + /* un-set the variable, using RAW name... should not work */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (verbose) printf( "env: PR_SetEnv() not un-set using RAW name. Good!\n"); + } else { + if (debug) printf("env: PR_SetEnv() un-set using RAW name. Bad!\n" ); + failedAlready = PR_TRUE; + } + + value = PR_GetEnv( ENVNAME ); + if ( NULL == value ) { + if (debug) printf("env: PR_GetEnv() after un-set using RAW name. Bad!\n" ); + failedAlready = PR_TRUE; + } else { + if (verbose) printf( "env: PR_GetEnv() after RAW un-set found: %s\n", value ); + } + +/* ---------------------------------------------------------------------- */ + /* set it again ... */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME "=" ENVVALUE ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (debug) printf( "env: PR_SetEnv() failed setting the second time.\n"); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_SetEnv() worked.\n"); + } + + /* un-set the variable using the form name= */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME "=" ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (debug) printf( "env: PR_SetEnv() failed un-setting using name=\n"); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_SetEnv() un-set using name= worked\n" ); + } + + value = PR_GetEnv( ENVNAME ); + if (( NULL == value ) || ( 0x00 == *value )) { + if (verbose) printf("env: PR_GetEnv() after un-set using name= worked\n" ); + } else { + if (debug) printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value ); + failedAlready = PR_TRUE; + } +/* ---------------------------------------------------------------------- */ + /* un-set the variable using the form name= */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME "999=" ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (debug) printf( "env: PR_SetEnv() failed un-setting using name=\n"); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_SetEnv() un-set using name= worked\n" ); + } + + value = PR_GetEnv( ENVNAME "999" ); + if (( NULL == value ) || ( 0x00 == *value )) { + if (verbose) printf("env: PR_GetEnv() after un-set using name= worked\n" ); + } else { + if (debug) printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value ); + failedAlready = PR_TRUE; + } + +/* ---------------------------------------------------------------------- */ + if (debug || verbose) printf("\n%s\n", (failedAlready)? "FAILED" : "PASSED" ); + return( (failedAlready)? 1 : 0 ); +} /* main() */ + +/* env.c */ diff --git a/nsprpub/pr/tests/errcodes.c b/nsprpub/pr/tests/errcodes.c new file mode 100644 index 00000000000..76156848fee --- /dev/null +++ b/nsprpub/pr/tests/errcodes.c @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: errcodes.c +** +** Description: print nspr error codes +** +*/ +#include "prerror.h" +#include "plgetopt.h" + +#include + +static int _debug_on = 0; + +struct errinfo { + PRErrorCode errcode; + char *errname; +}; + +struct errinfo errcodes[] = { +{PR_OUT_OF_MEMORY_ERROR, "PR_OUT_OF_MEMORY_ERROR"}, +{PR_BAD_DESCRIPTOR_ERROR, "PR_BAD_DESCRIPTOR_ERROR"}, +{PR_WOULD_BLOCK_ERROR, "PR_WOULD_BLOCK_ERROR"}, +{PR_ACCESS_FAULT_ERROR, "PR_ACCESS_FAULT_ERROR"}, +{PR_INVALID_METHOD_ERROR, "PR_INVALID_METHOD_ERROR"}, +{PR_ILLEGAL_ACCESS_ERROR, "PR_ILLEGAL_ACCESS_ERROR"}, +{PR_UNKNOWN_ERROR, "PR_UNKNOWN_ERROR"}, +{PR_PENDING_INTERRUPT_ERROR, "PR_PENDING_INTERRUPT_ERROR"}, +{PR_NOT_IMPLEMENTED_ERROR, "PR_NOT_IMPLEMENTED_ERROR"}, +{PR_IO_ERROR, "PR_IO_ERROR"}, +{PR_IO_TIMEOUT_ERROR, "PR_IO_TIMEOUT_ERROR"}, +{PR_IO_PENDING_ERROR, "PR_IO_PENDING_ERROR"}, +{PR_DIRECTORY_OPEN_ERROR, "PR_DIRECTORY_OPEN_ERROR"}, +{PR_INVALID_ARGUMENT_ERROR, "PR_INVALID_ARGUMENT_ERROR"}, +{PR_ADDRESS_NOT_AVAILABLE_ERROR, "PR_ADDRESS_NOT_AVAILABLE_ERROR"}, +{PR_ADDRESS_NOT_SUPPORTED_ERROR, "PR_ADDRESS_NOT_SUPPORTED_ERROR"}, +{PR_IS_CONNECTED_ERROR, "PR_IS_CONNECTED_ERROR"}, +{PR_BAD_ADDRESS_ERROR, "PR_BAD_ADDRESS_ERROR"}, +{PR_ADDRESS_IN_USE_ERROR, "PR_ADDRESS_IN_USE_ERROR"}, +{PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR"}, +{PR_NETWORK_UNREACHABLE_ERROR, "PR_NETWORK_UNREACHABLE_ERROR"}, +{PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR"}, +{PR_NOT_CONNECTED_ERROR, "PR_NOT_CONNECTED_ERROR"}, +{PR_LOAD_LIBRARY_ERROR, "PR_LOAD_LIBRARY_ERROR"}, +{PR_UNLOAD_LIBRARY_ERROR, "PR_UNLOAD_LIBRARY_ERROR"}, +{PR_FIND_SYMBOL_ERROR, "PR_FIND_SYMBOL_ERROR"}, +{PR_INSUFFICIENT_RESOURCES_ERROR, "PR_INSUFFICIENT_RESOURCES_ERROR"}, +{PR_DIRECTORY_LOOKUP_ERROR, "PR_DIRECTORY_LOOKUP_ERROR"}, +{PR_TPD_RANGE_ERROR, "PR_TPD_RANGE_ERROR"}, +{PR_PROC_DESC_TABLE_FULL_ERROR, "PR_PROC_DESC_TABLE_FULL_ERROR"}, +{PR_SYS_DESC_TABLE_FULL_ERROR, "PR_SYS_DESC_TABLE_FULL_ERROR"}, +{PR_NOT_SOCKET_ERROR, "PR_NOT_SOCKET_ERROR"}, +{PR_NOT_TCP_SOCKET_ERROR, "PR_NOT_TCP_SOCKET_ERROR"}, +{PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "PR_SOCKET_ADDRESS_IS_BOUND_ERROR"}, +{PR_NO_ACCESS_RIGHTS_ERROR, "PR_NO_ACCESS_RIGHTS_ERROR"}, +{PR_OPERATION_NOT_SUPPORTED_ERROR, "PR_OPERATION_NOT_SUPPORTED_ERROR"}, +{PR_PROTOCOL_NOT_SUPPORTED_ERROR, "PR_PROTOCOL_NOT_SUPPORTED_ERROR"}, +{PR_REMOTE_FILE_ERROR, "PR_REMOTE_FILE_ERROR"}, +{PR_BUFFER_OVERFLOW_ERROR, "PR_BUFFER_OVERFLOW_ERROR"}, +{PR_CONNECT_RESET_ERROR, "PR_CONNECT_RESET_ERROR"}, +{PR_RANGE_ERROR, "PR_RANGE_ERROR"}, +{PR_DEADLOCK_ERROR, "PR_DEADLOCK_ERROR"}, +{PR_FILE_IS_LOCKED_ERROR, "PR_FILE_IS_LOCKED_ERROR"}, +{PR_FILE_TOO_BIG_ERROR, "PR_FILE_TOO_BIG_ERROR"}, +{PR_NO_DEVICE_SPACE_ERROR, "PR_NO_DEVICE_SPACE_ERROR"}, +{PR_PIPE_ERROR, "PR_PIPE_ERROR"}, +{PR_NO_SEEK_DEVICE_ERROR, "PR_NO_SEEK_DEVICE_ERROR"}, +{PR_IS_DIRECTORY_ERROR, "PR_IS_DIRECTORY_ERROR"}, +{PR_LOOP_ERROR, "PR_LOOP_ERROR"}, +{PR_NAME_TOO_LONG_ERROR, "PR_NAME_TOO_LONG_ERROR"}, +{PR_FILE_NOT_FOUND_ERROR, "PR_FILE_NOT_FOUND_ERROR"}, +{PR_NOT_DIRECTORY_ERROR, "PR_NOT_DIRECTORY_ERROR"}, +{PR_READ_ONLY_FILESYSTEM_ERROR, "PR_READ_ONLY_FILESYSTEM_ERROR"}, +{PR_DIRECTORY_NOT_EMPTY_ERROR, "PR_DIRECTORY_NOT_EMPTY_ERROR"}, +{PR_FILESYSTEM_MOUNTED_ERROR, "PR_FILESYSTEM_MOUNTED_ERROR"}, +{PR_NOT_SAME_DEVICE_ERROR, "PR_NOT_SAME_DEVICE_ERROR"}, +{PR_DIRECTORY_CORRUPTED_ERROR, "PR_DIRECTORY_CORRUPTED_ERROR"}, +{PR_FILE_EXISTS_ERROR, "PR_FILE_EXISTS_ERROR"}, +{PR_MAX_DIRECTORY_ENTRIES_ERROR, "PR_MAX_DIRECTORY_ENTRIES_ERROR"}, +{PR_INVALID_DEVICE_STATE_ERROR, "PR_INVALID_DEVICE_STATE_ERROR"}, +{PR_DEVICE_IS_LOCKED_ERROR, "PR_DEVICE_IS_LOCKED_ERROR"}, +{PR_NO_MORE_FILES_ERROR, "PR_NO_MORE_FILES_ERROR"}, +{PR_END_OF_FILE_ERROR, "PR_END_OF_FILE_ERROR"}, +{PR_FILE_SEEK_ERROR, "PR_FILE_SEEK_ERROR"}, +{PR_FILE_IS_BUSY_ERROR, "PR_FILE_IS_BUSY_ERROR"}, +{PR_IN_PROGRESS_ERROR, "PR_IN_PROGRESS_ERROR"}, +{PR_ALREADY_INITIATED_ERROR, "PR_ALREADY_INITIATED_ERROR"}, +{PR_GROUP_EMPTY_ERROR, "PR_GROUP_EMPTY_ERROR"}, +{PR_INVALID_STATE_ERROR, "PR_INVALID_STATE_ERROR"}, +{PR_NETWORK_DOWN_ERROR, "PR_NETWORK_DOWN_ERROR"}, +{PR_SOCKET_SHUTDOWN_ERROR, "PR_SOCKET_SHUTDOWN_ERROR"}, +{PR_CONNECT_ABORTED_ERROR, "PR_CONNECT_ABORTED_ERROR"}, +{PR_HOST_UNREACHABLE_ERROR, "PR_HOST_UNREACHABLE_ERROR"} +}; + +int +main(int argc, char **argv) +{ + + int count, errnum; + + /* + * -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 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + count = sizeof(errcodes)/sizeof(errcodes[0]); + printf("\nNumber of error codes = %d\n\n",count); + for (errnum = 0; errnum < count; errnum++) { + printf("%-40s = %d\n",errcodes[errnum].errname, + errcodes[errnum].errcode); + } + + return 0; +} diff --git a/nsprpub/pr/tests/errset.c b/nsprpub/pr/tests/errset.c new file mode 100644 index 00000000000..7d025f12d25 --- /dev/null +++ b/nsprpub/pr/tests/errset.c @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: errset.c +** +** Description: errset.c exercises the functions in prerror.c. +** This code is a unit test of the prerror.c capability. +** +** Note: There's some fluff in here. The guts of the test +** were plagerized from another test. So, sue me. +** +** +*/ +#include "prerror.h" +#include "plgetopt.h" +#include "prlog.h" + +#include +#include + +static int _debug_on = 0; + +struct errinfo { + PRErrorCode errcode; + char *errname; +}; + +struct errinfo errcodes[] = { +{PR_OUT_OF_MEMORY_ERROR, "PR_OUT_OF_MEMORY_ERROR"}, +{PR_UNKNOWN_ERROR, "An intentionally long error message text intended to force a delete of the current errorString buffer and get another one."}, +{PR_BAD_DESCRIPTOR_ERROR, "PR_BAD_DESCRIPTOR_ERROR"}, +{PR_WOULD_BLOCK_ERROR, "PR_WOULD_BLOCK_ERROR"}, +{PR_ACCESS_FAULT_ERROR, "PR_ACCESS_FAULT_ERROR"}, +{PR_INVALID_METHOD_ERROR, "PR_INVALID_METHOD_ERROR"}, +{PR_ILLEGAL_ACCESS_ERROR, "PR_ILLEGAL_ACCESS_ERROR"}, +{PR_UNKNOWN_ERROR, "PR_UNKNOWN_ERROR"}, +{PR_PENDING_INTERRUPT_ERROR, "PR_PENDING_INTERRUPT_ERROR"}, +{PR_NOT_IMPLEMENTED_ERROR, "PR_NOT_IMPLEMENTED_ERROR"}, +{PR_IO_ERROR, "PR_IO_ERROR"}, +{PR_IO_TIMEOUT_ERROR, "PR_IO_TIMEOUT_ERROR"}, +{PR_IO_PENDING_ERROR, "PR_IO_PENDING_ERROR"}, +{PR_DIRECTORY_OPEN_ERROR, "PR_DIRECTORY_OPEN_ERROR"}, +{PR_INVALID_ARGUMENT_ERROR, "PR_INVALID_ARGUMENT_ERROR"}, +{PR_ADDRESS_NOT_AVAILABLE_ERROR, "PR_ADDRESS_NOT_AVAILABLE_ERROR"}, +{PR_ADDRESS_NOT_SUPPORTED_ERROR, "PR_ADDRESS_NOT_SUPPORTED_ERROR"}, +{PR_IS_CONNECTED_ERROR, "PR_IS_CONNECTED_ERROR"}, +{PR_BAD_ADDRESS_ERROR, "PR_BAD_ADDRESS_ERROR"}, +{PR_ADDRESS_IN_USE_ERROR, "PR_ADDRESS_IN_USE_ERROR"}, +{PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR"}, +{PR_NETWORK_UNREACHABLE_ERROR, "PR_NETWORK_UNREACHABLE_ERROR"}, +{PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR"}, +{PR_NOT_CONNECTED_ERROR, "PR_NOT_CONNECTED_ERROR"}, +{PR_LOAD_LIBRARY_ERROR, "PR_LOAD_LIBRARY_ERROR"}, +{PR_UNLOAD_LIBRARY_ERROR, "PR_UNLOAD_LIBRARY_ERROR"}, +{PR_FIND_SYMBOL_ERROR, "PR_FIND_SYMBOL_ERROR"}, +{PR_INSUFFICIENT_RESOURCES_ERROR, "PR_INSUFFICIENT_RESOURCES_ERROR"}, +{PR_DIRECTORY_LOOKUP_ERROR, "PR_DIRECTORY_LOOKUP_ERROR"}, +{PR_TPD_RANGE_ERROR, "PR_TPD_RANGE_ERROR"}, +{PR_PROC_DESC_TABLE_FULL_ERROR, "PR_PROC_DESC_TABLE_FULL_ERROR"}, +{PR_SYS_DESC_TABLE_FULL_ERROR, "PR_SYS_DESC_TABLE_FULL_ERROR"}, +{PR_NOT_SOCKET_ERROR, "PR_NOT_SOCKET_ERROR"}, +{PR_NOT_TCP_SOCKET_ERROR, "PR_NOT_TCP_SOCKET_ERROR"}, +{PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "PR_SOCKET_ADDRESS_IS_BOUND_ERROR"}, +{PR_NO_ACCESS_RIGHTS_ERROR, "PR_NO_ACCESS_RIGHTS_ERROR"}, +{PR_OPERATION_NOT_SUPPORTED_ERROR, "PR_OPERATION_NOT_SUPPORTED_ERROR"}, +{PR_PROTOCOL_NOT_SUPPORTED_ERROR, "PR_PROTOCOL_NOT_SUPPORTED_ERROR"}, +{PR_REMOTE_FILE_ERROR, "PR_REMOTE_FILE_ERROR"}, +{PR_BUFFER_OVERFLOW_ERROR, "PR_BUFFER_OVERFLOW_ERROR"}, +{PR_CONNECT_RESET_ERROR, "PR_CONNECT_RESET_ERROR"}, +{PR_RANGE_ERROR, "PR_RANGE_ERROR"}, +{PR_DEADLOCK_ERROR, "PR_DEADLOCK_ERROR"}, +{PR_FILE_IS_LOCKED_ERROR, "PR_FILE_IS_LOCKED_ERROR"}, +{PR_FILE_TOO_BIG_ERROR, "PR_FILE_TOO_BIG_ERROR"}, +{PR_NO_DEVICE_SPACE_ERROR, "PR_NO_DEVICE_SPACE_ERROR"}, +{PR_PIPE_ERROR, "PR_PIPE_ERROR"}, +{PR_NO_SEEK_DEVICE_ERROR, "PR_NO_SEEK_DEVICE_ERROR"}, +{PR_IS_DIRECTORY_ERROR, "PR_IS_DIRECTORY_ERROR"}, +{PR_LOOP_ERROR, "PR_LOOP_ERROR"}, +{PR_NAME_TOO_LONG_ERROR, "PR_NAME_TOO_LONG_ERROR"}, +{PR_FILE_NOT_FOUND_ERROR, "PR_FILE_NOT_FOUND_ERROR"}, +{PR_NOT_DIRECTORY_ERROR, "PR_NOT_DIRECTORY_ERROR"}, +{PR_READ_ONLY_FILESYSTEM_ERROR, "PR_READ_ONLY_FILESYSTEM_ERROR"}, +{PR_DIRECTORY_NOT_EMPTY_ERROR, "PR_DIRECTORY_NOT_EMPTY_ERROR"}, +{PR_FILESYSTEM_MOUNTED_ERROR, "PR_FILESYSTEM_MOUNTED_ERROR"}, +{PR_NOT_SAME_DEVICE_ERROR, "PR_NOT_SAME_DEVICE_ERROR"}, +{PR_DIRECTORY_CORRUPTED_ERROR, "PR_DIRECTORY_CORRUPTED_ERROR"}, +{PR_FILE_EXISTS_ERROR, "PR_FILE_EXISTS_ERROR"}, +{PR_MAX_DIRECTORY_ENTRIES_ERROR, "PR_MAX_DIRECTORY_ENTRIES_ERROR"}, +{PR_INVALID_DEVICE_STATE_ERROR, "PR_INVALID_DEVICE_STATE_ERROR"}, +{PR_DEVICE_IS_LOCKED_ERROR, "PR_DEVICE_IS_LOCKED_ERROR"}, +{PR_NO_MORE_FILES_ERROR, "PR_NO_MORE_FILES_ERROR"}, +{PR_END_OF_FILE_ERROR, "PR_END_OF_FILE_ERROR"}, +{PR_FILE_SEEK_ERROR, "PR_FILE_SEEK_ERROR"}, +{PR_FILE_IS_BUSY_ERROR, "PR_FILE_IS_BUSY_ERROR"}, +{PR_IN_PROGRESS_ERROR, "PR_IN_PROGRESS_ERROR"}, +{PR_ALREADY_INITIATED_ERROR, "PR_ALREADY_INITIATED_ERROR"}, +{PR_GROUP_EMPTY_ERROR, "PR_GROUP_EMPTY_ERROR"}, +{PR_INVALID_STATE_ERROR, "PR_INVALID_STATE_ERROR"}, +{PR_NETWORK_DOWN_ERROR, "PR_NETWORK_DOWN_ERROR"}, +{PR_SOCKET_SHUTDOWN_ERROR, "PR_SOCKET_SHUTDOWN_ERROR"}, +{PR_CONNECT_ABORTED_ERROR, "PR_CONNECT_ABORTED_ERROR"}, +{PR_HOST_UNREACHABLE_ERROR, "PR_HOST_UNREACHABLE_ERROR"} +}; + +int +main(int argc, char **argv) +{ + + int count, errnum; + + /* + * -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 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + count = sizeof(errcodes)/sizeof(errcodes[0]); + printf("\nNumber of error codes = %d\n\n",count); + for (errnum = 0; errnum < count; errnum++) { + PRInt32 len1, len2, err; + char msg[256]; + + PR_SetError( errnum, -5 ); + err = PR_GetError(); + PR_ASSERT( err == errnum ); + err = PR_GetOSError(); + PR_ASSERT( err == -5 ); + PR_SetErrorText( strlen(errcodes[errnum].errname), errcodes[errnum].errname ); + len1 = PR_GetErrorTextLength(); + len2 = PR_GetErrorText( msg ); + PR_ASSERT( len1 == len2 ); + printf("%5.5d -- %s\n", errnum, msg ); + } + + return 0; +} diff --git a/nsprpub/pr/tests/exit.c b/nsprpub/pr/tests/exit.c new file mode 100644 index 00000000000..6ccbe86d540 --- /dev/null +++ b/nsprpub/pr/tests/exit.c @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prprf.h" +#include "prinit.h" +#include "prthread.h" +#include "prproces.h" +#include "prinrval.h" + +#include "plgetopt.h" + +#include + +static PRInt32 dally = 0; +static PRFileDesc *err = NULL; +static PRBool verbose = PR_FALSE, force = PR_FALSE; + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-t s] [-h]\n"); + PR_fprintf(err, "\t-d Verbose output (default: FALSE)\n"); + PR_fprintf(err, "\t-x Forced termination (default: FALSE)\n"); + PR_fprintf(err, "\t-t Time for thread to block (default: 10 seconds)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static void Dull(void *arg) +{ + PR_Sleep(PR_SecondsToInterval(dally)); + if (verbose && force) + PR_fprintf(err, "If you see this, the test failed\n"); +} /* Dull */ + +static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "ht:dx"); + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* verbosity */ + verbose = PR_TRUE; + break; + case 'x': /* force exit */ + force = PR_TRUE; + break; + case 't': /* seconds to dally in child */ + dally = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + if (0 == dally) dally = 10; + + /* + * Create LOCAL and GLOBAL threads + */ + (void)PR_CreateThread( + PR_USER_THREAD, Dull, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + (void)PR_CreateThread( + PR_USER_THREAD, Dull, NULL, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + if (verbose) + PR_fprintf( + err, "Main is exiting now. Program should exit %s.\n", + (force) ? "immediately" : "after child dally time"); + + if (force) + { + PR_ProcessExit(0); + if (verbose) + { + PR_fprintf(err, "You should not have gotten here.\n"); + return 1; + } + } + return 0; + +} + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/fdcach.c b/nsprpub/pr/tests/fdcach.c new file mode 100644 index 00000000000..33382fa8a77 --- /dev/null +++ b/nsprpub/pr/tests/fdcach.c @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: fdcach.c + * Description: + * This test verifies that the fd cache and stack are working + * correctly. + */ + +#include "nspr.h" + +#include +#include + +/* + * Define ORDER_PRESERVED if the implementation of PR_SetFDCacheSize + * preserves the ordering of the fd's when moving them between the + * cache and the stack. + */ +#define ORDER_PRESERVED 1 + +/* + * NUM_FDS must be <= FD_CACHE_SIZE. + */ +#define FD_CACHE_SIZE 1024 +#define NUM_FDS 20 + +int main(int argc, char **argv) +{ + int i; + PRFileDesc *fds[NUM_FDS]; + PRFileDesc *savefds[NUM_FDS]; + int numfds = sizeof(fds)/sizeof(fds[0]); + + /* + * Switch between cache and stack when they are empty. + * Then start with the fd cache. + */ + PR_SetFDCacheSize(0, FD_CACHE_SIZE); + PR_SetFDCacheSize(0, 0); + PR_SetFDCacheSize(0, FD_CACHE_SIZE); + + /* Add some fd's to the fd cache. */ + for (i = 0; i < numfds; i++) { + savefds[i] = PR_NewTCPSocket(); + if (NULL == savefds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* + * Create some fd's. These fd's should come from + * the fd cache. Verify the FIFO ordering of the fd + * cache. + */ + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (fds[i] != savefds[i]) { + fprintf(stderr, "fd cache malfunctioned\n"); + exit(1); + } + } + /* Put the fd's back to the fd cache. */ + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* Switch to the fd stack. */ + PR_SetFDCacheSize(0, 0); + + /* + * Create some fd's. These fd's should come from + * the fd stack. + */ + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } +#ifdef ORDER_PRESERVED + if (fds[i] != savefds[numfds-1-i]) { + fprintf(stderr, "fd stack malfunctioned\n"); + exit(1); + } +#else + savefds[numfds-1-i] = fds[i]; +#endif + } + /* Put the fd's back to the fd stack. */ + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* + * Now create some fd's and verify the LIFO ordering of + * the fd stack. + */ + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (fds[i] != savefds[numfds-1-i]) { + fprintf(stderr, "fd stack malfunctioned\n"); + exit(1); + } + } + /* Put the fd's back to the fd stack. */ + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* Switch to the fd cache. */ + PR_SetFDCacheSize(0, FD_CACHE_SIZE); + + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } +#ifdef ORDER_PRESERVED + if (fds[i] != savefds[i]) { + fprintf(stderr, "fd cache malfunctioned\n"); + exit(1); + } +#else + savefds[i] = fds[i]; +#endif + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (fds[i] != savefds[i]) { + fprintf(stderr, "fd cache malfunctioned\n"); + exit(1); + } + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* Switch to the fd stack. */ + PR_SetFDCacheSize(0, 0); + + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } +#ifdef ORDER_PRESERVED + if (fds[i] != savefds[numfds-1-i]) { + fprintf(stderr, "fd stack malfunctioned\n"); + exit(1); + } +#else + savefds[numfds-1-i]; +#endif + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (fds[i] != savefds[numfds-1-i]) { + fprintf(stderr, "fd stack malfunctioned\n"); + exit(1); + } + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + PR_Cleanup(); + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/fileio.c b/nsprpub/pr/tests/fileio.c new file mode 100644 index 00000000000..0b154047ac6 --- /dev/null +++ b/nsprpub/pr/tests/fileio.c @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: fileio.c +** +** Description: Program to copy one file to another. +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1, remove debug option (obsolete). +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +#include "prinit.h" +#include "prthread.h" +#include "prlock.h" +#include "prcvar.h" +#include "prmon.h" +#include "prmem.h" +#include "prio.h" +#include "prlog.h" + +#include + +#ifdef XP_MAC +#include "prsem.h" +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + + +#define TBSIZE 1024 + +static PRUint8 tbuf[TBSIZE]; + +static PRFileDesc *t1, *t2; + +PRIntn failed_already=0; +PRIntn debug_mode; +static void InitialSetup(void) +{ + PRUintn i; + PRInt32 nWritten, rv; + + t1 = PR_Open("t1.tmp", PR_CREATE_FILE | PR_RDWR, 0); + PR_ASSERT(t1 != NULL); + + for (i=0; i= 0) { + buf[i].nbytes = nbytes; + PR_PostSem(fullBufs); + i = (i + 1) % 2; + } + } while (nbytes > 0); +} + +static void PR_CALLBACK writer(void *arg) +{ + PRUintn i = 0; + PRInt32 nbytes; + + do { + (void) PR_WaitSem(fullBufs); + nbytes = buf[i].nbytes; + if (nbytes > 0) { + nbytes = PR_Write((PRFileDesc*)arg, buf[i].data, nbytes); + PR_PostSem(emptyBufs); + i = (i + 1) % 2; + } + } while (nbytes > 0); +} + +int main(int argc, char **argv) +{ + PRThread *r, *w; + + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("fileio.log"); + debug_mode = 1; +#endif + + emptyBufs = PR_NewSem(2); /* two empty buffers */ + + fullBufs = PR_NewSem(0); /* zero full buffers */ + + /* Create initial temp file setup */ + InitialSetup(); + + /* create the reader thread */ + + r = PR_CreateThread(PR_USER_THREAD, + reader, t1, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + w = PR_CreateThread(PR_USER_THREAD, + writer, t2, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + /* Do the joining for both threads */ + (void) PR_JoinThread(r); + (void) PR_JoinThread(w); + + /* Do the verification and clean up */ + VerifyAndCleanup(); + + PR_DestroySem(emptyBufs); + PR_DestroySem(fullBufs); + + PR_Cleanup(); + + if(failed_already) + { + printf("Fail\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } + + +} diff --git a/nsprpub/pr/tests/foreign.c b/nsprpub/pr/tests/foreign.c new file mode 100644 index 00000000000..7ba4dee99a5 --- /dev/null +++ b/nsprpub/pr/tests/foreign.c @@ -0,0 +1,414 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** 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 +#include + +static enum { + thread_nspr, thread_pthread, thread_uithread, 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 +#include "md/_pth.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(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) +#include +static void *uithread_start(void *arg) +{ + StartFn start = ((StartObject*)arg)->start; + void *data = ((StartObject*)arg)->arg; + PR_Free(arg); + start(data); + return NULL; +} /* uithread_start */ +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + +#if defined(IRIX) && !defined(_PR_PTHREADS) +#include +#include +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 /* 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 = _PT_PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setstacksize(&tattr, 64 * 1024); + PR_ASSERT(0 == rv); + + rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object); + (void)_PT_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_uithread: +#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + { + int rv; + thread_t id; + long flags; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + + flags = THR_DETACHED; + + rv = thr_create(NULL, NULL, uithread_start, start_object, flags, &id); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; + break; +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + + 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; + PRLock *lock; + PRFileDesc *fd; + PRDir *dir; + PRFileDesc *pair[2]; + PRIntn test = (PRIntn)arg; + + for (test = 0; test < 12; ++test) { + + switch (test) + { + case 0: + lock = PR_NewLock(); + DPRINTF((output,"Thread[0x%x] called PR_NewLock\n", + PR_GetCurrentThread())); + PR_DestroyLock(lock); + 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: + fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666); + DPRINTF((output,"Thread[0x%x] called PR_Open\n", + PR_GetCurrentThread())); + PR_Close(fd); + break; + + case 4: + fd = PR_NewUDPSocket(); + DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n", + PR_GetCurrentThread())); + PR_Close(fd); + break; + + case 5: + fd = PR_NewTCPSocket(); + DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n", + PR_GetCurrentThread())); + PR_Close(fd); + break; + + case 6: + dir = PR_OpenDir("/tmp/"); + DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n", + PR_GetCurrentThread())); + PR_CloseDir(dir); + 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())); + PR_Close(pair[0]); + PR_Close(pair[1]); + break; + + case 10: + PR_SetConcurrency(2); + DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n", + PR_GetCurrentThread())); + break; + + case 11: + PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH); + DPRINTF((output,"Thread[0x%x] called PR_SetThreadPriority\n", + PR_GetCurrentThread())); + break; + + default: + break; + } /* switch() */ + } +} /* OneShot */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + 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(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + thread_provider = thread_uithread; +#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/nsprpub/pr/tests/forktest.c b/nsprpub/pr/tests/forktest.c new file mode 100644 index 00000000000..ad260ad7425 --- /dev/null +++ b/nsprpub/pr/tests/forktest.c @@ -0,0 +1,346 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: forktest.c +** +** Description: UNIX test for fork functions. +** +** Modification History: +** 15-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 AGarcic - Revert to return code 0 and 1, remove debug option (obsolete). +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include +#include +#include + +PRIntn failed_already=0; + +#ifdef XP_UNIX + +#include +#include +#include +#include + +static char *message = "Hello world!"; + +static void +ClientThreadFunc(void *arg) +{ + PRNetAddr addr; + PRFileDesc *sock = NULL; + PRInt32 tmp = (PRInt32)arg; + + /* + * Make sure the PR_Accept call will block + */ + + printf("Wait one second before connect\n"); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(1)); + + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = 0; + if ((sock = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "failed to create TCP socket: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + if (PR_Bind(sock, &addr) != PR_SUCCESS) { + fprintf(stderr, "PR_Bind failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + addr.inet.ip = PR_htonl(INADDR_LOOPBACK); + addr.inet.port = PR_htons((PRInt16)tmp); + printf("Connecting to port %hu\n", PR_ntohs(addr.inet.port)); + fflush(stdout); + if (PR_Connect(sock, &addr, PR_SecondsToInterval(5)) != + PR_SUCCESS) { + fprintf(stderr, "PR_Connect failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + printf("Writing message \"%s\"\n", message); + fflush(stdout); + if (PR_Send(sock, message, strlen(message) + 1, 0, PR_INTERVAL_NO_TIMEOUT) == + -1) { + fprintf(stderr, "PR_Send failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } +finish: + if (sock) { + PR_Close(sock); + } + return; +} + +/* + * DoIO -- + * This function creates a thread that acts as a client and itself. + * acts as a server. Then it joins the client thread. + */ +static void +DoIO(void) +{ + PRThread *clientThread; + PRFileDesc *listenSock = NULL; + PRFileDesc *sock = NULL; + PRNetAddr addr; + PRInt32 nBytes; + char buf[128]; + + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + fprintf(stderr, "failed to create a TCP socket: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = 0; + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "failed to bind socket: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "failed to get socket port number: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + clientThread = PR_CreateThread( PR_USER_THREAD, ClientThreadFunc, + (void *) PR_ntohs(addr.inet.port), PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "Cannot create client thread: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already = 1; + goto finish; + } + printf("Accepting connection at port %hu\n", PR_ntohs(addr.inet.port)); + fflush(stdout); + sock = PR_Accept(listenSock, &addr, PR_SecondsToInterval(5)); + if (!sock) { + fprintf(stderr, "PR_Accept failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + nBytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (nBytes == -1) { + fprintf(stderr, "PR_Recv failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + + /* + * Make sure it has proper null byte to mark end of string + */ + + buf[sizeof(buf) - 1] = '\0'; + printf("Received \"%s\" from the client\n", buf); + fflush(stdout); + if (!strcmp(buf, message)) { + PR_JoinThread(clientThread); + + printf("The message is received correctly\n"); + fflush(stdout); + } else { + fprintf(stderr, "The message should be \"%s\"\n", + message); + failed_already = 1; + } + +finish: + if (listenSock) { + PR_Close(listenSock); + } + if (sock) { + PR_Close(sock); + } + return; +} + +#ifdef _PR_DCETHREADS + +#include + +pid_t PR_UnixFork1(void) +{ + pid_t parent = getpid(); + int rv = syscall(SYS_fork); + + if (rv == -1) { + return (pid_t) -1; + } else { + /* For each process, rv is the pid of the other process */ + if (rv == parent) { + /* the child */ + return 0; + } else { + /* the parent */ + return rv; + } + } +} + +#elif defined(SOLARIS) + +/* + * It seems like that in Solaris 2.4 one must call fork1() if the + * the child process is going to use thread functions. Solaris 2.5 + * doesn't have this problem. Calling fork() also works. + */ + +pid_t PR_UnixFork1(void) +{ + return fork1(); +} + +#else + +pid_t PR_UnixFork1(void) +{ + return fork(); +} + +#endif /* PR_DCETHREADS */ + +int main( +int argc, +char *argv[] +) +{ + pid_t pid; + int rv; + + /* main test program */ + + DoIO(); + + pid = PR_UnixFork1(); + + if (pid == (pid_t) -1) { + fprintf(stderr, "Fork failed: errno %d\n", errno); + failed_already=1; + return 1; + } else if (pid > 0) { + int childStatus; + + printf("Fork succeeded. Parent process continues.\n"); + DoIO(); + 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; + } + printf("Parent process exits.\n"); + if (!failed_already) { + printf("PASSED\n"); + } else { + printf("FAILED\n"); + } + 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"); + return failed_already; + } +} + +#else /* XP_UNIX */ + +int main( int argc, +char *argv[] +) +{ + + printf("The fork test is applicable to Unix only.\n"); + return 0; + +} + +#endif /* XP_UNIX */ diff --git a/nsprpub/pr/tests/formattm.c b/nsprpub/pr/tests/formattm.c new file mode 100644 index 00000000000..c3c758b5f28 --- /dev/null +++ b/nsprpub/pr/tests/formattm.c @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* A test program for PR_FormatTime and PR_FormatTimeUSEnglish */ + +#include "prtime.h" + +#include + +int main() +{ + char buffer[256]; + PRTime now; + PRExplodedTime tod; + + now = PR_Now(); + PR_ExplodeTime(now, PR_LocalTimeParameters, &tod); + (void)PR_FormatTime(buffer, sizeof(buffer), + "%a %b %d %H:%M:%S %Z %Y", &tod); + printf("%s\n", buffer); + (void)PR_FormatTimeUSEnglish(buffer, sizeof(buffer), + "%a %b %d %H:%M:%S %Z %Y", &tod); + printf("%s\n", buffer); + return 0; +} diff --git a/nsprpub/pr/tests/freeif.c b/nsprpub/pr/tests/freeif.c new file mode 100644 index 00000000000..7aa16b491ea --- /dev/null +++ b/nsprpub/pr/tests/freeif.c @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * A test to see if the macros PR_DELETE and PR_FREEIF are + * properly defined. (See Bugzilla bug #39110.) + */ + +#include "nspr.h" + +#include +#include + +static void Noop(void) { } + +static void Fail(void) +{ + printf("FAIL\n"); + exit(1); +} + +int main() +{ + int foo = 1; + char *ptr = NULL; + + /* this fails to compile with the old definition of PR_DELETE */ + if (foo) + PR_DELETE(ptr); + else + Noop(); + + /* this nests incorrectly with the old definition of PR_FREEIF */ + if (foo) + PR_FREEIF(ptr); + else + Fail(); + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/fsync.c b/nsprpub/pr/tests/fsync.c new file mode 100644 index 00000000000..cea298b3e44 --- /dev/null +++ b/nsprpub/pr/tests/fsync.c @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prmem.h" +#include "prprf.h" +#include "prinrval.h" + +#include "plerror.h" +#include "plgetopt.h" + +static PRFileDesc *err = NULL; + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-S] [-K ] [-h] \n"); + PR_fprintf(err, "\t-c Nuber of iterations (default: 10)\n"); + PR_fprintf(err, "\t-S Sync the file (default: FALSE)\n"); + PR_fprintf(err, "\t-K Size of file (K bytes) (default: 10)\n"); + PR_fprintf(err, "\t Name of file to write (default: /usr/tmp/sync.dat)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PLOptStatus os; + PRUint8 *buffer; + PRFileDesc *file = NULL; + const char *filename = "sync.dat"; + PRUint32 index, loops, iterations = 10, filesize = 10; + PRIntn flags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; + PLOptState *opt = PL_CreateOptState(argc, argv, "hSK:c:"); + PRIntervalTime time, total = 0, shortest = 0x7fffffff, longest = 0; + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* Name of file to create */ + filename = opt->value; + break; + case 'S': /* Use sych option on file */ + flags |= PR_SYNC; + break; + case 'K': /* Size of file to write */ + filesize = atoi(opt->value); + break; + case 'c': /* Number of iterations */ + iterations = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + default: /* user needs some guidance */ + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + file = PR_Open(filename, flags, 0666); + if (NULL == file) + { + PL_FPrintError(err, "Failed to open file"); + return 1; + } + + buffer = (PRUint8*)PR_CALLOC(1024); + if (NULL == buffer) + { + PL_FPrintError(err, "Cannot allocate buffer"); + return 1; + } + + for (index = 0; index < sizeof(buffer); ++index) + buffer[index] = (PRUint8)index; + + for (loops = 0; loops < iterations; ++loops) + { + time = PR_IntervalNow(); + for (index = 0; index < filesize; ++index) + { + PR_Write(file, buffer, 1024); + } + time = (PR_IntervalNow() - time); + + total += time; + if (time < shortest) shortest = time; + else if (time > longest) longest = time; + if (0 != PR_Seek(file, 0, PR_SEEK_SET)) + { + PL_FPrintError(err, "Rewinding file"); + return 1; + } + } + + total = total / iterations; + PR_fprintf( + err, "%u iterations over a %u kbyte %sfile: %u [%u] %u\n", + iterations, filesize, ((flags & PR_SYNC) ? "SYNCH'd " : ""), + PR_IntervalToMicroseconds(shortest), + PR_IntervalToMicroseconds(total), + PR_IntervalToMicroseconds(longest)); + + PR_DELETE(buffer); + rv = PR_Close(file); + if (PR_SUCCESS != rv) + { + PL_FPrintError(err, "Closing file failed"); + return 1; + } + rv = PR_Delete(filename); + if (PR_SUCCESS != rv) + { + PL_FPrintError(err, "Deleting file failed"); + return 1; + } + return 0; +} diff --git a/nsprpub/pr/tests/getai.c b/nsprpub/pr/tests/getai.c new file mode 100644 index 00000000000..bc4a59a7de0 --- /dev/null +++ b/nsprpub/pr/tests/getai.c @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" + +#include +#include + +int main(int argc, char *argv[]) +{ + PRAddrInfo *ai; + void *iter; + PRNetAddr addr; + + ai = PR_GetAddrInfoByName(argv[1], PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + if (ai == NULL) { + fprintf(stderr, "PR_GetAddrInfoByName failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("%s\n", PR_GetCanonNameFromAddrInfo(ai)); + iter = NULL; + while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) { + char buf[128]; + PR_NetAddrToString(&addr, buf, sizeof buf); + printf("%s\n", buf); + } + PR_FreeAddrInfo(ai); + return 0; +} diff --git a/nsprpub/pr/tests/gethost.c b/nsprpub/pr/tests/gethost.c new file mode 100644 index 00000000000..3af41a3fcb3 --- /dev/null +++ b/nsprpub/pr/tests/gethost.c @@ -0,0 +1,291 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: gethost.c + * + * Description: tests various functions in prnetdb.h + * + * Usage: gethost [-6] [hostname] + */ + +#include "prio.h" +#include "prnetdb.h" +#include "plgetopt.h" + +#include +#include + +#define DEFAULT_HOST_NAME "mcom.com" + +static void Help(void) +{ + fprintf(stderr, "Usage: gethost [-h] [hostname]\n"); + fprintf(stderr, "\t-h help\n"); + fprintf(stderr, "\thostname Name of host (default: %s)\n", + DEFAULT_HOST_NAME); +} /* Help */ + +/* + * Prints the contents of a PRHostEnt structure + */ +void PrintHostent(const PRHostEnt *he) +{ + int i; + int j; + + printf("h_name: %s\n", he->h_name); + for (i = 0; he->h_aliases[i]; i++) { + printf("h_aliases[%d]: %s\n", i, he->h_aliases[i]); + } + printf("h_addrtype: %d\n", he->h_addrtype); + printf("h_length: %d\n", he->h_length); + for (i = 0; he->h_addr_list[i]; i++) { + printf("h_addr_list[%d]: ", i); + for (j = 0; j < he->h_length; j++) { + if (j != 0) printf("."); + printf("%u", (unsigned char)he->h_addr_list[i][j]); + } + printf("\n"); + } +} + +int main(int argc, char **argv) +{ + const char *hostName = DEFAULT_HOST_NAME; + PRHostEnt he, reversehe; + char buf[PR_NETDB_BUF_SIZE]; + char reversebuf[PR_NETDB_BUF_SIZE]; + PRIntn idx; + PRNetAddr addr; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 0: /* naked */ + hostName = opt->value; + break; + case 'h': /* Help message */ + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (PR_GetHostByName(hostName, buf, sizeof(buf), &he) == PR_FAILURE) { + fprintf(stderr, "PR_GetHostByName failed\n"); + exit(1); + } + PrintHostent(&he); + idx = 0; + while (1) { + idx = PR_EnumerateHostEnt(idx, &he, 0, &addr); + if (idx == -1) { + fprintf(stderr, "PR_EnumerateHostEnt failed\n"); + exit(1); + } + if (idx == 0) break; /* normal loop termination */ + printf("reverse lookup\n"); + if (PR_GetHostByAddr(&addr, reversebuf, sizeof(reversebuf), + &reversehe) == PR_FAILURE) { + fprintf(stderr, "PR_GetHostByAddr failed\n"); + exit(1); + } + PrintHostent(&reversehe); + } + + printf("PR_GetIPNodeByName with PR_AF_INET\n"); + if (PR_GetIPNodeByName(hostName, PR_AF_INET, PR_AI_DEFAULT, + buf, sizeof(buf), &he) == PR_FAILURE) { + fprintf(stderr, "PR_GetIPNodeByName failed\n"); + exit(1); + } + PrintHostent(&he); + printf("PR_GetIPNodeByName with PR_AF_INET6\n"); + if (PR_GetIPNodeByName(hostName, PR_AF_INET6, PR_AI_DEFAULT, + buf, sizeof(buf), &he) == PR_FAILURE) { + fprintf(stderr, "PR_GetIPNodeByName failed\n"); + exit(1); + } + PrintHostent(&he); + idx = 0; + printf("PR_GetHostByAddr with PR_AF_INET6\n"); + while (1) { + idx = PR_EnumerateHostEnt(idx, &he, 0, &addr); + if (idx == -1) { + fprintf(stderr, "PR_EnumerateHostEnt failed\n"); + exit(1); + } + if (idx == 0) break; /* normal loop termination */ + printf("reverse lookup\n"); + if (PR_GetHostByAddr(&addr, reversebuf, sizeof(reversebuf), + &reversehe) == PR_FAILURE) { + fprintf(stderr, "PR_GetHostByAddr failed\n"); + exit(1); + } + PrintHostent(&reversehe); + } + printf("PR_GetHostByAddr with PR_AF_INET6 done\n"); + + PR_StringToNetAddr("::1", &addr); + if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped) == PR_TRUE) { + fprintf(stderr, "addr should not be ipv4 mapped address\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + + PR_StringToNetAddr("127.0.0.1", &addr); + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + PR_StringToNetAddr("::FFFF:127.0.0.1", &addr); + if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped) == PR_FALSE) { + fprintf(stderr, "addr should be ipv4 mapped address\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + + if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) { + fprintf(stderr, "addr should be unspecified address\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + + if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) { + fprintf(stderr, "addr should be unspecified address\n"); + exit(1); + } + if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + + addr.inet.family = PR_AF_INET; + addr.inet.port = 0; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) { + fprintf(stderr, "addr should be unspecified address\n"); + exit(1); + } + { + char buf[256]; + PR_NetAddrToString(&addr, buf, 256); + printf("IPv4 INADDRANY: %s\n", buf); + } + addr.inet.family = PR_AF_INET; + addr.inet.port = 0; + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + { + char buf[256]; + PR_NetAddrToString(&addr, buf, 256); + printf("IPv4 LOOPBACK: %s\n", buf); + } + + if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) { + fprintf(stderr, "addr should be unspecified address\n"); + exit(1); + } + { + char buf[256]; + PR_NetAddrToString(&addr, buf, 256); + printf("IPv6 INADDRANY: %s\n", buf); + } + if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + { + char buf[256]; + PR_NetAddrToString(&addr, buf, 256); + printf("IPv6 LOOPBACK: %s\n", buf); + } + { + PRIPv6Addr v6addr; + char tmp_buf[256]; + + PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET, 0, &addr); + + PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &v6addr); + PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr); + addr.ipv6.ip = v6addr; + PR_NetAddrToString(&addr, tmp_buf, 256); + printf("IPv4-mapped IPv6 LOOPBACK: %s\n", tmp_buf); + } + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/getproto.c b/nsprpub/pr/tests/getproto.c new file mode 100644 index 00000000000..7381bbd8e1a --- /dev/null +++ b/nsprpub/pr/tests/getproto.c @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + ************************************************************************* + * + * File: getproto.c + * + * A test program for PR_GetProtoByName and PR_GetProtoByNumber + * + ************************************************************************* + */ + +#include "plstr.h" +#include "plerror.h" +#include "prinit.h" +#include "prprf.h" +#include "prnetdb.h" +#include "prerror.h" + +int main() +{ + PRFileDesc *prstderr = PR_GetSpecialFD(PR_StandardError); + PRBool failed = PR_FALSE; + PRProtoEnt proto; + char buf[2048]; + PRStatus rv; + + PR_STDIO_INIT(); + rv = PR_GetProtoByName("tcp", buf, sizeof(buf), &proto); + if (PR_FAILURE == rv) { + failed = PR_TRUE; + PL_FPrintError(prstderr, "PR_GetProtoByName failed"); + } + else if (6 != proto.p_num) { + PR_fprintf( + prstderr,"tcp is usually 6, but is %d on this machine\n", + proto.p_num); + } + else PR_fprintf(prstderr, "tcp is protocol number %d\n", proto.p_num); + + rv = PR_GetProtoByName("udp", buf, sizeof(buf), &proto); + if (PR_FAILURE == rv) { + failed = PR_TRUE; + PL_FPrintError(prstderr, "PR_GetProtoByName failed"); + } + else if (17 != proto.p_num) { + PR_fprintf( + prstderr, "udp is usually 17, but is %d on this machine\n", + proto.p_num); + } + else PR_fprintf(prstderr, "udp is protocol number %d\n", proto.p_num); + + rv = PR_GetProtoByNumber(6, buf, sizeof(buf), &proto); + if (PR_FAILURE == rv) { + failed = PR_TRUE; + PL_FPrintError(prstderr, "PR_GetProtoByNumber failed"); + } + else if (PL_strcmp("tcp", proto.p_name)) { + PR_fprintf( + prstderr, "Protocol number 6 is usually tcp, but is %s" + " on this platform\n", proto.p_name); + } + else PR_fprintf(prstderr, "Protocol number 6 is %s\n", proto.p_name); + + rv = PR_GetProtoByNumber(17, buf, sizeof(buf), &proto); + if (PR_FAILURE == rv) { + failed = PR_TRUE; + PL_FPrintError(prstderr, "PR_GetProtoByNumber failed"); + } + else if (PL_strcmp("udp", proto.p_name)) { + PR_fprintf( + prstderr, "Protocol number 17 is usually udp, but is %s" + " on this platform\n", proto.p_name); + } + else PR_fprintf(prstderr, "Protocol number 17 is %s\n", proto.p_name); + + PR_fprintf(prstderr, (failed) ? "FAILED\n" : "PASSED\n"); + return (failed) ? 1 : 0; +} diff --git a/nsprpub/pr/tests/i2l.c b/nsprpub/pr/tests/i2l.c new file mode 100644 index 00000000000..4ff67bc0e31 --- /dev/null +++ b/nsprpub/pr/tests/i2l.c @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include "prio.h" +#include "prinit.h" +#include "prprf.h" +#include "prlong.h" + +#include "plerror.h" +#include "plgetopt.h" + +typedef union Overlay_i +{ + PRInt32 i; + PRInt64 l; +} Overlay_i; + +typedef union Overlay_u +{ + PRUint32 i; + PRUint64 l; +} Overlay_u; + +static PRFileDesc *err = NULL; + +static void Help(void) +{ + PR_fprintf(err, "Usage: -i n | -u n | -h\n"); + PR_fprintf(err, "\t-i n treat following number as signed integer\n"); + PR_fprintf(err, "\t-u n treat following number as unsigned integer\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv) +{ + Overlay_i si; + Overlay_u ui; + PLOptStatus os; + PRBool bsi = PR_FALSE, bui = PR_FALSE; + PLOptState *opt = PL_CreateOptState(argc, argv, "hi:u:"); + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'i': /* signed integer */ + si.i = (PRInt32)atoi(opt->value); + bsi = PR_TRUE; + break; + case 'u': /* unsigned */ + ui.i = (PRUint32)atoi(opt->value); + bui = PR_TRUE; + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + +#if defined(HAVE_LONG_LONG) + PR_fprintf(err, "We have long long\n"); +#else + PR_fprintf(err, "We don't have long long\n"); +#endif + + if (bsi) + { + PR_fprintf(err, "Converting %ld: ", si.i); + LL_I2L(si.l, si.i); + PR_fprintf(err, "%lld\n", si.l); + } + + if (bui) + { + PR_fprintf(err, "Converting %lu: ", ui.i); + LL_I2L(ui.l, ui.i); + PR_fprintf(err, "%llu\n", ui.l); + } + return 0; + +} /* main */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ + +/* i2l.c */ diff --git a/nsprpub/pr/tests/initclk.c b/nsprpub/pr/tests/initclk.c new file mode 100644 index 00000000000..6540519e6a9 --- /dev/null +++ b/nsprpub/pr/tests/initclk.c @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * 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 +#include + +/* 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("Elapsed time: %u ms, expected time: %u ms\n", + LONG_TIMEOUT, elapsed_ms); + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/inrval.c b/nsprpub/pr/tests/inrval.c new file mode 100644 index 00000000000..b057c685354 --- /dev/null +++ b/nsprpub/pr/tests/inrval.c @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** file: inrval.c +** description: Interval conversion test. +** Modification History: +** 15-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +**/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#ifdef XP_MAC +#include "pralarm.h" +#else +#include "obsolete/pralarm.h" +#endif + +#include "prio.h" +#include "prprf.h" +#include "prlock.h" +#include "prlong.h" +#include "prcvar.h" +#include "prinrval.h" +#include "prtime.h" + +#include "plgetopt.h" + +#include +#include + +static PRIntn debug_mode; +static PRFileDesc *output; + + +static void TestConversions(void) +{ + PRIntervalTime ticks = PR_TicksPerSecond(); + + if (debug_mode) { + 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)); + + 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)); + + 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; + 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; + PRUint32 delta; + PRInt32 seconds; + PRUint64 elapsed, thousand; + PRTime timein, timeout; + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + for (seconds = 0; seconds < 10; ++seconds) + { + PRIntervalTime ticks = PR_SecondsToInterval(seconds); + PR_Lock(ml); + timein = PR_Now(); + rv = PR_WaitCondVar(cv, ticks); + timeout = PR_Now(); + PR_Unlock(ml); + LL_SUB(elapsed, timeout, timein); + LL_I2L(thousand, 1000); + LL_DIV(elapsed, elapsed, thousand); + LL_L2UI(delta, elapsed); + 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) PR_fprintf(output, "\n"); +} /* TestIntervals */ + +static PRIntn PR_CALLBACK RealMain(int argc, char** argv) +{ + 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + /* main test */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dl: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; + break; + case 'c': /* concurrency counter */ + cpus = atoi(opt->value); + break; + case 'l': /* loop counter */ + loops = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + output = PR_GetSpecialFD(PR_StandardOutput); + PR_fprintf(output, "inrval: Examine stdout to determine results.\n"); + + if (cpus == 0) cpus = 8; + if (loops == 0) loops = 1000; + + if (debug_mode > 0) + { + PR_fprintf(output, "Inrval: Using %d loops\n", loops); + PR_fprintf(output, "Inrval: Using 1 and %d cpu(s)\n", cpus); + } + + 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); + + TestNowOverhead(); + TestIntervalOverhead(); + TestConversions(); + TestIntervals(); + } + + return 0; +} + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ + diff --git a/nsprpub/pr/tests/instrumt.c b/nsprpub/pr/tests/instrumt.c new file mode 100644 index 00000000000..f1577609474 --- /dev/null +++ b/nsprpub/pr/tests/instrumt.c @@ -0,0 +1,507 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ); + const char *qn, *rn, *dn; + const 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 ); + const char *qn, *rn, *dn; + const 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; + PRIntn i = 0; + PR_DEFINE_COUNTER( tc ); + PR_DEFINE_COUNTER( zCounter ); + + PR_LOG( lm, msgLevel, + ("Begin CounterTest")); + + /* + ** Test Get and Set of a counter. + ** + */ + PR_CREATE_COUNTER( zCounter, "Atomic", "get/set test", "test get and set of counter" ); + PR_SET_COUNTER( zCounter, 9 ); + PR_GET_COUNTER( i, zCounter ); + if ( i != 9 ) + { + failed = PR_TRUE; + PR_LOG( lm, msgLevel, + ("Counter set/get failed")); + } + + 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_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_DESTROY_COUNTER( hCounter ); + + 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/nsprpub/pr/tests/intrio.c b/nsprpub/pr/tests/intrio.c new file mode 100644 index 00000000000..e1dcf661df0 --- /dev/null +++ b/nsprpub/pr/tests/intrio.c @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: intrio.c + * Purpose: testing i/o interrupts (see Bugzilla bug #31120) + */ + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +/* for synchronization between the main thread and iothread */ +static PRLock *lock; +static PRCondVar *cvar; +static PRBool iothread_ready; + +static void PR_CALLBACK AbortIO(void *arg) +{ + PRStatus rv; + PR_Sleep(PR_SecondsToInterval(2)); + rv = PR_Interrupt((PRThread*)arg); + PR_ASSERT(PR_SUCCESS == rv); +} /* AbortIO */ + +static void PR_CALLBACK IOThread(void *arg) +{ + PRFileDesc *sock, *newsock; + PRNetAddr addr; + + sock = PR_OpenTCPSocket(PR_AF_INET6); + if (sock == NULL) { + fprintf(stderr, "PR_OpenTCPSocket failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_Bind(sock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_Listen(sock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + /* tell the main thread that we are ready */ + PR_Lock(lock); + iothread_ready = PR_TRUE; + PR_NotifyCondVar(cvar); + PR_Unlock(lock); + newsock = PR_Accept(sock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (newsock != NULL) { + fprintf(stderr, "PR_Accept shouldn't have succeeded\n"); + exit(1); + } + if (PR_GetError() != PR_PENDING_INTERRUPT_ERROR) { + fprintf(stderr, "PR_Accept failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("PR_Accept() is interrupted as expected\n"); + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +static void Test(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *iothread, *abortio; + + printf("A %s thread will be interrupted by a %s thread\n", + (scope1 == PR_LOCAL_THREAD ? "local" : "global"), + (scope2 == PR_LOCAL_THREAD ? "local" : "global")); + iothread_ready = PR_FALSE; + iothread = PR_CreateThread( + PR_USER_THREAD, IOThread, NULL, PR_PRIORITY_NORMAL, + scope1, PR_JOINABLE_THREAD, 0); + if (iothread == NULL) { + fprintf(stderr, "cannot create thread\n"); + exit(1); + } + PR_Lock(lock); + while (!iothread_ready) + PR_WaitCondVar(cvar, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(lock); + abortio = PR_CreateThread( + PR_USER_THREAD, AbortIO, iothread, PR_PRIORITY_NORMAL, + scope2, PR_JOINABLE_THREAD, 0); + if (abortio == NULL) { + fprintf(stderr, "cannot create thread\n"); + exit(1); + } + if (PR_JoinThread(iothread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + if (PR_JoinThread(abortio) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } +} + +PRIntn main(PRIntn argc, char **argv) +{ + PR_STDIO_INIT(); + lock = PR_NewLock(); + if (lock == NULL) { + fprintf(stderr, "PR_NewLock failed\n"); + exit(1); + } + cvar = PR_NewCondVar(lock); + if (cvar == NULL) { + fprintf(stderr, "PR_NewCondVar failed\n"); + exit(1); + } + /* test all four combinations */ + Test(PR_LOCAL_THREAD, PR_LOCAL_THREAD); + Test(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); + Test(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); + Test(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); + printf("PASSED\n"); + return 0; +} /* main */ diff --git a/nsprpub/pr/tests/intrupt.c b/nsprpub/pr/tests/intrupt.c new file mode 100644 index 00000000000..a4d62f7734f --- /dev/null +++ b/nsprpub/pr/tests/intrupt.c @@ -0,0 +1,373 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: intrupt.c + * Purpose: testing thread interrupts + */ + +#include "plgetopt.h" +#include "prcvar.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prthread.h" +#include "prtypes.h" +#include "prnetdb.h" + +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define DEFAULT_TCP_PORT 12500 + +static PRLock *ml = NULL; +static PRCondVar *cv = NULL; + +static PRBool passed = PR_TRUE; +static PRBool debug_mode = PR_FALSE; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +static void PR_CALLBACK AbortCV(void *arg) +{ + PRStatus rv; + PRThread *me = PR_GetCurrentThread(); + + /* some other thread (main) is doing the interrupt */ + PR_Lock(ml); + rv = PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + if (debug_mode) printf( "Expected interrupt on wait CV and "); + if (PR_FAILURE == rv) + { + if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) + { + if (debug_mode) printf("got it\n"); + } + else + { + if (debug_mode) printf("got random error\n"); + passed = PR_FALSE; + } + } + else + { + if (debug_mode) printf("got a successful completion\n"); + passed = PR_FALSE; + } + + rv = PR_WaitCondVar(cv, 10); + if (debug_mode) + { + printf( + "Expected success on wait CV and %s\n", + (PR_SUCCESS == rv) ? "got it" : "failed"); + } + passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; + + /* interrupt myself, then clear */ + PR_Interrupt(me); + PR_ClearInterrupt(); + rv = PR_WaitCondVar(cv, 10); + if (debug_mode) + { + printf("Expected success on wait CV and "); + if (PR_FAILURE == rv) + { + printf( + "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ? + "got interrupted" : "a random failure"); + } + printf("got it\n"); + } + passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; + + /* set, then wait - interrupt - then wait again */ + PR_Interrupt(me); + rv = PR_WaitCondVar(cv, 10); + if (debug_mode) printf( "Expected interrupt on wait CV and "); + if (PR_FAILURE == rv) + { + if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) + { + if (debug_mode) printf("got it\n"); + } + else + { + if (debug_mode) printf("failed\n"); + passed = PR_FALSE; + } + } + else + { + if (debug_mode) printf("got a successful completion\n"); + passed = PR_FALSE; + } + + rv = PR_WaitCondVar(cv, 10); + if (debug_mode) + { + printf( + "Expected success on wait CV and %s\n", + (PR_SUCCESS == rv) ? "got it" : "failed"); + } + passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; + + PR_Unlock(ml); + +} /* AbortCV */ + +static void PR_CALLBACK AbortIO(void *arg) +{ + PRStatus rv; + PR_Sleep(PR_SecondsToInterval(2)); + rv = PR_Interrupt((PRThread*)arg); + PR_ASSERT(PR_SUCCESS == rv); +} /* AbortIO */ + +static void PR_CALLBACK AbortJoin(void *arg) +{ +} /* AbortJoin */ + +static void setup_listen_socket(PRFileDesc **listner, PRNetAddr *netaddr) +{ + PRStatus rv; + PRInt16 port = DEFAULT_TCP_PORT; + + *listner = PR_NewTCPSocket(); + PR_ASSERT(*listner != NULL); + memset(netaddr, 0, sizeof(*netaddr)); + (*netaddr).inet.ip = PR_htonl(PR_INADDR_ANY); + (*netaddr).inet.family = PR_AF_INET; + do + { + (*netaddr).inet.port = PR_htons(port); + rv = PR_Bind(*listner, netaddr); + port += 1; + PR_ASSERT(port < (DEFAULT_TCP_PORT + 10)); + } while (PR_FAILURE == rv); + + rv = PR_Listen(*listner, 5); + + if (PR_GetSockName(*listner, netaddr) < 0) { + if (debug_mode) printf("intrupt: ERROR - PR_GetSockName failed\n"); + passed = PR_FALSE; + return; + } + +} + +static void PR_CALLBACK IntrBlock(void *arg) +{ + PRStatus rv; + PRNetAddr netaddr; + PRFileDesc *listner; + + /* some other thread (main) is doing the interrupt */ + /* block the interrupt */ + PR_BlockInterrupt(); + PR_Lock(ml); + rv = PR_WaitCondVar(cv, PR_SecondsToInterval(4)); + PR_Unlock(ml); + if (debug_mode) + { + printf("Expected success on wait CV and "); + if (PR_FAILURE == rv) + { + printf( + "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ? + "got interrupted" : "got a random failure"); + } else + printf("got it\n"); + } + passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; + + setup_listen_socket(&listner, &netaddr); + PR_UnblockInterrupt(); + if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) + { + PRInt32 error = PR_GetError(); + if (debug_mode) printf("Expected interrupt on PR_Accept() and "); + if (PR_PENDING_INTERRUPT_ERROR == error) + { + if (debug_mode) printf("got it\n"); + } + else + { + if (debug_mode) printf("failed\n"); + passed = PR_FALSE; + } + } + else + { + if (debug_mode) printf("Failed to interrupt PR_Accept()\n"); + passed = PR_FALSE; + } + + (void)PR_Close(listner); listner = NULL; +} /* TestIntrBlock */ + +void PR_CALLBACK Intrupt(void *arg) +{ + PRStatus rv; + PRNetAddr netaddr; + PRFileDesc *listner; + PRThread *abortCV, *abortIO, *abortJoin, *intrBlock; + + ml = PR_NewLock(); + cv = PR_NewCondVar(ml); + +#ifdef XP_MAC + SetupMacPrintfLog("intrupt.log"); + debug_mode = PR_TRUE; +#endif + + /* Part I */ + if (debug_mode) printf("Part I\n"); + abortCV = PR_CreateThread( + PR_USER_THREAD, AbortCV, 0, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + + PR_Sleep(PR_SecondsToInterval(2)); + rv = PR_Interrupt(abortCV); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(abortCV); + PR_ASSERT(PR_SUCCESS == rv); + + /* Part II */ + if (debug_mode) printf("Part II\n"); + abortJoin = PR_CreateThread( + PR_USER_THREAD, AbortJoin, 0, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + PR_Sleep(PR_SecondsToInterval(2)); + if (debug_mode) printf("Expecting to interrupt an exited thread "); + rv = PR_Interrupt(abortJoin); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(abortJoin); + PR_ASSERT(PR_SUCCESS == rv); + if (debug_mode) printf("and succeeded\n"); + + /* Part III */ + if (debug_mode) printf("Part III\n"); + setup_listen_socket(&listner, &netaddr); + abortIO = PR_CreateThread( + PR_USER_THREAD, AbortIO, PR_GetCurrentThread(), PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + + if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) + { + PRInt32 error = PR_GetError(); + if (debug_mode) printf("Expected interrupt on PR_Accept() and "); + if (PR_PENDING_INTERRUPT_ERROR == error) + { + if (debug_mode) printf("got it\n"); + } + else + { + if (debug_mode) printf("failed\n"); + passed = PR_FALSE; + } + } + else + { + if (debug_mode) printf("Failed to interrupt PR_Accept()\n"); + passed = PR_FALSE; + } + + (void)PR_Close(listner); listner = NULL; + + rv = PR_JoinThread(abortIO); + PR_ASSERT(PR_SUCCESS == rv); + /* Part VI */ + if (debug_mode) printf("Part VI\n"); + intrBlock = PR_CreateThread( + PR_USER_THREAD, IntrBlock, 0, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + + PR_Sleep(PR_SecondsToInterval(2)); + rv = PR_Interrupt(intrBlock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(intrBlock); + PR_ASSERT(PR_SUCCESS == rv); + + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); +} /* Intrupt */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRThread *intrupt; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dG"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + intrupt = PR_CreateThread( + PR_USER_THREAD, Intrupt, NULL, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + if (intrupt == NULL) { + fprintf(stderr, "cannot create thread\n"); + passed = PR_FALSE; + } else { + PRStatus rv; + rv = PR_JoinThread(intrupt); + PR_ASSERT(rv == PR_SUCCESS); + } + printf("%s\n", ((passed) ? "PASSED" : "FAILED")); + return ((passed) ? 0 : 1); +} /* main */ + +/* intrupt.c */ diff --git a/nsprpub/pr/tests/io_timeout.c b/nsprpub/pr/tests/io_timeout.c new file mode 100644 index 00000000000..2a680aa5c1e --- /dev/null +++ b/nsprpub/pr/tests/io_timeout.c @@ -0,0 +1,299 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Test socket IO timeouts +** +** +** +** +** 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. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include "nspr.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define NUM_THREADS 1 +#define BASE_PORT 8000 +#define DEFAULT_ACCEPT_TIMEOUT 2 + +typedef struct threadInfo { + PRInt16 id; + PRInt16 accept_timeout; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 *alive; +} threadInfo; + +PRIntn failed_already = 0; +PRIntn debug_mode = 0; + +#define LOCAL_SCOPE_STRING "LOCAL scope" +#define GLOBAL_SCOPE_STRING "GLOBAL scope" +#define GLOBAL_BOUND_SCOPE_STRING "GLOBAL_BOUND scope" + +void +thread_main(void *_info) +{ + threadInfo *info = (threadInfo *)_info; + PRNetAddr listenAddr; + PRNetAddr clientAddr; + PRFileDesc *listenSock = NULL; + PRFileDesc *clientSock; + PRStatus rv; + PRThreadScope tscope; + char *scope_str; + + + if (debug_mode) + printf("thread %d is alive\n", info->id); + tscope = PR_GetThreadScope(PR_GetCurrentThread()); + + switch(tscope) { + case PR_LOCAL_THREAD: + scope_str = LOCAL_SCOPE_STRING; + break; + case PR_GLOBAL_THREAD: + scope_str = GLOBAL_SCOPE_STRING; + break; + case PR_GLOBAL_BOUND_THREAD: + scope_str = GLOBAL_BOUND_SCOPE_STRING; + break; + default: + PR_ASSERT(!"Invalid thread scope"); + break; + } + printf("thread id %d, scope %s\n", info->id, scope_str); + + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + if (debug_mode) + printf("unable to create listen socket\n"); + failed_already=1; + goto dead; + } + + listenAddr.inet.family = PR_AF_INET; + listenAddr.inet.port = PR_htons(BASE_PORT + info->id); + listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + rv = PR_Bind(listenSock, &listenAddr); + if (rv == PR_FAILURE) { + if (debug_mode) + printf("unable to bind\n"); + failed_already=1; + goto dead; + } + + rv = PR_Listen(listenSock, 4); + if (rv == PR_FAILURE) { + if (debug_mode) + printf("unable to listen\n"); + failed_already=1; + goto dead; + } + + if (debug_mode) + printf("thread %d going into accept for %d seconds\n", + info->id, info->accept_timeout + info->id); + + clientSock = PR_Accept(listenSock, &clientAddr, PR_SecondsToInterval(info->accept_timeout +info->id)); + + if (clientSock == NULL) { + if (PR_GetError() == PR_IO_TIMEOUT_ERROR) { + if (debug_mode) { + printf("PR_Accept() timeout worked!\n"); + printf("TEST PASSED! PR_Accept() returned error %d\n", + PR_IO_TIMEOUT_ERROR); + } + } else { + if (debug_mode) + printf("TEST FAILED! PR_Accept() returned error %d\n", + PR_GetError()); + failed_already=1; + } + } else { + if (debug_mode) + printf ("TEST FAILED! PR_Accept() succeeded?\n"); + failed_already=1; + PR_Close(clientSock); + } + +dead: + if (listenSock) { + PR_Close(listenSock); + } + PR_Lock(info->dead_lock); + (*info->alive)--; + PR_NotifyCondVar(info->dead_cv); + PR_Unlock(info->dead_lock); + + if (debug_mode) + printf("thread %d is dead\n", info->id); + + PR_Free(info); +} + +void +thread_test(PRThreadScope scope, PRInt32 num_threads) +{ + PRInt32 index; + PRThread *thr; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 alive; + + if (debug_mode) + printf("IO Timeout test started with %d threads\n", num_threads); + + dead_lock = PR_NewLock(); + dead_cv = PR_NewCondVar(dead_lock); + alive = num_threads; + + for (index = 0; index < num_threads; index++) { + threadInfo *info = (threadInfo *)PR_Malloc(sizeof(threadInfo)); + + info->id = index; + info->dead_lock = dead_lock; + info->dead_cv = dead_cv; + info->alive = &alive; + info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT; + + thr = PR_CreateThread( PR_USER_THREAD, + thread_main, + (void *)info, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); + + if (!thr) { + printf("Failed to create thread, error = %d(%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + + PR_Lock(dead_lock); + alive--; + PR_Unlock(dead_lock); + } + } + + PR_Lock(dead_lock); + while(alive) { + if (debug_mode) + printf("main loop awake; alive = %d\n", alive); + PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(dead_lock); + + PR_DestroyCondVar(dead_cv); + PR_DestroyLock(dead_lock); +} + +int main(int argc, char **argv) +{ + PRInt32 num_threads = 0; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name [-d] [-t ] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 't': /* threads to involve */ + num_threads = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + if (0 == num_threads) + num_threads = NUM_THREADS; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("io_timeout.log"); + debug_mode = 1; +#endif + + printf("test with global bound thread\n"); + thread_test(PR_GLOBAL_BOUND_THREAD, num_threads); + + printf("test with local thread\n"); + thread_test(PR_LOCAL_THREAD, num_threads); + + printf("test with global thread\n"); + thread_test(PR_GLOBAL_THREAD, num_threads); + + PR_Cleanup(); + + if (failed_already) + return 1; + else + return 0; +} diff --git a/nsprpub/pr/tests/io_timeoutk.c b/nsprpub/pr/tests/io_timeoutk.c new file mode 100644 index 00000000000..26e3beeb6fc --- /dev/null +++ b/nsprpub/pr/tests/io_timeoutk.c @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** name io_timeoutk.c +** Description:Test socket IO timeouts (kernel level) +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include "nspr.h" + +#define NUM_THREADS 1 +#define BASE_PORT 8000 +#define DEFAULT_ACCEPT_TIMEOUT 2 + +typedef struct threadInfo { + PRInt16 id; + PRInt16 accept_timeout; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 *alive; +} threadInfo; + +PRIntn failed_already=0; +PRIntn debug_mode; + + +void +thread_main(void *_info) +{ + threadInfo *info = (threadInfo *)_info; + PRNetAddr listenAddr; + PRNetAddr clientAddr; + PRFileDesc *listenSock = NULL; + PRFileDesc *clientSock; + PRStatus rv; + + if (debug_mode) printf("thread %d is alive\n", info->id); + + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + if (debug_mode) printf("unable to create listen socket\n"); + goto dead; + } + + listenAddr.inet.family = AF_INET; + listenAddr.inet.port = PR_htons(BASE_PORT + info->id); + listenAddr.inet.ip = PR_htonl(INADDR_ANY); + rv = PR_Bind(listenSock, &listenAddr); + if (rv == PR_FAILURE) { + if (debug_mode) printf("unable to bind\n"); + goto dead; + } + + rv = PR_Listen(listenSock, 4); + if (rv == PR_FAILURE) { + if (debug_mode) printf("unable to listen\n"); + goto dead; + } + + if (debug_mode) printf("thread %d going into accept for %d seconds\n", + info->id, info->accept_timeout + info->id); + + clientSock = PR_Accept(listenSock, &clientAddr, PR_SecondsToInterval(info->accept_timeout +info->id)); + + if (clientSock == NULL) { + if (PR_GetError() == PR_IO_TIMEOUT_ERROR) + if (debug_mode) { + printf("PR_Accept() timeout worked!\n"); + printf("TEST FAILED! PR_Accept() returned error %d\n", + PR_GetError()); + } + else failed_already=1; + } else { + if (debug_mode) printf ("TEST FAILED! PR_Accept() succeeded?\n"); + else failed_already=1; + PR_Close(clientSock); + } + +dead: + if (listenSock) { + PR_Close(listenSock); + } + PR_Lock(info->dead_lock); + (*info->alive)--; + PR_NotifyCondVar(info->dead_cv); + PR_Unlock(info->dead_lock); + + if (debug_mode) printf("thread %d is dead\n", info->id); +} + +void +thread_test(PRInt32 scope, PRInt32 num_threads) +{ + PRInt32 index; + PRThread *thr; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 alive; + + if (debug_mode) printf("IO Timeout test started with %d threads\n", num_threads); + + dead_lock = PR_NewLock(); + dead_cv = PR_NewCondVar(dead_lock); + alive = num_threads; + + for (index = 0; index < num_threads; index++) { + threadInfo *info = (threadInfo *)malloc(sizeof(threadInfo)); + + info->id = index; + info->dead_lock = dead_lock; + info->dead_cv = dead_cv; + info->alive = &alive; + info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT; + + thr = PR_CreateThread( PR_USER_THREAD, + thread_main, + (void *)info, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); + + if (!thr) { + PR_Lock(dead_lock); + alive--; + PR_Unlock(dead_lock); + } + } + + PR_Lock(dead_lock); + while(alive) { + if (debug_mode) printf("main loop awake; alive = %d\n", alive); + PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(dead_lock); +} + +int main(int argc, char **argv) +{ + PRInt32 num_threads; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + if (argc > 2) + num_threads = atoi(argv[2]); + else + num_threads = NUM_THREADS; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0); + PR_STDIO_INIT(); + + if (debug_mode) printf("kernel level test\n"); + thread_test(PR_GLOBAL_THREAD, num_threads); + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/nsprpub/pr/tests/io_timeoutu.c b/nsprpub/pr/tests/io_timeoutu.c new file mode 100644 index 00000000000..c17a93f759f --- /dev/null +++ b/nsprpub/pr/tests/io_timeoutu.c @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* +** name io_timeoutu.c +** Description: Test socket IO timeouts (user level) +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include "nspr.h" + +#define NUM_THREADS 1 +#define BASE_PORT 8000 +#define DEFAULT_ACCEPT_TIMEOUT 2 + +typedef struct threadInfo { + PRInt16 id; + PRInt16 accept_timeout; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 *alive; +} threadInfo; +PRIntn failed_already=0; +PRIntn debug_mode; + +void +thread_main(void *_info) +{ + threadInfo *info = (threadInfo *)_info; + PRNetAddr listenAddr; + PRNetAddr clientAddr; + PRFileDesc *listenSock = NULL; + PRFileDesc *clientSock; + PRStatus rv; + + if (debug_mode) printf("thread %d is alive\n", info->id); + + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + if (debug_mode) printf("unable to create listen socket\n"); + goto dead; + } + + listenAddr.inet.family = AF_INET; + listenAddr.inet.port = PR_htons(BASE_PORT + info->id); + listenAddr.inet.ip = PR_htonl(INADDR_ANY); + rv = PR_Bind(listenSock, &listenAddr); + if (rv == PR_FAILURE) { + if (debug_mode) printf("unable to bind\n"); + goto dead; + } + + rv = PR_Listen(listenSock, 4); + if (rv == PR_FAILURE) { + if (debug_mode) printf("unable to listen\n"); + goto dead; + } + + if (debug_mode) printf("thread %d going into accept for %d seconds\n", + info->id, info->accept_timeout + info->id); + + clientSock = PR_Accept( + listenSock, &clientAddr, PR_SecondsToInterval( + info->accept_timeout + info->id)); + + if (clientSock == NULL) { + if (PR_GetError() == PR_IO_TIMEOUT_ERROR) + if (debug_mode) { + printf("PR_Accept() timeout worked!\n"); + printf("TEST FAILED! PR_Accept() returned error %d\n", + } + PR_GetError()); + else failed_already=1; + } else { + if (debug_mode) printf ("TEST FAILED! PR_Accept() succeeded?\n"); + else failed_already=1; + PR_Close(clientSock); + } + +dead: + if (listenSock) { + PR_Close(listenSock); + } + PR_Lock(info->dead_lock); + (*info->alive)--; + PR_NotifyCondVar(info->dead_cv); + PR_Unlock(info->dead_lock); + + if (debug_mode) printf("thread %d is dead\n", info->id); +} + +void +thread_test(PRInt32 scope, PRInt32 num_threads) +{ + PRInt32 index; + PRThread *thr; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 alive; + + if (debug_mode) printf("IO Timeout test started with %d threads\n", num_threads); + + dead_lock = PR_NewLock(); + dead_cv = PR_NewCondVar(dead_lock); + alive = num_threads; + + for (index = 0; index < num_threads; index++) { + threadInfo *info = (threadInfo *)malloc(sizeof(threadInfo)); + + info->id = index; + info->dead_lock = dead_lock; + info->dead_cv = dead_cv; + info->alive = &alive; + info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT; + + thr = PR_CreateThread( PR_USER_THREAD, + thread_main, + (void *)info, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); + + if (!thr) { + PR_Lock(dead_lock); + alive--; + PR_Unlock(dead_lock); + } + } + + PR_Lock(dead_lock); + while(alive) { + if (debug_mode) printf("main loop awake; alive = %d\n", alive); + PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(dead_lock); +} + +int main(int argc, char **argv) +{ + PRInt32 num_threads; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + if (argc > 2) + num_threads = atoi(argv[2]); + else + num_threads = NUM_THREADS; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0); + PR_STDIO_INIT(); + + if (debug_mode) printf("user level test\n"); + thread_test(PR_LOCAL_THREAD, num_threads); + + PR_Cleanup(); + if(failed_already) + return 1; + else + return 0; + + +} diff --git a/nsprpub/pr/tests/ioconthr.c b/nsprpub/pr/tests/ioconthr.c new file mode 100644 index 00000000000..2e39522dfb1 --- /dev/null +++ b/nsprpub/pr/tests/ioconthr.c @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This is a test for the io continuation thread machinery + * in pthreads. + */ + +#include "nspr.h" +#include + +int num_threads = 10; /* must be an even number */ +PRThreadScope thread_scope = PR_GLOBAL_THREAD; + +void ThreadFunc(void *arg) +{ + PRFileDesc *fd = (PRFileDesc *) arg; + char buf[1024]; + PRInt32 nbytes; + PRErrorCode err; + + nbytes = PR_Recv(fd, buf, sizeof(buf), 0, PR_SecondsToInterval(20)); + if (nbytes == -1) { + err = PR_GetError(); + if (err != PR_PENDING_INTERRUPT_ERROR) { + fprintf(stderr, "PR_Recv failed: (%d, %d)\n", + err, PR_GetOSError()); + PR_ProcessExit(1); + } + /* + * After getting an I/O interrupt, this thread must + * close the fd before it exits due to a limitation + * of our NT implementation. + */ + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + PR_ProcessExit(1); + } + } else { + fprintf(stderr, "PR_Recv received %d bytes!?\n", nbytes); + PR_ProcessExit(1); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc **fds; + PRThread **threads; + PRIntervalTime start, elapsed; + int index; + + fds = (PRFileDesc **) PR_MALLOC(2 * num_threads * sizeof(PRFileDesc *)); + PR_ASSERT(fds != NULL); + threads = (PRThread **) PR_MALLOC(num_threads * sizeof(PRThread *)); + PR_ASSERT(threads != NULL); + + for (index = 0; index < num_threads; index++) { + if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + PR_ProcessExit(1); + } + threads[index] = PR_CreateThread( + PR_USER_THREAD, ThreadFunc, fds[2 * index], + PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0); + if (NULL == threads[index]) { + fprintf(stderr, "PR_CreateThread failed\n"); + PR_ProcessExit(1); + } + } + + /* Let the threads block in PR_Recv */ + PR_Sleep(PR_SecondsToInterval(2)); + + printf("Interrupting the threads\n"); + fflush(stdout); + start = PR_IntervalNow(); + for (index = 0; index < num_threads; index++) { + if (PR_Interrupt(threads[index]) == PR_FAILURE) { + fprintf(stderr, "PR_Interrupt failed\n"); + PR_ProcessExit(1); + } + } + for (index = 0; index < num_threads; index++) { + if (PR_JoinThread(threads[index]) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + PR_ProcessExit(1); + } + } + elapsed = (PRIntervalTime)(PR_IntervalNow() - start); + printf("Threads terminated in %d milliseconds\n", + PR_IntervalToMilliseconds(elapsed)); + fflush(stdout); + + /* We are being very generous and allow 10 seconds. */ + if (elapsed >= PR_SecondsToInterval(10)) { + fprintf(stderr, "Interrupting threads took longer than 10 seconds!!\n"); + PR_ProcessExit(1); + } + + for (index = 0; index < num_threads; index++) { + /* fds[2 * index] was passed to and closed by threads[index]. */ + if (PR_Close(fds[2 * index + 1]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + PR_ProcessExit(1); + } + } + PR_DELETE(threads); + PR_DELETE(fds); + printf("PASS\n"); + PR_Cleanup(); + return 0; +} diff --git a/nsprpub/pr/tests/ipv6.c b/nsprpub/pr/tests/ipv6.c new file mode 100644 index 00000000000..742239ae44e --- /dev/null +++ b/nsprpub/pr/tests/ipv6.c @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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" +#include "obsolete/probslet.h" + +#include + +#define DNS_BUFFER 100 +#define ADDR_BUFFER 100 +#define HOST_BUFFER 1024 +#define PROTO_BUFFER 1500 + +#define NETADDR_SIZE(addr) \ + (PR_AF_INET == (addr)->raw.family ? \ + sizeof((addr)->inet) : sizeof((addr)->ipv6)) + +static PRFileDesc *err = NULL; + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-V] [-h]\n"); + PR_fprintf(err, "\t Name of host to lookup (default: self)\n"); + PR_fprintf(err, "\t-V Display runtime version info (default: FALSE)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static void DumpAddr(const PRNetAddr* address, const char *msg) +{ + PRUint32 *word = (PRUint32*)address; + PRUint32 addr_len = sizeof(PRNetAddr); + PR_fprintf(err, "%s[%d]\t", msg, NETADDR_SIZE(address)); + while (addr_len > 0) + { + PR_fprintf(err, " %08x", *word++); + addr_len -= sizeof(PRUint32); + } + PR_fprintf(err, "\n"); +} /* DumpAddr */ + +static PRStatus PrintAddress(const PRNetAddr* address) +{ + PRNetAddr translation; + char buffer[ADDR_BUFFER]; + PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); + if (PR_FAILURE == rv) PL_FPrintError(err, "PR_NetAddrToString"); + else + { + PR_fprintf(err, "\t%s\n", buffer); + memset(&translation, 0, sizeof(translation)); + rv = PR_StringToNetAddr(buffer, &translation); + if (PR_FAILURE == rv) PL_FPrintError(err, "PR_StringToNetAddr"); + else + { + PRSize addr_len = NETADDR_SIZE(address); + if (0 != memcmp(address, &translation, addr_len)) + { + PR_fprintf(err, "Address translations do not match\n"); + DumpAddr(address, "original"); + DumpAddr(&translation, "translate"); + rv = PR_FAILURE; + } + } + } + return rv; +} /* PrintAddress */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PLOptStatus os; + PRHostEnt host; + PRProtoEnt proto; + const char *name = NULL; + PRBool failed = PR_FALSE, version = PR_FALSE; + PLOptState *opt = PL_CreateOptState(argc, argv, "Vh"); + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* Name of host to lookup */ + name = opt->value; + break; + case 'V': /* Do version discovery */ + version = PR_TRUE; + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + if (version) + { +#if defined(WINNT) +#define NSPR_LIB "libnspr4" +#else +#define NSPR_LIB "nspr4" +#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 (NULL == name) + { + char *me = (char*)PR_MALLOC(DNS_BUFFER); + rv = PR_GetSystemInfo(PR_SI_HOSTNAME, me, DNS_BUFFER); + if (PR_FAILURE == rv) + { + failed = PR_TRUE; + PL_FPrintError(err, "PR_GetSystemInfo"); + return 2; + } + name = me; /* just leak the storage */ + } + } + + { + char buffer[HOST_BUFFER]; + PR_fprintf(err, "Translating the name %s ...", name); + + rv = PR_GetHostByName(name, buffer, sizeof(buffer), &host); + if (PR_FAILURE == rv) + { + failed = PR_TRUE; + PL_FPrintError(err, "PR_GetHostByName"); + } + else + { + PRIntn index = 0; + PRNetAddr address; + memset(&address, 0, sizeof(PRNetAddr)); + PR_fprintf(err, "success .. enumerating results\n"); + do + { + index = PR_EnumerateHostEnt(index, &host, 0, &address); + if (index > 0) PrintAddress(&address); + else if (-1 == index) + { + failed = PR_TRUE; + PL_FPrintError(err, "PR_EnumerateHostEnt"); + } + } while (index > 0); + } + } + + + { + char buffer[PROTO_BUFFER]; + /* + ** Get Proto by name/number + */ + rv = PR_GetProtoByName("tcp", &buffer[1], sizeof(buffer) - 1, &proto); + rv = PR_GetProtoByNumber(6, &buffer[3], sizeof(buffer) - 3, &proto); + } + + return (failed) ? 1 : 0; +} diff --git a/nsprpub/pr/tests/join.c b/nsprpub/pr/tests/join.c new file mode 100644 index 00000000000..73d7eb83e61 --- /dev/null +++ b/nsprpub/pr/tests/join.c @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c +** +** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions. +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** 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. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" +#include "prttools.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static void Test_Result (int result) +{ + if (result == PASS) + printf ("PASS\n"); + else + printf ("FAIL\n"); + exit (1); +} + + +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void PR_CALLBACK lowPriority(void *arg) +{ +} + +static void PR_CALLBACK highPriority(void *arg) +{ +} + +static void PR_CALLBACK unjoinable(void *arg) +{ + PR_Sleep(PR_INTERVAL_NO_TIMEOUT); +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else Test_Result(FAIL); + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else Test_Result(FAIL); + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else Test_Result (FAIL); + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else Test_Result(FAIL); + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +void joinWithUnjoinable(void) +{ + PRThread *thread; + + /* create the unjoinable thread */ + + thread = PR_CreateThread(PR_USER_THREAD, + unjoinable, 0, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (!thread) { + if (debug_mode) printf("\tcannot create unjoinable thread\n"); + else Test_Result(FAIL); + return; + } + + if (PR_JoinThread(thread) == PR_SUCCESS) { + if (debug_mode) printf("\tsuccessfully joined with unjoinable thread?!\n"); + else Test_Result(FAIL); + return; + } else { + if (debug_mode) printf("\tcannot join with unjoinable thread, as expected\n"); + if (PR_GetError() != PR_INVALID_ARGUMENT_ERROR) { + if (debug_mode) printf("\tWrong error code\n"); + else Test_Result(FAIL); + return; + } + } + if (PR_Interrupt(thread) == PR_FAILURE) { + if (debug_mode) printf("\tcannot interrupt unjoinable thread\n"); + else Test_Result(FAIL); + return; + } else { + if (debug_mode) printf("\tinterrupted unjoinable thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain(int argc, char **argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + +#ifdef XP_MAC + SetupMacPrintfLog("join.log"); + debug_mode = 1; +#endif + + + + /* main test */ + printf("User-User test\n"); + runTest(PR_LOCAL_THREAD, PR_LOCAL_THREAD); + printf("User-Kernel test\n"); + runTest(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); + printf("Kernel-User test\n"); + runTest(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); + printf("Kernel-Kernel test\n"); + runTest(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); + printf("Join with unjoinable thread\n"); + joinWithUnjoinable(); + + printf("PASSED\n"); + + return 0; +} + + + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/joinkk.c b/nsprpub/pr/tests/joinkk.c new file mode 100644 index 00000000000..0fd991e5161 --- /dev/null +++ b/nsprpub/pr/tests/joinkk.c @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c +** +** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions. +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void lowPriority(void *arg) +{ +} + +static void highPriority(void *arg) +{ +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else failed_already=1; + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else failed_already=1; + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + +#ifdef XP_MAC + SetupMacPrintfLog("join.log"); +#endif + + + + /* main test */ + + if (debug_mode) printf("Kernel-Kernel test\n"); + runTest(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); + + if(failed_already) + { + printf("FAIL\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } + +} + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/joinku.c b/nsprpub/pr/tests/joinku.c new file mode 100644 index 00000000000..ecaa24c9ce7 --- /dev/null +++ b/nsprpub/pr/tests/joinku.c @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c +** +** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions. +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif +PRIntn failed_already=0; +PRIntn debug_mode; + + +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void lowPriority(void *arg) +{ +} + +static void highPriority(void *arg) +{ +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else failed_already=1; + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else failed_already=1; + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("joinku.log"); +#endif + + + + /* main test */ + + if (debug_mode) printf("Kernel-User test\n"); + runTest(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); + + + if(failed_already) + { + printf("FAIL\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } + +} + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/joinuk.c b/nsprpub/pr/tests/joinuk.c new file mode 100644 index 00000000000..1564731dd7b --- /dev/null +++ b/nsprpub/pr/tests/joinuk.c @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: joinuk.c +** +** Description: Join kernel - user +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif +PRIntn failed_already=0; +PRIntn debug_mode; +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void lowPriority(void *arg) +{ +} + +static void highPriority(void *arg) +{ +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else failed_already=1; + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else failed_already=1; + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("joinuk.log"); +#endif + + + + /* main test */ + + if (debug_mode) printf("User-Kernel test\n"); + runTest(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); + + + if(failed_already) + { + printf("FAIL\n"); + return 1; + } else + { + printf("PASS\n"); + return 0; + } +} + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/joinuu.c b/nsprpub/pr/tests/joinuu.c new file mode 100644 index 00000000000..ea0d2d705ea --- /dev/null +++ b/nsprpub/pr/tests/joinuu.c @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c +** +** Description: Join tests user - user +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif +PRIntn failed_already=0; +PRIntn debug_mode; + + +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void lowPriority(void *arg) +{ +} + +static void highPriority(void *arg) +{ +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else failed_already=1; + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else failed_already=1; + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("joinuu.log"); +#endif + + + + /* main test */ + if (debug_mode) printf("User-User test\n"); + runTest(PR_LOCAL_THREAD, PR_LOCAL_THREAD); + + if(failed_already) + { + printf("FAIL\n"); + return 1; + } else + { + printf("PASS\n"); + return 0; + } + + +} + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/layer.c b/nsprpub/pr/tests/layer.c new file mode 100644 index 00000000000..cb914ba0164 --- /dev/null +++ b/nsprpub/pr/tests/layer.c @@ -0,0 +1,466 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prprf.h" +#include "prlog.h" +#include "prnetdb.h" +#include "prthread.h" + +#include "plerror.h" +#include "plgetopt.h" +#include "prwin16.h" + +#include +#include + +/* +** Testing layering of I/O +** +** The layered server +** A thread that acts as a server. It creates a TCP listener with a dummy +** layer pushed on top. Then listens for incoming connections. Each connection +** request for connection will be layered as well, accept one request, echo +** it back and close. +** +** The layered client +** Pretty much what you'd expect. +*/ + +static PRFileDesc *logFile; +static PRDescIdentity identity; +static PRNetAddr server_address; + +static PRIOMethods myMethods; + +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; + +static PRIntn minor_iterations = 5; +static PRIntn major_iterations = 1; +static Verbosity verbosity = quiet; +static PRUint16 default_port = 12273; + +static PRFileDesc *PushLayer(PRFileDesc *stack) +{ + PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods); + PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); + PR_ASSERT(PR_SUCCESS == rv); + return stack; +} /* PushLayer */ + +static PRFileDesc *PushNewLayers(PRFileDesc *stack) +{ + PRDescIdentity tmp_identity; + PRFileDesc *layer; + PRStatus rv; + + /* push a dummy layer */ + tmp_identity = PR_GetUniqueIdentity("Dummy 1"); + layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods()); + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, + stack); + PR_ASSERT(PR_SUCCESS == rv); + + /* push a data procesing layer */ + layer = PR_CreateIOLayerStub(identity, &myMethods); + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, + stack); + PR_ASSERT(PR_SUCCESS == rv); + + /* push another dummy layer */ + tmp_identity = PR_GetUniqueIdentity("Dummy 2"); + layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods()); + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, + stack); + PR_ASSERT(PR_SUCCESS == rv); + return stack; +} /* PushLayer */ + +#if 0 +static PRFileDesc *PopLayer(PRFileDesc *stack) +{ + PRFileDesc *popped = PR_PopIOLayer(stack, identity); + if (verbosity > quiet) + PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack); + popped->dtor(popped); + + return stack; +} /* PopLayer */ +#endif + +static void PR_CALLBACK Client(void *arg) +{ + PRStatus rv; + PRUint8 buffer[100]; + PRIntn empty_flags = 0; + PRIntn bytes_read, bytes_sent; + PRFileDesc *stack = (PRFileDesc*)arg; + + /* Initialize the buffer so that Purify won't complain */ + memset(buffer, 0, sizeof(buffer)); + + rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(PR_SUCCESS == rv); + while (minor_iterations-- > 0) + { + bytes_sent = PR_Send( + stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(sizeof(buffer) == bytes_sent); + if (verbosity > chatty) + PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent); + bytes_read = PR_Recv( + stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read); + PR_ASSERT(bytes_read == bytes_sent); + } + + if (verbosity > quiet) + PR_fprintf(logFile, "Client shutting down stack\n"); + + rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); +} /* Client */ + +static void PR_CALLBACK Server(void *arg) +{ + PRStatus rv; + PRUint8 buffer[100]; + PRFileDesc *service; + PRUintn empty_flags = 0; + PRIntn bytes_read, bytes_sent; + PRFileDesc *stack = (PRFileDesc*)arg; + PRNetAddr client_address; + + service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > quiet) + PR_fprintf(logFile, "Server accepting connection\n"); + + do + { + bytes_read = PR_Recv( + service, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (0 != bytes_read) + { + if (verbosity > chatty) + PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read); + PR_ASSERT(bytes_read > 0); + bytes_sent = PR_Send( + service, buffer, bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent); + PR_ASSERT(bytes_read == bytes_sent); + } + + } while (0 != bytes_read); + + if (verbosity > quiet) + PR_fprintf(logFile, "Server shutting down and closing stack\n"); + rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); + +} /* Server */ + +static PRInt32 PR_CALLBACK MyRecv( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + char *b = (char*)buf; + PRFileDesc *lo = fd->lower; + PRInt32 rv, readin = 0, request = 0; + rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout); + if (verbosity > chatty) PR_fprintf( + logFile, "MyRecv sending permission for %d bytes\n", request); + if (0 < rv) + { + if (verbosity > chatty) PR_fprintf( + logFile, "MyRecv received permission request for %d bytes\n", request); + rv = lo->methods->send( + lo, &request, sizeof(request), flags, timeout); + if (0 < rv) + { + if (verbosity > chatty) PR_fprintf( + logFile, "MyRecv sending permission for %d bytes\n", request); + while (readin < request) + { + rv = lo->methods->recv( + lo, b + readin, amount - readin, flags, timeout); + if (rv <= 0) break; + if (verbosity > chatty) PR_fprintf( + logFile, "MyRecv received %d bytes\n", rv); + readin += rv; + } + rv = readin; + } + } + return rv; +} /* MyRecv */ + +static PRInt32 PR_CALLBACK MySend( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + PRFileDesc *lo = fd->lower; + const char *b = (const char*)buf; + PRInt32 rv, wroteout = 0, request; + if (verbosity > chatty) PR_fprintf( + logFile, "MySend asking permission to send %d bytes\n", amount); + rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout); + if (0 < rv) + { + rv = lo->methods->recv( + lo, &request, sizeof(request), flags, timeout); + if (0 < rv) + { + PR_ASSERT(request == amount); + if (verbosity > chatty) PR_fprintf( + logFile, "MySend got permission to send %d bytes\n", request); + while (wroteout < request) + { + rv = lo->methods->send( + lo, b + wroteout, request - wroteout, flags, timeout); + if (rv <= 0) break; + if (verbosity > chatty) PR_fprintf( + logFile, "MySend wrote %d bytes\n", rv); + wroteout += rv; + } + rv = amount; + } + } + return rv; +} /* MySend */ + +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) +{ + PRIntn verbage = (PRIntn)verbosity + delta; + if (verbage < (PRIntn)silent) verbage = (PRIntn)silent; + else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy; + return (Verbosity)verbage; +} /* ChangeVerbosity */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PRIntn mits; + PLOptStatus os; + PRFileDesc *client, *service; + PRFileDesc *client_stack, *service_stack; + PRNetAddr any_address; + const char *server_name = NULL; + const PRIOMethods *stubMethods; + PRThread *client_thread, *server_thread; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + server_name = opt->value; + break; + case 'd': /* debug mode */ + if (verbosity < noisy) + verbosity = ChangeVerbosity(verbosity, 1); + break; + case 'q': /* debug mode */ + if (verbosity > silent) + verbosity = ChangeVerbosity(verbosity, -1); + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'C': /* number of threads waiting */ + major_iterations = atoi(opt->value); + break; + case 'c': /* number of client threads */ + minor_iterations = atoi(opt->value); + break; + case 'p': /* default port */ + default_port = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + + logFile = PR_GetSpecialFD(PR_StandardError); + + identity = PR_GetUniqueIdentity("Dummy"); + stubMethods = PR_GetDefaultIOMethods(); + + /* + ** The protocol we're going to implement is one where in order to initiate + ** a send, the sender must first solicit permission. Therefore, every + ** send is really a send - receive - send sequence. + */ + myMethods = *stubMethods; /* first get the entire batch */ + myMethods.recv = MyRecv; /* then override the ones we care about */ + myMethods.send = MySend; /* then override the ones we care about */ + + if (NULL == server_name) + rv = PR_InitializeNetAddr( + PR_IpAddrLoopback, default_port, &server_address); + else + { + rv = PR_StringToNetAddr(server_name, &server_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_InitializeNetAddr( + PR_IpAddrNull, default_port, &server_address); + } + PR_ASSERT(PR_SUCCESS == rv); + + /* one type w/o layering */ + + mits = minor_iterations; + while (major_iterations-- > 0) + { + if (verbosity > silent) + PR_fprintf(logFile, "Beginning non-layered test\n"); + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + minor_iterations = mits; + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + 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 non-layered test\n"); + + /* with layering */ + if (verbosity > silent) + PR_fprintf(logFile, "Beginning layered test\n"); + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + PushLayer(client); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + PushLayer(service); + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + minor_iterations = mits; + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); + /* with layering, using new style stack */ + if (verbosity > silent) + PR_fprintf(logFile, + "Beginning layered test with new style stack\n"); + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + client_stack = PR_CreateIOLayer(client); + PushNewLayers(client_stack); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + service_stack = PR_CreateIOLayer(service); + PushNewLayers(service_stack); + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + minor_iterations = mits; + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service_stack, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client_stack, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_Close(client_stack); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service_stack); PR_ASSERT(PR_SUCCESS == rv); + if (verbosity > silent) + PR_fprintf(logFile, "Ending layered test\n"); + } + return 0; +} /* main */ + +/* layer.c */ diff --git a/nsprpub/pr/tests/lazyinit.c b/nsprpub/pr/tests/lazyinit.c new file mode 100644 index 00000000000..09f0b6fa2a9 --- /dev/null +++ b/nsprpub/pr/tests/lazyinit.c @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: lazyinit.c +** Description: Testing lazy initialization +** +** Since you only get to initialize once, you have to rerun the test +** for each test case. The test cases are numbered. If you want to +** add more tests, take the next number and add it to the switch +** statement. +** +** This test is problematic on systems that don't support the notion +** of console output. The workarounds to emulate that feature include +** initializations themselves, which defeats the purpose here. +*/ + +#include "prcvar.h" +#include "prenv.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prthread.h" +#include "prtypes.h" + +#include +#include + +static void PR_CALLBACK lazyEntry(void *arg) +{ + PR_ASSERT(NULL == arg); +} /* lazyEntry */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRUintn pdkey; + PRStatus status; + char *path = NULL; + PRDir *dir = NULL; + PRLock *ml = NULL; + PRCondVar *cv = NULL; + PRThread *thread = NULL; + PRIntervalTime interval = 0; + PRFileDesc *file, *udp, *tcp, *pair[2]; + PRIntn test; + + if ( argc < 2) + { + test = 0; + } + else + test = atoi(argv[1]); + + switch (test) + { + case 0: ml = PR_NewLock(); + break; + + case 1: interval = PR_SecondsToInterval(1); + break; + + case 2: thread = PR_CreateThread( + PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + break; + + case 3: file = PR_Open("/usr/tmp/", PR_RDONLY, 0); + break; + + case 4: udp = PR_NewUDPSocket(); + break; + + case 5: tcp = PR_NewTCPSocket(); + break; + + case 6: dir = PR_OpenDir("/usr/tmp/"); + break; + + case 7: (void)PR_NewThreadPrivateIndex(&pdkey, NULL); + break; + + case 8: path = PR_GetEnv("PATH"); + break; + + case 9: status = PR_NewTCPSocketPair(pair); + break; + + case 10: PR_SetConcurrency(2); + break; + + default: + printf( + "lazyinit: unrecognized command line argument: %s\n", + argv[1] ); + printf( "FAIL\n" ); + exit( 1 ); + break; + } /* switch() */ + return 0; +} /* Lazy */ + +/* lazyinit.c */ diff --git a/nsprpub/pr/tests/libfilename.c b/nsprpub/pr/tests/libfilename.c new file mode 100644 index 00000000000..ab482936dc4 --- /dev/null +++ b/nsprpub/pr/tests/libfilename.c @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: libfilename.c +** +** Description: test PR_GetLibraryFilePathname. +** +***********************************************************************/ + +#include "nspr.h" +#include "pprio.h" +#include +#include +#include + +PRBool debug_mode = PR_FALSE; + +static PRStatus RunTest(const char *name, PRFuncPtr addr) +{ + char *pathname; + PRFileDesc *fd; + + pathname = PR_GetLibraryFilePathname(name, addr); + if (pathname == NULL) { + fprintf(stderr, "PR_GetLibraryFilePathname failed\n"); + /* we let this test pass if this function is not implemented */ + if (PR_GetError() == PR_NOT_IMPLEMENTED_ERROR) { + return PR_SUCCESS; + } + return PR_FAILURE; + } + + if (debug_mode) printf("Pathname is %s\n", pathname); + fd = PR_OpenFile(pathname, PR_RDONLY, 0); + if (fd == NULL) { + fprintf(stderr, "PR_Open failed: %d\n", (int)PR_GetError()); + return PR_FAILURE; + } + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed: %d\n", (int)PR_GetError()); + return PR_FAILURE; + } + PR_Free(pathname); + return PR_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + char *name; + PRFuncPtr addr; + PRLibrary *lib; + PRBool failed = PR_FALSE; + + if (argc >= 2 && strcmp(argv[1], "-d") == 0) { + debug_mode = PR_TRUE; + } + + /* First test a library that is implicitly linked. */ +#ifdef WINNT + name = PR_Malloc(strlen("libnspr4.dll")+1); + strcpy(name, "libnspr4.dll"); +#else + name = PR_GetLibraryName(NULL, "nspr4"); +#endif + addr = (PRFuncPtr)PR_GetTCPMethods()->close; + if (RunTest(name, addr) == PR_FAILURE) { + failed = PR_TRUE; + } + PR_FreeLibraryName(name); + + /* Next test a library that is dynamically loaded. */ + name = PR_GetLibraryName("dll", "my"); + if (debug_mode) printf("Loading library %s\n", name); + lib = PR_LoadLibrary(name); + if (!lib) { + fprintf(stderr, "PR_LoadLibrary failed\n"); + exit(1); + } + PR_FreeLibraryName(name); + name = PR_GetLibraryName(NULL, "my"); + addr = PR_FindFunctionSymbol(lib, "My_GetValue"); + if (RunTest(name, addr) == PR_FAILURE) { + failed = PR_TRUE; + } + PR_FreeLibraryName(name); + PR_UnloadLibrary(lib); + if (failed) { + printf("FAIL\n"); + return 1; + } + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/lltest.c b/nsprpub/pr/tests/lltest.c new file mode 100644 index 00000000000..f8ce4c6ab92 --- /dev/null +++ b/nsprpub/pr/tests/lltest.c @@ -0,0 +1,859 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** testll.c -- test suite for 64bit integer (longlong) operations +** +** Summary: testll [-d] | [-h] +** +** Where: +** -d set debug mode on; displays individual test failures +** -v verbose mode; displays progress in test, plus -d +** -h gives usage message. +** +** Description: +** lltest.c tests the functions defined in NSPR 2.0's prlong.h. +** +** Successive tests begin to depend on other LL functions working +** correctly. So, ... Do not change the order of the tests as run +** from main(). +** +** Caveats: +** Do not even begin to think that this is an exhaustive test! +** +** These tests try a little of everything, but not all boundary +** conditions and limits are tested. +** You want better coverage? ... Add it. +** +** --- +** Author: Lawrence Hardiman . +** --- +** Revision History: +** 01-Oct-1997. Original implementation. +** +*/ + +#include "nspr.h" +#include "plgetopt.h" + +/* --- Local Definitions --- */ +#define ReportProgress(m) if (verboseMode) PR_fprintf(output, (m)); + + +/* --- Global variables --- */ +static PRIntn failedAlready = 0; +static PRFileDesc* output = NULL; +static PRBool debugMode = PR_FALSE; +static PRBool verboseMode = PR_FALSE; + +/* +** Constants used in tests. +*/ +const PRInt64 bigZero = LL_INIT( 0, 0 ); +const PRInt64 bigOne = LL_INIT( 0, 1 ); +const PRInt64 bigTwo = LL_INIT( 0, 2 ); +const PRInt64 bigSixTeen = LL_INIT( 0, 16 ); +const PRInt64 bigThirtyTwo = LL_INIT( 0, 32 ); +const PRInt64 bigMinusOne = LL_INIT( 0xffffffff, 0xffffffff ); +const PRInt64 bigMinusTwo = LL_INIT( 0xffffffff, 0xfffffffe ); +const PRInt64 bigNumber = LL_INIT( 0x7fffffff, 0xffffffff ); +const PRInt64 bigMinusNumber = LL_INIT( 0x80000000, 0x00000001 ); +const PRInt64 bigMaxInt32 = LL_INIT( 0x00000000, 0x7fffffff ); +const PRInt64 big2To31 = LL_INIT( 0x00000000, 0x80000000 ); +const PRUint64 bigZeroFox = LL_INIT( 0x00000000, 0xffffffff ); +const PRUint64 bigFoxFox = LL_INIT( 0xffffffff, 0xffffffff ); +const PRUint64 bigFoxZero = LL_INIT( 0xffffffff, 0x00000000 ); +const PRUint64 bigEightZero = LL_INIT( 0x80000000, 0x00000000 ); +const PRUint64 big64K = LL_INIT( 0x00000000, 0x00010000 ); +const PRInt64 bigInt0 = LL_INIT( 0x01a00000, 0x00001000 ); +const PRInt64 bigInt1 = LL_INIT( 0x01a00000, 0x00001100 ); +const PRInt64 bigInt2 = LL_INIT( 0x01a00000, 0x00000100 ); +const PRInt64 bigInt3 = LL_INIT( 0x01a00001, 0x00001000 ); +const PRInt64 bigInt4 = LL_INIT( 0x01a00001, 0x00001100 ); +const PRInt64 bigInt5 = LL_INIT( 0x01a00001, 0x00000100 ); +const PRInt64 bigInt6 = LL_INIT( 0xb1a00000, 0x00001000 ); +const PRInt64 bigInt7 = LL_INIT( 0xb1a00000, 0x00001100 ); +const PRInt64 bigInt8 = LL_INIT( 0xb1a00000, 0x00000100 ); +const PRInt64 bigInt9 = LL_INIT( 0xb1a00001, 0x00001000 ); +const PRInt64 bigInt10 = LL_INIT( 0xb1a00001, 0x00001100 ); +const PRInt64 bigInt11 = LL_INIT( 0xb1a00001, 0x00000100 ); +const PRInt32 one = 1l; +const PRInt32 minusOne = -1l; +const PRInt32 sixteen = 16l; +const PRInt32 thirtyTwo = 32l; +const PRInt32 sixtyThree = 63l; + +/* +** SetFailed() -- Report individual test failure +** +*/ +static void +SetFailed( char *what, char *how ) +{ + failedAlready = 1; + if ( debugMode ) + PR_fprintf(output, "%s: failed: %s\n", what, how ); + return; +} + +static void +ResultFailed( char *what, char *how, PRInt64 expected, PRInt64 got) +{ + if ( debugMode) + { + SetFailed( what, how ); + PR_fprintf(output, "Expected: 0x%llx Got: 0x%llx\n", expected, got ); + } + return; +} + + +/* +** TestAssignment() -- Test the assignment +*/ +static void TestAssignment( void ) +{ + PRInt64 zero = LL_Zero(); + PRInt64 min = LL_MinInt(); + PRInt64 max = LL_MaxInt(); + if (!LL_EQ(zero, bigZero)) + SetFailed("LL_EQ(zero, bigZero)", "!="); + if (!LL_CMP(max, >, min)) + SetFailed("LL_CMP(max, >, min)", "!>"); +} + +/* +** TestComparisons() -- Test the longlong comparison operations +*/ +static void +TestComparisons( void ) +{ + ReportProgress("Testing Comparisons Operations\n"); + + /* test for zero */ + if ( !LL_IS_ZERO( bigZero )) + SetFailed( "LL_IS_ZERO", "Zero is not zero" ); + + if ( LL_IS_ZERO( bigOne )) + SetFailed( "LL_IS_ZERO", "One tests as zero" ); + + if ( LL_IS_ZERO( bigMinusOne )) + SetFailed( "LL_IS_ZERO", "Minus One tests as zero" ); + + /* test equal */ + if ( !LL_EQ( bigZero, bigZero )) + SetFailed( "LL_EQ", "zero EQ zero"); + + if ( !LL_EQ( bigOne, bigOne )) + SetFailed( "LL_EQ", "one EQ one" ); + + if ( !LL_EQ( bigNumber, bigNumber )) + SetFailed( "LL_EQ", "bigNumber EQ bigNumber" ); + + if ( !LL_EQ( bigMinusOne, bigMinusOne )) + SetFailed( "LL_EQ", "minus one EQ minus one"); + + if ( LL_EQ( bigZero, bigOne )) + SetFailed( "LL_EQ", "zero EQ one"); + + if ( LL_EQ( bigOne, bigZero )) + SetFailed( "LL_EQ", "one EQ zero" ); + + if ( LL_EQ( bigMinusOne, bigOne )) + SetFailed( "LL_EQ", "minus one EQ one"); + + if ( LL_EQ( bigNumber, bigOne )) + SetFailed( "LL_EQ", "bigNumber EQ one"); + + /* test not equal */ + if ( LL_NE( bigZero, bigZero )) + SetFailed( "LL_NE", "0 NE 0"); + + if ( LL_NE( bigOne, bigOne )) + SetFailed( "LL_NE", "1 NE 1"); + + if ( LL_NE( bigMinusOne, bigMinusOne )) + SetFailed( "LL_NE", "-1 NE -1"); + + if ( LL_NE( bigNumber, bigNumber )) + SetFailed( "LL_NE", "n NE n"); + + if ( LL_NE( bigMinusNumber, bigMinusNumber )) + SetFailed( "LL_NE", "-n NE -n"); + + if ( !LL_NE( bigZero, bigOne)) + SetFailed( "LL_NE", "0 NE 1"); + + if ( !LL_NE( bigOne, bigMinusNumber)) + SetFailed( "LL_NE", "1 NE -n"); + + /* Greater than or equal to zero */ + if ( !LL_GE_ZERO( bigZero )) + SetFailed( "LL_GE_ZERO", "0"); + + if ( !LL_GE_ZERO( bigOne )) + SetFailed( "LL_GE_ZERO", "1"); + + if ( !LL_GE_ZERO( bigNumber )) + SetFailed( "LL_GE_ZERO", "n"); + + if ( LL_GE_ZERO( bigMinusOne )) + SetFailed( "LL_GE_ZERO", "-1"); + + if ( LL_GE_ZERO( bigMinusNumber )) + SetFailed( "LL_GE_ZERO", "-n"); + + /* Algebraic Compare two values */ + if ( !LL_CMP( bigZero, ==, bigZero )) + SetFailed( "LL_CMP", "0 == 0"); + + if ( LL_CMP( bigZero, >, bigZero )) + SetFailed( "LL_CMP", "0 > 0"); + + if ( LL_CMP( bigZero, <, bigZero )) + SetFailed( "LL_CMP", "0 < 0"); + + if ( LL_CMP( bigNumber, <, bigOne )) + SetFailed( "LL_CMP", "n < 1"); + + if ( !LL_CMP( bigNumber, >, bigOne )) + SetFailed( "LL_CMP", "n <= 1"); + + if ( LL_CMP( bigOne, >, bigNumber )) + SetFailed( "LL_CMP", "1 > n"); + + if ( LL_CMP( bigMinusNumber, >, bigNumber )) + SetFailed( "LL_CMP", "-n > n"); + + if ( LL_CMP( bigNumber, !=, bigNumber)) + SetFailed( "LL_CMP", "n != n"); + + if ( !LL_CMP( bigMinusOne, >, bigMinusTwo )) + SetFailed( "LL_CMP", "-1 <= -2"); + + if ( !LL_CMP( bigMaxInt32, <, big2To31 )) + SetFailed( "LL_CMP", "Max 32-bit signed int >= 2^31"); + + /* Two positive numbers */ + if ( !LL_CMP( bigInt0, <=, bigInt0 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt0, <=, bigInt1 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( LL_CMP( bigInt0, <=, bigInt2 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt0, <=, bigInt3 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt0, <=, bigInt4 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt0, <=, bigInt5 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + /* Two negative numbers */ + if ( !LL_CMP( bigInt6, <=, bigInt6 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt6, <=, bigInt7 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( LL_CMP( bigInt6, <=, bigInt8 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt6, <=, bigInt9 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt6, <=, bigInt10 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt6, <=, bigInt11 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + /* One positive, one negative */ + if ( LL_CMP( bigInt0, <=, bigInt6 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( LL_CMP( bigInt0, <=, bigInt7 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( LL_CMP( bigInt0, <=, bigInt8 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + /* Bitwise Compare two numbers */ + if ( !LL_UCMP( bigZero, ==, bigZero )) + SetFailed( "LL_UCMP", "0 == 0"); + + if ( LL_UCMP( bigZero, >, bigZero )) + SetFailed( "LL_UCMP", "0 > 0"); + + if ( LL_UCMP( bigZero, <, bigZero )) + SetFailed( "LL_UCMP", "0 < 0"); + + if ( LL_UCMP( bigNumber, <, bigOne )) + SetFailed( "LL_UCMP", "n < 1"); + + if ( !LL_UCMP( bigNumber, >, bigOne )) + SetFailed( "LL_UCMP", "n < 1"); + + if ( LL_UCMP( bigOne, >, bigNumber )) + SetFailed( "LL_UCMP", "1 > n"); + + if ( LL_UCMP( bigMinusNumber, <, bigNumber )) + SetFailed( "LL_UCMP", "-n < n"); + + /* Two positive numbers */ + if ( !LL_UCMP( bigInt0, <=, bigInt0 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt1 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( LL_UCMP( bigInt0, <=, bigInt2 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt3 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt4 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt5 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + /* Two negative numbers */ + if ( !LL_UCMP( bigInt6, <=, bigInt6 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt6, <=, bigInt7 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( LL_UCMP( bigInt6, <=, bigInt8 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt6, <=, bigInt9 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt6, <=, bigInt10 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt6, <=, bigInt11 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + /* One positive, one negative */ + if ( !LL_UCMP( bigInt0, <=, bigInt6 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt7 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt8 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + return; +} + +/* +** TestLogicalOperations() -- Tests for AND, OR, ... +** +*/ +static void +TestLogicalOperations( void ) +{ + PRUint64 result, result2; + + ReportProgress("Testing Logical Operations\n"); + + /* Test AND */ + LL_AND( result, bigZero, bigZero ); + if ( !LL_IS_ZERO( result )) + ResultFailed( "LL_AND", "0 & 0", bigZero, result ); + + LL_AND( result, bigOne, bigOne ); + if ( LL_IS_ZERO( result )) + ResultFailed( "LL_AND", "1 & 1", bigOne, result ); + + LL_AND( result, bigZero, bigOne ); + if ( !LL_IS_ZERO( result )) + ResultFailed( "LL_AND", "1 & 1", bigZero, result ); + + LL_AND( result, bigMinusOne, bigMinusOne ); + if ( !LL_UCMP( result, ==, bigMinusOne )) + ResultFailed( "LL_AND", "-1 & -1", bigMinusOne, result ); + + /* test OR */ + LL_OR( result, bigZero, bigZero ); + if ( !LL_IS_ZERO( result )) + ResultFailed( "LL_OR", "0 | 1", bigZero, result); + + LL_OR( result, bigZero, bigOne ); + if ( LL_IS_ZERO( result )) + ResultFailed( "LL_OR", "0 | 1", bigOne, result ); + + LL_OR( result, bigZero, bigMinusNumber ); + if ( !LL_UCMP( result, ==, bigMinusNumber )) + ResultFailed( "LL_OR", "0 | -n", bigMinusNumber, result); + + LL_OR( result, bigMinusNumber, bigZero ); + if ( !LL_UCMP( result, ==, bigMinusNumber )) + ResultFailed( "LL_OR", "-n | 0", bigMinusNumber, result ); + + /* test XOR */ + LL_XOR( result, bigZero, bigZero ); + if ( LL_UCMP( result, !=, bigZero )) + ResultFailed( "LL_XOR", "0 ^ 0", bigZero, result); + + LL_XOR( result, bigOne, bigZero ); + if ( LL_UCMP( result, !=, bigOne )) + ResultFailed( "LL_XOR", "1 ^ 0", bigZero, result ); + + LL_XOR( result, bigMinusNumber, bigZero ); + if ( LL_UCMP( result, !=, bigMinusNumber )) + ResultFailed( "LL_XOR", "-n ^ 0", bigMinusNumber, result ); + + LL_XOR( result, bigMinusNumber, bigMinusNumber ); + if ( LL_UCMP( result, !=, bigZero )) + ResultFailed( "LL_XOR", "-n ^ -n", bigMinusNumber, result); + + /* test OR2. */ + result = bigZero; + LL_OR2( result, bigOne ); + if ( LL_UCMP( result, !=, bigOne )) + ResultFailed( "LL_OR2", "(r=0) |= 1", bigOne, result); + + result = bigOne; + LL_OR2( result, bigNumber ); + if ( LL_UCMP( result, !=, bigNumber )) + ResultFailed( "LL_OR2", "(r=1) |= n", bigNumber, result); + + result = bigMinusNumber; + LL_OR2( result, bigMinusNumber ); + if ( LL_UCMP( result, !=, bigMinusNumber )) + ResultFailed( "LL_OR2", "(r=-n) |= -n", bigMinusNumber, result); + + /* test NOT */ + LL_NOT( result, bigMinusNumber); + LL_NOT( result2, result); + if ( LL_UCMP( result2, !=, bigMinusNumber )) + ResultFailed( "LL_NOT", "r != ~(~-n)", bigMinusNumber, result); + + /* test Negation */ + LL_NEG( result, bigMinusNumber ); + LL_NEG( result2, result ); + if ( LL_CMP( result2, !=, bigMinusNumber )) + ResultFailed( "LL_NEG", "r != -(-(-n))", bigMinusNumber, result); + + return; +} + + + +/* +** TestConversion() -- Test Conversion Operations +** +*/ +static void +TestConversion( void ) +{ + PRInt64 result; + PRInt64 resultU; + PRInt32 result32; + PRUint32 resultU32; + float resultF; + PRFloat64 resultD; + + ReportProgress("Testing Conversion Operations\n"); + + /* LL_L2I -- Convert to signed 32bit */ + LL_L2I(result32, bigOne ); + if ( result32 != one ) + SetFailed( "LL_L2I", "r != 1"); + + LL_L2I(result32, bigMinusOne ); + if ( result32 != minusOne ) + SetFailed( "LL_L2I", "r != -1"); + + /* LL_L2UI -- Convert 64bit to unsigned 32bit */ + LL_L2UI( resultU32, bigMinusOne ); + if ( resultU32 != (PRUint32) minusOne ) + SetFailed( "LL_L2UI", "r != -1"); + + LL_L2UI( resultU32, bigOne ); + if ( resultU32 != (PRUint32) one ) + SetFailed( "LL_L2UI", "r != 1"); + + /* LL_L2F -- Convert to 32bit floating point */ + LL_L2F( resultF, bigOne ); + if ( resultF != 1.0 ) + SetFailed( "LL_L2F", "r != 1.0"); + + LL_L2F( resultF, bigMinusOne ); + if ( resultF != -1.0 ) + SetFailed( "LL_L2F", "r != 1.0"); + + /* LL_L2D -- Convert to 64bit floating point */ + LL_L2D( resultD, bigOne ); + if ( resultD != 1.0L ) + SetFailed( "LL_L2D", "r != 1.0"); + + LL_L2D( resultD, bigMinusOne ); + if ( resultD != -1.0L ) + SetFailed( "LL_L2D", "r != -1.0"); + + /* LL_I2L -- Convert 32bit signed to 64bit signed */ + LL_I2L( result, one ); + if ( LL_CMP(result, !=, bigOne )) + SetFailed( "LL_I2L", "r != 1"); + + LL_I2L( result, minusOne ); + if ( LL_CMP(result, !=, bigMinusOne )) + SetFailed( "LL_I2L", "r != -1"); + + /* LL_UI2L -- Convert 32bit unsigned to 64bit unsigned */ + LL_UI2L( resultU, (PRUint32) one ); + if ( LL_CMP(resultU, !=, bigOne )) + SetFailed( "LL_UI2L", "r != 1"); + + /* [lth.] This did not behave as expected, but it is correct + */ + LL_UI2L( resultU, (PRUint32) minusOne ); + if ( LL_CMP(resultU, !=, bigZeroFox )) + ResultFailed( "LL_UI2L", "r != -1", bigZeroFox, resultU); + + /* LL_F2L -- Convert 32bit float to 64bit signed */ + LL_F2L( result, 1.0 ); + if ( LL_CMP(result, !=, bigOne )) + SetFailed( "LL_F2L", "r != 1"); + + LL_F2L( result, -1.0 ); + if ( LL_CMP(result, !=, bigMinusOne )) + SetFailed( "LL_F2L", "r != -1"); + + /* LL_D2L -- Convert 64bit Float to 64bit signed */ + LL_D2L( result, 1.0L ); + if ( LL_CMP(result, !=, bigOne )) + SetFailed( "LL_D2L", "r != 1"); + + LL_D2L( result, -1.0L ); + if ( LL_CMP(result, !=, bigMinusOne )) + SetFailed( "LL_D2L", "r != -1"); + + return; +} + +static void ShiftCompileOnly() +{ + /* + ** This function is only compiled, never called. + ** The real test is to see if it compiles w/o + ** warnings. This is no small feat, by the way. + */ + PRInt64 ia, ib; + PRUint64 ua, ub; + LL_SHR(ia, ib, 32); + LL_SHL(ia, ib, 32); + + LL_USHR(ua, ub, 32); + LL_ISHL(ia, 49, 32); + +} /* ShiftCompileOnly */ + + +/* +** TestShift() -- Test Shifting Operations +** +*/ +static void +TestShift( void ) +{ + static const PRInt64 largeTwoZero = LL_INIT( 0x00000002, 0x00000000 ); + PRInt64 result; + PRUint64 resultU; + + ReportProgress("Testing Shifting Operations\n"); + + /* LL_SHL -- Shift left algebraic */ + LL_SHL( result, bigOne, one ); + if ( LL_CMP( result, !=, bigTwo )) + ResultFailed( "LL_SHL", "r != 2", bigOne, result ); + + LL_SHL( result, bigTwo, thirtyTwo ); + if ( LL_CMP( result, !=, largeTwoZero )) + ResultFailed( "LL_SHL", "r != twoZero", largeTwoZero, result); + + /* LL_SHR -- Shift right algebraic */ + LL_SHR( result, bigFoxZero, thirtyTwo ); + if ( LL_CMP( result, !=, bigMinusOne )) + ResultFailed( "LL_SHR", "r != -1", bigMinusOne, result); + + LL_SHR( result, bigTwo, one ); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_SHR", "r != 1", bigOne, result); + + LL_SHR( result, bigFoxFox, thirtyTwo ); + if ( LL_CMP( result, !=, bigMinusOne )) + ResultFailed( "LL_SHR", "r != -1 (was ff,ff)", bigMinusOne, result); + + /* LL_USHR -- Logical shift right */ + LL_USHR( resultU, bigZeroFox, thirtyTwo ); + if ( LL_UCMP( resultU, !=, bigZero )) + ResultFailed( "LL_USHR", "r != 0 ", bigZero, result); + + LL_USHR( resultU, bigFoxFox, thirtyTwo ); + if ( LL_UCMP( resultU, !=, bigZeroFox )) + ResultFailed( "LL_USHR", "r != 0 ", bigZeroFox, result); + + /* LL_ISHL -- Shift a 32bit integer into a 64bit result */ + LL_ISHL( resultU, minusOne, thirtyTwo ); + if ( LL_UCMP( resultU, !=, bigFoxZero )) + ResultFailed( "LL_ISHL", "r != ff,00 ", bigFoxZero, result); + + LL_ISHL( resultU, one, sixtyThree ); + if ( LL_UCMP( resultU, !=, bigEightZero )) + ResultFailed( "LL_ISHL", "r != 80,00 ", bigEightZero, result); + + LL_ISHL( resultU, one, sixteen ); + if ( LL_UCMP( resultU, !=, big64K )) + ResultFailed( "LL_ISHL", "r != 64K ", big64K, resultU); + + return; +} + + +/* +** TestArithmetic() -- Test arithmetic operations. +** +*/ +static void +TestArithmetic( void ) +{ + PRInt64 largeVal = LL_INIT( 0x00000001, 0xffffffff ); + PRInt64 largeValPlusOne = LL_INIT( 0x00000002, 0x00000000 ); + PRInt64 largeValTimesTwo = LL_INIT( 0x00000003, 0xfffffffe ); + PRInt64 largeMultCand = LL_INIT( 0x00000000, 0x7fffffff ); + PRInt64 largeMinusMultCand = LL_INIT( 0xffffffff, 0x10000001 ); + PRInt64 largeMultCandx64K = LL_INIT( 0x00007fff, 0xffff0000 ); + PRInt64 largeNumSHL5 = LL_INIT( 0x0000001f, 0xffffffe0 ); + PRInt64 result, result2; + + /* Addition */ + LL_ADD( result, bigOne, bigOne ); + if ( LL_CMP( result, !=, bigTwo )) + ResultFailed( "LL_ADD", "r != 1 + 1", bigTwo, result); + + LL_ADD( result, bigMinusOne, bigOne ); + if ( LL_CMP( result, !=, bigZero )) + ResultFailed( "LL_ADD", "r != -1 + 1", bigOne, result); + + LL_ADD( result, largeVal, bigOne ); + if ( LL_CMP( result, !=, largeValPlusOne )) + ResultFailed( "LL_ADD", "lVP1 != lV + 1", largeValPlusOne, result); + + /* Subtraction */ + LL_SUB( result, bigOne, bigOne ); + if ( LL_CMP( result, !=, bigZero )) + ResultFailed( "LL_SUB", "r != 1 - 1", bigZero, result); + + LL_SUB( result, bigTwo, bigOne ); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_SUB", "r != 2 - 1", bigOne, result); + + LL_SUB( result, largeValPlusOne, bigOne ); + if ( LL_CMP( result, !=, largeVal )) + ResultFailed( "LL_SUB", "r != lVP1 - 1", largeVal, result); + + + /* Multiply */ + LL_MUL( result, largeVal, bigTwo ); + if ( LL_CMP( result, !=, largeValTimesTwo )) + ResultFailed( "LL_MUL", "r != lV*2", largeValTimesTwo, result); + + LL_MUL( result, largeMultCand, big64K ); + if ( LL_CMP( result, !=, largeMultCandx64K )) + ResultFailed( "LL_MUL", "r != lV*64K", largeMultCandx64K, result); + + LL_NEG( result2, largeMultCand ); + LL_MUL( result, largeMultCand, bigMinusOne ); + if ( LL_CMP( result, !=, result2 )) + ResultFailed( "LL_MUL", "r != -lMC", result2, result); + + LL_SHL( result2, bigZeroFox, 5); + LL_MUL( result, bigZeroFox, bigThirtyTwo ); + if ( LL_CMP( result, !=, largeNumSHL5 )) + ResultFailed( "LL_MUL", "r != 0f<<5", largeNumSHL5, result ); + + + + /* LL_DIV() Division */ + LL_DIV( result, bigOne, bigOne); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_DIV", "1 != 1", bigOne, result); + + LL_DIV( result, bigNumber, bigOne ); + if ( LL_CMP( result, !=, bigNumber )) + ResultFailed( "LL_DIV", "r != n / 1", bigNumber, result); + + LL_DIV( result, bigNumber, bigMinusOne ); + if ( LL_CMP( result, !=, bigMinusNumber )) + ResultFailed( "LL_DIV", "r != n / -1", bigMinusNumber, result); + + LL_DIV( result, bigMinusNumber, bigMinusOne ); + if ( LL_CMP( result, !=, bigNumber )) + ResultFailed( "LL_DIV", "r != -n / -1", bigNumber, result); + + LL_SHL( result2, bigZeroFox, 5 ); + LL_DIV( result, result2, bigOne ); + if ( LL_CMP( result, !=, result2 )) + ResultFailed( "LL_DIV", "0f<<5 != 0f<<5", result2, result); + + LL_SHL( result2, bigZeroFox, 5 ); + LL_NEG( result2, result2 ); + LL_DIV( result, result2, bigOne ); + if ( LL_CMP( result, !=, result2 )) + ResultFailed( "LL_DIV", "-0f<<5 != -0f<<5", result2, result); + + LL_SHL( result2, bigZeroFox, 17 ); + LL_DIV( result, result2, bigMinusOne ); + LL_NEG( result2, result2 ); + if ( LL_CMP( result, !=, result2 )) + ResultFailed( "LL_DIV", "-0f<<17 != -0f<<17", result2, result); + + + /* LL_MOD() Modulo Division */ + LL_ADD( result2, bigThirtyTwo, bigOne ); + LL_MOD( result, result2, bigSixTeen ); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_MOD", "r != 1", bigSixTeen, result); + + + LL_MUL( result2, bigZeroFox, bigThirtyTwo ); + LL_ADD( result2, result2, bigSixTeen); + LL_MOD( result, result2, bigThirtyTwo ); + if ( LL_CMP( result, !=, bigSixTeen )) + ResultFailed( "LL_MOD", "r != 16", bigSixTeen, result); + + /* LL_UDIVMOD */ + LL_DIV( result, bigOne, bigOne); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_DIV", "r != 16", bigSixTeen, result); + + + return; +} + +static void TestWellknowns(void) +{ + PRInt64 max = LL_MAXINT, min = LL_MININT, zero = LL_ZERO; + PRInt64 mmax = LL_MaxInt(), mmin = LL_MinInt(), mzero = LL_Zero(); + if (LL_NE(max, mmax)) + ResultFailed( "max, mmax", "max != mmax", max, mmax); + if (LL_NE(min, mmin)) + ResultFailed( "min, mmin", "min != mmin", max, mmin); + if (LL_NE(zero, mzero)) + ResultFailed( "zero, mzero", "zero != mzero", zero, mzero); +} /* TestWellknowns */ + +/* +** Initialize() -- Initialize the test case +** +** Parse command line options +** +*/ +static PRIntn +Initialize( PRIntn argc, char **argv ) +{ + PLOptState *opt = PL_CreateOptState(argc, argv, "dvh"); + PLOptStatus os; + + /* + ** Parse command line options + */ + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* set debug mode */ + debugMode = PR_TRUE; + break; + + case 'v': /* set verbose mode */ + verboseMode = PR_TRUE; + debugMode = PR_TRUE; + break; + + case 'h': /* user wants some guidance */ + default: + PR_fprintf(output, "You get help.\n"); + return(1); + } + } + PL_DestroyOptState(opt); + return(0); +} + +PRIntn main( int argc, char **argv ) +{ + PR_STDIO_INIT(); + output = PR_GetSpecialFD(PR_StandardError); + + if ( Initialize( argc, argv )) + return(1); + + TestAssignment(); + TestComparisons(); + TestLogicalOperations(); + TestConversion(); + TestShift(); + TestArithmetic(); + TestWellknowns(); + + /* + ** That's all folks! + */ + if ( failedAlready ) + { + PR_fprintf(output, "FAIL\n");\ + } + else + { + PR_fprintf(output, "PASS\n");\ + } + return failedAlready; +} /* end main() */ diff --git a/nsprpub/pr/tests/lock.c b/nsprpub/pr/tests/lock.c new file mode 100644 index 00000000000..e0e23d018cf --- /dev/null +++ b/nsprpub/pr/tests/lock.c @@ -0,0 +1,547 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: lock.c +** Purpose: test basic locking functions +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** +** 11-Aug-97 LarryH. Win16 port of NSPR. +** - Added "PASS", "FAIL" messages on completion. +** - Change stack variables to static scope variables +** because of shadow-stack use by Win16 +** - Added PR_CALLBACK attribute to functions called by NSPR +** - Added command line arguments: +** - l to control the number of loops +** - c to control the number of CPUs. +** (was positional argv). +** +** +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* 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" +#include "prmem.h" +#include "prthread.h" +#include "prtypes.h" + +#include "plstr.h" + +#include + +#if defined(XP_UNIX) +#include +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +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; + PRInt32 loops; + PRUint32 contender; + PRUint32 contentious; + PRIntervalTime overhead; + PRIntervalTime interval; +} LockContentious_t; + +typedef struct MonitorContentious_s { + PRMonitor *ml; + PRInt32 loops; + PRUint32 contender; + PRUint32 contentious; + PRIntervalTime overhead; + PRIntervalTime interval; +} MonitorContentious_t; + + +static PRIntervalTime Sleeper(PRUint32 loops) +{ + PRIntervalTime predicted = 0; + while (loops-- > 0) + { + predicted += contention_interval; + (void)PR_Sleep(contention_interval); + } + return predicted; +} /* Sleeper */ + +/* +** BASIC LOCKS +*/ +static PRIntervalTime MakeLock(PRUint32 loops) +{ + PRLock *ml = NULL; + while (loops-- > 0) + { + ml = PR_NewLock(); + PR_DestroyLock(ml); + ml = NULL; + } + return 0; +} /* MakeLock */ + +static PRIntervalTime NonContentiousLock(PRUint32 loops) +{ + PRLock *ml = NULL; + ml = PR_NewLock(); + while (loops-- > 0) + { + PR_Lock(ml); + PR_Unlock(ml); + } + PR_DestroyLock(ml); + return 0; +} /* NonContentiousLock */ + +static void PR_CALLBACK LockContender(void *arg) +{ + LockContentious_t *contention = (LockContentious_t*)arg; + while (contention->loops-- > 0) + { + PR_Lock(contention->ml); + contention->contender+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_Unlock(contention->ml); + } +} /* LockContender */ + +static PRIntervalTime ContentiousLock(PRUint32 loops) +{ + PRStatus status; + PRThread *thread = NULL; + LockContentious_t * contention; + PRIntervalTime rv, overhead, timein = PR_IntervalNow(); + + contention = PR_NEWZAP(LockContentious_t); + contention->loops = loops; + contention->overhead = 0; + contention->ml = PR_NewLock(); + contention->interval = contention_interval; + thread = PR_CreateThread( + PR_USER_THREAD, LockContender, contention, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + + overhead = PR_IntervalNow() - timein; + + while (contention->loops-- > 0) + { + PR_Lock(contention->ml); + contention->contentious+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_Unlock(contention->ml); + } + + timein = PR_IntervalNow(); + status = PR_JoinThread(thread); + 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 */ + +/* +** MONITORS +*/ +static PRIntervalTime MakeMonitor(PRUint32 loops) +{ + PRMonitor *ml = NULL; + while (loops-- > 0) + { + ml = PR_NewMonitor(); + PR_DestroyMonitor(ml); + ml = NULL; + } + return 0; +} /* MakeMonitor */ + +static PRIntervalTime NonContentiousMonitor(PRUint32 loops) +{ + PRMonitor *ml = NULL; + ml = PR_NewMonitor(); + while (loops-- > 0) + { + PR_EnterMonitor(ml); + PR_ExitMonitor(ml); + } + PR_DestroyMonitor(ml); + return 0; +} /* NonContentiousMonitor */ + +static void PR_CALLBACK TryEntry(void *arg) +{ + PRMonitor *ml = (PRMonitor*)arg; + if (debug_mode) PR_fprintf(std_err, "Reentrant thread created\n"); + PR_EnterMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread acquired monitor\n"); + PR_ExitMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread released monitor\n"); +} /* TryEntry */ + +static PRIntervalTime ReentrantMonitor(PRUint32 loops) +{ + PRStatus status; + PRThread *thread; + PRMonitor *ml = PR_NewMonitor(); + if (debug_mode) PR_fprintf(std_err, "\nMonitor created for reentrant test\n"); + + PR_EnterMonitor(ml); + PR_EnterMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Monitor acquired twice\n"); + + thread = PR_CreateThread( + PR_USER_THREAD, TryEntry, ml, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + PR_Sleep(PR_SecondsToInterval(1)); + + PR_ExitMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Monitor released first time\n"); + + PR_ExitMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Monitor released second time\n"); + + status = PR_JoinThread(thread); + if (debug_mode) PR_fprintf(std_err, + "Reentrant thread joined %s\n", + (status == PR_SUCCESS) ? "successfully" : "in error"); + + PR_DestroyMonitor(ml); + return 0; +} /* ReentrantMonitor */ + +static void PR_CALLBACK MonitorContender(void *arg) +{ + MonitorContentious_t *contention = (MonitorContentious_t*)arg; + while (contention->loops-- > 0) + { + PR_EnterMonitor(contention->ml); + contention->contender+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_ExitMonitor(contention->ml); + } +} /* MonitorContender */ + +static PRUint32 ContentiousMonitor(PRUint32 loops) +{ + PRStatus status; + PRThread *thread = NULL; + MonitorContentious_t * contention; + PRIntervalTime rv, overhead, timein = PR_IntervalNow(); + + contention = PR_NEWZAP(MonitorContentious_t); + contention->loops = loops; + contention->overhead = 0; + contention->ml = PR_NewMonitor(); + contention->interval = contention_interval; + thread = PR_CreateThread( + PR_USER_THREAD, MonitorContender, contention, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + + overhead = PR_IntervalNow() - timein; + + while (contention->loops-- > 0) + { + PR_EnterMonitor(contention->ml); + contention->contentious+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_ExitMonitor(contention->ml); + } + + timein = PR_IntervalNow(); + status = PR_JoinThread(thread); + 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 */ + +/* +** CACHED MONITORS +*/ +static PRIntervalTime NonContentiousCMonitor(PRUint32 loops) +{ + MonitorContentious_t contention; + while (loops-- > 0) + { + PR_CEnterMonitor(&contention); + PR_CExitMonitor(&contention); + } + return 0; +} /* NonContentiousCMonitor */ + +static void PR_CALLBACK Contender(void *arg) +{ + MonitorContentious_t *contention = (MonitorContentious_t*)arg; + while (contention->loops-- > 0) + { + PR_CEnterMonitor(contention); + contention->contender+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_CExitMonitor(contention); + } +} /* Contender */ + +static PRIntervalTime ContentiousCMonitor(PRUint32 loops) +{ + PRStatus status; + PRThread *thread = NULL; + MonitorContentious_t * contention; + PRIntervalTime overhead, timein = PR_IntervalNow(); + + contention = PR_NEWZAP(MonitorContentious_t); + contention->ml = NULL; + contention->loops = loops; + contention->interval = contention_interval; + thread = PR_CreateThread( + PR_USER_THREAD, Contender, contention, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + + overhead = PR_IntervalNow() - timein; + + while (contention->loops-- > 0) + { + PR_CEnterMonitor(contention); + contention->contentious+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_CExitMonitor(contention); + } + + timein = PR_IntervalNow(); + status = PR_JoinThread(thread); + overhead += (PR_IntervalNow() - timein); + 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( + const char* msg, PRUint32 (*test)(PRUint32 loops), + PRUint32 loops, PRIntervalTime overhead) +{ + /* + * overhead - overhead not measured by the test. + * duration - wall clock time it took to perform test. + * predicted - extra time test says should not be counted + * + * Time accountable to the test is duration - overhead - predicted + * All times are Intervals and accumulated for all iterations. + */ + PRFloat64 elapsed; + PRIntervalTime accountable, duration; + PRUintn spaces = PL_strlen(msg); + PRIntervalTime timeout, timein = PR_IntervalNow(); + PRIntervalTime predicted = test(loops); + timeout = PR_IntervalNow(); + duration = timeout - timein; + + if (debug_mode) + { + accountable = duration - predicted; + accountable -= overhead; + elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable); + PR_fprintf(PR_STDOUT, "%s:", msg); + while (spaces++ < 50) PR_fprintf(PR_STDOUT, " "); + if ((PRInt32)accountable < 0) + PR_fprintf(PR_STDOUT, "*****.** usecs/iteration\n"); + else + PR_fprintf(PR_STDOUT, "%8.2f usecs/iteration\n", elapsed/loops); + } + return duration; +} /* Test */ + +int main(int argc, char **argv) +{ + PRBool rv = PR_TRUE; + PRIntervalTime duration; + PRUint32 cpu, cpus = 2, loops = 100; + + + PR_STDIO_INIT(); + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + { + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Command line argument -l sets the number of loops. + Command line argument -c sets the number of cpus. + Usage: lock [-d] [-l ] [-c ] + */ + PLOptStatus os; + 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 = PR_TRUE; + break; + case 'v': /* debug mode */ + verbosity = PR_TRUE; + break; + case 'l': /* number of loops */ + loops = atoi(opt->value); + break; + case 'c': /* number of cpus */ + cpus = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + /* main test */ + PR_SetConcurrency(8); + +#ifdef XP_MAC + SetupMacPrintfLog("lock.log"); + debug_mode = 1; +#endif + + if (loops == 0) loops = 100; + 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) 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) PR_fprintf(std_err, "\nLock: Using %d CPU(s)\n", cpu); + PR_SetConcurrency(cpu); + + duration = Test("Overhead of PR_Sleep", Sleeper, loops, 0); + duration = 0; + + (void)Test("Lock creation/deletion", MakeLock, loops, 0); + (void)Test("Lock non-contentious locking/unlocking", NonContentiousLock, loops, 0); + (void)Test("Lock contentious locking/unlocking", ContentiousLock, loops, duration); + (void)Test("Monitor creation/deletion", MakeMonitor, loops, 0); + (void)Test("Monitor non-contentious locking/unlocking", NonContentiousMonitor, loops, 0); + (void)Test("Monitor contentious locking/unlocking", ContentiousMonitor, loops, duration); + + (void)Test("Cached monitor non-contentious locking/unlocking", NonContentiousCMonitor, loops, 0); + (void)Test("Cached monitor contentious locking/unlocking", ContentiousCMonitor, loops, duration); + + (void)ReentrantMonitor(loops); + } + + if (debug_mode) + PR_fprintf( + std_err, "%s: test %s\n", "Lock(mutex) test", + ((rv) ? "passed" : "failed")); + else { + if (!rv) + failed_already=1; + } + + if(failed_already) + { + PR_fprintf(PR_STDOUT, "FAIL\n"); + return 1; + } + else + { + PR_fprintf(PR_STDOUT, "PASS\n"); + return 0; + } + +} /* main */ + +/* testlock.c */ diff --git a/nsprpub/pr/tests/lockfile.c b/nsprpub/pr/tests/lockfile.c new file mode 100644 index 00000000000..27f8821e53f --- /dev/null +++ b/nsprpub/pr/tests/lockfile.c @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: lockfile.c +** Purpose: test basic locking functions +** Just because this times stuff, don't think its a perforamnce +** test!!! +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prcmon.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prlock.h" +#include "prlog.h" +#include "prmon.h" +#include "prthread.h" +#include "prtypes.h" + +#ifndef XP_MAC +#include "private/pprio.h" +#else +#include "pprio.h" +#endif + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + +const static PRIntervalTime contention_interval = 50; + +typedef struct LockContentious_s { + PRLock *ml; + PRInt32 loops; + PRIntervalTime overhead; + PRIntervalTime interval; +} LockContentious_t; + +#define LOCKFILE "prlock.fil" + + + +static PRIntervalTime NonContentiousLock(PRInt32 loops) +{ + PRFileDesc *_lockfile; + while (loops-- > 0) + { + _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE|PR_RDWR, 0666); + if (!_lockfile) { + if (debug_mode) printf( + "could not create lockfile: %d [%d]\n", + PR_GetError(), PR_GetOSError()); + return PR_INTERVAL_NO_TIMEOUT; + } + PR_LockFile(_lockfile); + PR_UnlockFile(_lockfile); + PR_Close(_lockfile); + } + return 0; +} /* NonContentiousLock */ + +static void PR_CALLBACK LockContender(void *arg) +{ + LockContentious_t *contention = (LockContentious_t*)arg; + PRFileDesc *_lockfile; + while (contention->loops-- > 0) + { + _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE|PR_RDWR, 0666); + if (!_lockfile) { + if (debug_mode) printf( + "could not create lockfile: %d [%d]\n", + PR_GetError(), PR_GetOSError()); + break; + } + PR_LockFile(_lockfile); + PR_Sleep(contention->interval); + PR_UnlockFile(_lockfile); + PR_Close(_lockfile); + } + +} /* LockContender */ + +/* +** Win16 requires things passed to Threads not be on the stack +*/ +static LockContentious_t contention; + +static PRIntervalTime ContentiousLock(PRInt32 loops) +{ + PRStatus status; + PRThread *thread = NULL; + PRIntervalTime overhead, timein = PR_IntervalNow(); + + contention.loops = loops; + contention.overhead = 0; + contention.ml = PR_NewLock(); + contention.interval = contention_interval; + thread = PR_CreateThread( + PR_USER_THREAD, LockContender, &contention, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + + overhead = PR_IntervalNow() - timein; + + while (contention.loops > 0) + { + PR_Lock(contention.ml); + contention.overhead += contention.interval; + PR_Sleep(contention.interval); + PR_Unlock(contention.ml); + } + + timein = PR_IntervalNow(); + status = PR_JoinThread(thread); + PR_DestroyLock(contention.ml); + overhead += (PR_IntervalNow() - timein); + return overhead + contention.overhead; +} /* ContentiousLock */ + +static PRIntervalTime Test( + const char* msg, PRIntervalTime (*test)(PRInt32 loops), + PRInt32 loops, PRIntervalTime overhead) +{ + /* + * overhead - overhead not measured by the test. + * duration - wall clock time it took to perform test. + * predicted - extra time test says should not be counted + * + * Time accountable to the test is duration - overhead - predicted + * All times are Intervals and accumulated for all iterations. + */ + PRFloat64 elapsed; + PRIntervalTime accountable, duration; + PRUintn spaces = strlen(msg); + PRIntervalTime timeout, timein = PR_IntervalNow(); + PRIntervalTime predicted = test(loops); + timeout = PR_IntervalNow(); + duration = timeout - timein; + accountable = duration - predicted; + accountable -= overhead; + elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable); + if (debug_mode) printf("%s:", msg); + while (spaces++ < 50) if (debug_mode) printf(" "); + if ((PRInt32)accountable < 0) { + if (debug_mode) printf("*****.** usecs/iteration\n"); + } else { + if (debug_mode) printf("%8.2f usecs/iteration\n", elapsed/loops); + } + return duration; +} /* Test */ + +int main(int argc, char **argv) +{ + PRIntervalTime duration; + PRUint32 cpu, cpus = 2; + PRInt32 loops = 100; + + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("lockfile.log"); + debug_mode = 1; +#endif + + if (argc > 1) loops = atoi(argv[1]); + if (loops == 0) loops = 100; + if (debug_mode) printf("Lock: Using %d loops\n", loops); + + cpus = (argc < 3) ? 2 : atoi(argv[2]); + if (cpus == 0) cpus = 2; + if (debug_mode) printf("Lock: Using %d cpu(s)\n", cpus); + + + for (cpu = 1; cpu <= cpus; ++cpu) + { + if (debug_mode) printf("\nLockFile: Using %d CPU(s)\n", cpu); + PR_SetConcurrency(cpu); + + duration = Test("LockFile non-contentious locking/unlocking", NonContentiousLock, loops, 0); + (void)Test("LockFile contentious locking/unlocking", ContentiousLock, loops, duration); + } + + PR_Delete(LOCKFILE); /* try to get rid of evidence */ + + if (debug_mode) printf("%s: test %s\n", "Lock(mutex) test", ((failed_already) ? "failed" : "passed")); + if(failed_already) + return 1; + else + return 0; +} /* main */ + +/* testlock.c */ diff --git a/nsprpub/pr/tests/logger.c b/nsprpub/pr/tests/logger.c new file mode 100644 index 00000000000..58c55d3e1d5 --- /dev/null +++ b/nsprpub/pr/tests/logger.c @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: logger.c + * Description: test program for logging's basic functions + */ + +#include "prinit.h" +#include "prlog.h" +#include "prlock.h" +#include "prcvar.h" +#include "prthread.h" +#include "prinrval.h" + +#include + +#ifdef XP_MAC +extern void SetupMacPrintfLog(char *logFile); +#endif + +/* lth. re-define PR_LOG() */ +#if 0 +#undef PR_LOG_TEST +#undef PR_LOG +#define PR_LOG_TEST(_module,_level) ((_module)->level <= (_level)) +#define PR_LOG(_module,_level,_args) \ + { \ + if (PR_LOG_TEST(_module,_level)) \ + PR_LogPrint _args ; \ + } +#endif + + +static void Error(const char* msg) +{ + printf("\t%s\n", msg); +} /* Error */ + +static void PR_CALLBACK forked(void *arg) +{ + PRIntn i; + PRLock *ml; + PRCondVar *cv; + + PR_LogPrint("%s logging creating mutex\n", (const char*)arg); + ml = PR_NewLock(); + PR_LogPrint("%s logging creating condition variable\n", (const char*)arg); + cv = PR_NewCondVar(ml); + + PR_LogPrint("%s waiting on condition timeout 10 times\n", (const char*)arg); + for (i = 0; i < 10; ++i) + { + PR_Lock(ml); + PR_WaitCondVar(cv, PR_SecondsToInterval(1)); + PR_Unlock(ml); + } + + PR_LogPrint("%s logging destroying condition variable\n", (const char*)arg); + PR_DestroyCondVar(cv); + PR_LogPrint("%s logging destroying mutex\n", (const char*)arg); + PR_DestroyLock(ml); + PR_LogPrint("%s forked thread exiting\n", (const char*)arg); +} + +static void UserLogStuff( void ) +{ + PRLogModuleInfo *myLM; + PRIntn i; + + myLM = PR_NewLogModule( "userStuff" ); + if (! myLM ) + { + printf("UserLogStuff(): can't create new log module\n" ); + return; + } + + PR_LOG( myLM, PR_LOG_NOTICE, ("Log a Notice %d\n", 1 )); + + for (i = 0; i < 10 ; i++ ) + { + PR_LOG( myLM, PR_LOG_DEBUG, ("Log Debug number: %d\n", i)); + PR_Sleep( 300 ); + } + +} /* end UserLogStuff() */ + +int main(PRIntn argc, const char **argv) +{ + PRThread *thread; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifndef XP_MAC + if (argc > 1) + { + if (!PR_SetLogFile(argv[1])) + { + Error("Access: Cannot create log file"); + goto exit; + } + } +#else + SetupMacPrintfLog("logger.log"); +#endif + + /* Start logging something here */ + PR_LogPrint("%s logging into %s\n", argv[0], argv[1]); + + PR_LogPrint("%s creating new thread\n", argv[0]); + + /* + ** Now change buffering. + */ + PR_SetLogBuffering( 65500 ); + thread = PR_CreateThread( + PR_USER_THREAD, forked, (void*)argv[0], PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_LogPrint("%s joining thread\n", argv[0]); + + UserLogStuff(); + + PR_JoinThread(thread); + + PR_LogFlush(); + return 0; + +exit: + return -1; +} + +/* logger.c */ diff --git a/nsprpub/pr/tests/makedir.c b/nsprpub/pr/tests/makedir.c new file mode 100644 index 00000000000..2720f13e6db --- /dev/null +++ b/nsprpub/pr/tests/makedir.c @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This test calls PR_MakeDir to create a bunch of directories + * with various mode bits. + */ + +#include "prio.h" + +#include +#include + +int main() +{ + if (PR_MakeDir("tdir0400", 0400) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0200", 0200) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0100", 0100) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0500", 0500) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0600", 0600) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0300", 0300) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0700", 0700) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0640", 0640) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0660", 0660) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0644", 0644) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0664", 0664) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0666", 0666) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + return 0; +} diff --git a/nsprpub/pr/tests/many_cv.c b/nsprpub/pr/tests/many_cv.c new file mode 100644 index 00000000000..c61b714d97e --- /dev/null +++ b/nsprpub/pr/tests/many_cv.c @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include "prprf.h" +#include "prthread.h" +#include "prcvar.h" +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" + +#include "primpl.h" + +#include "plgetopt.h" + +#include + +static PRInt32 Random(void) +{ + PRInt32 ran = rand() >> 16; + return ran; +} /* Random */ + +static void Help(void) +{ + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PR_fprintf(err, "many_cv usage: [-c n] [-l n] [-h]\n"); + PR_fprintf(err, "\t-c n Number of conditions per lock (default: 10)\n"); + PR_fprintf(err, "\t-l n Number of times to loop the test (default: 1)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + PLOptStatus os; + PRIntn index, nl; + PRLock *ml = NULL; + PRCondVar **cv = NULL; + PRBool stats = PR_FALSE; + PRIntn nc, loops = 1, cvs = 10; + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PLOptState *opt = PL_CreateOptState(argc, argv, "hsc:l:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 's': /* number of CVs to association with lock */ + stats = PR_TRUE; + break; + case 'c': /* number of CVs to association with lock */ + cvs = atoi(opt->value); + break; + case 'l': /* number of times to run the tests */ + loops = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + PR_fprintf(err, "Settings\n"); + PR_fprintf(err, "\tConditions / lock: %d\n", cvs); + PR_fprintf(err, "\tLoops to run test: %d\n", loops); + + ml = PR_NewLock(); + PR_ASSERT(NULL != ml); + + cv = (PRCondVar**)PR_CALLOC(sizeof(PRCondVar*) * cvs); + PR_ASSERT(NULL != cv); + + for (index = 0; index < cvs; ++index) + { + cv[index] = PR_NewCondVar(ml); + PR_ASSERT(NULL != cv[index]); + } + + for (index = 0; index < loops; ++index) + { + PR_Lock(ml); + for (nl = 0; nl < cvs; ++nl) + { + PRInt32 ran = Random() % 8; + if (0 == ran) PR_NotifyAllCondVar(cv[nl]); + else for (nc = 0; nc < ran; ++nc) + PR_NotifyCondVar(cv[nl]); + } + PR_Unlock(ml); + } + + for (index = 0; index < cvs; ++index) + PR_DestroyCondVar(cv[index]); + + PR_DELETE(cv); + + PR_DestroyLock(ml); + + printf("PASS\n"); + + PT_FPrintStats(err, "\nPThread Statistics\n"); + return 0; +} + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/mbcs.c b/nsprpub/pr/tests/mbcs.c new file mode 100644 index 00000000000..7ab89118c3e --- /dev/null +++ b/nsprpub/pr/tests/mbcs.c @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: mbcs.c +** +** Synopsis: mbcs {dirName} +** +** where dirName is the directory to be traversed. dirName is required. +** +** Description: +** mbcs.c tests use of multi-byte characters, as would be passed to +** NSPR funtions by internationalized applications. +** +** mbcs.c, when run on any single-byte platform, should run correctly. +** In truth, running the mbcs test on a single-byte platform is +** really meaningless. mbcs.c, nor any NSPR library or test is not +** intended for use with any wide character set, including Unicode. +** mbcs.c should not be included in runtests.ksh because it requires +** extensive user intervention to set-up and run. +** +** mbcs.c should be run on a platform using some form of multi-byte +** characters. The initial platform for this test is a Japanese +** language Windows NT 4.0 machine. ... Thank you Noriko Hoshi. +** +** To run mbcs.c, the tester should create a directory tree containing +** some files in the same directory from which the test is run; i.e. +** the current working directory. The directory and files should be +** named such that when represented in the local multi-byte character +** set, one or more characters of the name is longer than a single +** byte. +** +*/ + +#include +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ + +char *dirName = NULL; /* directory name to traverse */ + +/* +** Traverse directory +*/ +static void TraverseDirectory( unsigned char *dir ) +{ + PRDir *cwd; + PRDirEntry *dirEntry; + PRFileInfo info; + PRStatus rc; + PRInt32 err; + PRFileDesc *fd; + char nextDir[256]; + char file[256]; + + printf("Directory: %s\n", dir ); + cwd = PR_OpenDir( dir ); + if ( NULL == cwd ) { + printf("PR_OpenDir() failed on directory: %s, with error: %d, %d\n", + dir, PR_GetError(), PR_GetOSError()); + exit(1); + } + while( NULL != (dirEntry = PR_ReadDir( cwd, PR_SKIP_BOTH | PR_SKIP_HIDDEN ))) { + sprintf( file, "%s/%s", dir, dirEntry->name ); + rc = PR_GetFileInfo( file, &info ); + if ( PR_FAILURE == rc ) { + printf("PR_GetFileInfo() failed on file: %s, with error: %d, %d\n", + dirEntry->name, PR_GetError(), PR_GetOSError()); + exit(1); + } + if ( PR_FILE_FILE == info.type ) { + printf("File: %s \tsize: %ld\n", dirEntry->name, info.size ); + fd = PR_Open( file, PR_RDONLY, 0 ); + if ( NULL == fd ) { + printf("PR_Open() failed. Error: %ld, OSError: %ld\n", + PR_GetError(), PR_GetOSError()); + } + rc = PR_Close( fd ); + if ( PR_FAILURE == rc ) { + printf("PR_Close() failed. Error: %ld, OSError: %ld\n", + PR_GetError(), PR_GetOSError()); + } + } else if ( PR_FILE_DIRECTORY == info.type ) { + sprintf( nextDir, "%s/%s", dir, dirEntry->name ); + TraverseDirectory(nextDir); + } else { + printf("type is not interesting for file: %s\n", dirEntry->name ); + /* keep going */ + } + } + /* assume end-of-file, actually could be error */ + + rc = PR_CloseDir( cwd ); + if ( PR_FAILURE == rc ) { + printf("PR_CloseDir() failed on directory: %s, with error: %d, %d\n", + dir, PR_GetError(), PR_GetOSError()); + } + +} /* end TraverseDirectory() */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + { /* get command line options */ + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dv"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'v': /* verbose mode */ + msgLevel = PR_LOG_DEBUG; + break; + default: + dirName = strdup(opt->value); + break; + } + } + PL_DestroyOptState(opt); + } /* end get command line options */ + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + + if ( dirName == NULL ) { + printf("you gotta specify a directory as an operand!\n"); + exit(1); + } + + TraverseDirectory( dirName ); + + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end template.c */ diff --git a/nsprpub/pr/tests/multiacc.c b/nsprpub/pr/tests/multiacc.c new file mode 100644 index 00000000000..ccae270be6f --- /dev/null +++ b/nsprpub/pr/tests/multiacc.c @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: multiacc.c + * + * Description: + * This test creates multiple threads that accept on the + * same listening socket. + */ + +#include "nspr.h" + +#include +#include +#include + +#define NUM_SERVER_THREADS 10 + +static int num_server_threads = NUM_SERVER_THREADS; +static PRThreadScope thread_scope = PR_GLOBAL_THREAD; +static PRBool exit_flag = PR_FALSE; + +static void ServerThreadFunc(void *arg) +{ + PRFileDesc *listenSock = (PRFileDesc *) arg; + PRFileDesc *acceptSock; + PRErrorCode err; + PRStatus status; + + while (!exit_flag) { + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + err = PR_GetError(); + if (PR_PENDING_INTERRUPT_ERROR == err) { + printf("server thread is interrupted\n"); + fflush(stdout); + continue; + } + fprintf(stderr, "PR_Accept failed: %d\n", err); + exit(1); + } + status = PR_Close(acceptSock); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } +} + +int main(int argc, char **argv) +{ + PRNetAddr serverAddr; + PRFileDesc *dummySock; + PRFileDesc *listenSock; + PRFileDesc *clientSock; + PRThread *dummyThread; + PRThread **serverThreads; + PRStatus status; + PRUint16 port; + int idx; + PRInt32 nbytes; + char buf[1024]; + + serverThreads = (PRThread **) + PR_Malloc(num_server_threads * sizeof(PRThread *)); + if (NULL == serverThreads) { + fprintf(stderr, "PR_Malloc failed\n"); + exit(1); + } + + /* + * Create a dummy listening socket and have the first + * (dummy) thread listen on it. This is to ensure that + * the first thread becomes the I/O continuation thread + * in the pthreads implementation (see ptio.c) and remains + * so throughout the test, so that we never have to + * recycle the I/O continuation thread. + */ + dummySock = PR_NewTCPSocket(); + if (NULL == dummySock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + memset(&serverAddr, 0, sizeof(serverAddr)); + status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + status = PR_Bind(dummySock, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + status = PR_Listen(dummySock, 5); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + listenSock = PR_NewTCPSocket(); + if (NULL == listenSock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + memset(&serverAddr, 0, sizeof(serverAddr)); + status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + status = PR_Bind(listenSock, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + status = PR_GetSockName(listenSock, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + port = PR_ntohs(serverAddr.inet.port); + status = PR_Listen(listenSock, 5); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + printf("creating dummy thread\n"); + fflush(stdout); + dummyThread = PR_CreateThread(PR_USER_THREAD, + ServerThreadFunc, dummySock, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + if (NULL == dummyThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + printf("sleeping one second before creating server threads\n"); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(1)); + for (idx = 0; idx < num_server_threads; idx++) { + serverThreads[idx] = PR_CreateThread(PR_USER_THREAD, + ServerThreadFunc, listenSock, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + if (NULL == serverThreads[idx]) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + } + + memset(&serverAddr, 0, sizeof(serverAddr)); + PR_InitializeNetAddr(PR_IpAddrLoopback, port, &serverAddr); + clientSock = PR_NewTCPSocket(); + if (NULL == clientSock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + printf("sleeping one second before connecting\n"); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(1)); + status = PR_Connect(clientSock, &serverAddr, PR_INTERVAL_NO_TIMEOUT); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Connect failed\n"); + exit(1); + } + nbytes = PR_Read(clientSock, buf, sizeof(buf)); + if (nbytes != 0) { + fprintf(stderr, "expected 0 bytes but got %d bytes\n", nbytes); + exit(1); + } + status = PR_Close(clientSock); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + printf("sleeping one second before shutting down server threads\n"); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(1)); + + exit_flag = PR_TRUE; + status = PR_Interrupt(dummyThread); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Interrupt failed\n"); + exit(1); + } + status = PR_JoinThread(dummyThread); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + for (idx = 0; idx < num_server_threads; idx++) { + status = PR_Interrupt(serverThreads[idx]); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Interrupt failed\n"); + exit(1); + } + status = PR_JoinThread(serverThreads[idx]); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + } + PR_Free(serverThreads); + status = PR_Close(dummySock); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(listenSock); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/multiwait.c b/nsprpub/pr/tests/multiwait.c new file mode 100644 index 00000000000..10e22dad1d1 --- /dev/null +++ b/nsprpub/pr/tests/multiwait.c @@ -0,0 +1,725 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prprf.h" +#include "prlog.h" +#include "prmem.h" +#include "pratom.h" +#include "prlock.h" +#include "prmwait.h" +#include "prclist.h" +#include "prerror.h" +#include "prinrval.h" +#include "prnetdb.h" +#include "prthread.h" + +#include "plstr.h" +#include "plerror.h" +#include "plgetopt.h" + +#include + +typedef struct Shared +{ + const char *title; + PRLock *list_lock; + PRWaitGroup *group; + PRIntervalTime timeout; +} Shared; + +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; + +static PRFileDesc *debug = NULL; +static PRInt32 desc_allocated = 0; +static PRUint16 default_port = 12273; +static enum Verbosity verbosity = quiet; +static PRInt32 ops_required = 1000, ops_done = 0; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; +static PRIntn client_threads = 20, worker_threads = 2, wait_objects = 50; + +#if defined(DEBUG) +#define MW_ASSERT(_expr) \ + ((_expr)?((void)0):_MW_Assert(# _expr,__FILE__,__LINE__)) +static void _MW_Assert(const char *s, const char *file, PRIntn ln) +{ + if (NULL != debug) PL_FPrintError(debug, NULL); + PR_Assert(s, file, ln); +} /* _MW_Assert */ +#else +#define MW_ASSERT(_expr) +#endif + +static void PrintRecvDesc(PRRecvWait *desc, const char *msg) +{ + const char *tag[] = { + "PR_MW_INTERRUPT", "PR_MW_TIMEOUT", + "PR_MW_FAILURE", "PR_MW_SUCCESS", "PR_MW_PENDING"}; + PR_fprintf( + debug, "%s: PRRecvWait(@0x%x): {fd: 0x%x, outcome: %s, tmo: %u}\n", + msg, desc, desc->fd, tag[desc->outcome + 3], desc->timeout); +} /* PrintRecvDesc */ + +static Shared *MakeShared(const char *title) +{ + Shared *shared = PR_NEWZAP(Shared); + shared->group = PR_CreateWaitGroup(1); + shared->timeout = PR_SecondsToInterval(1); + shared->list_lock = PR_NewLock(); + shared->title = title; + return shared; +} /* MakeShared */ + +static void DestroyShared(Shared *shared) +{ + PRStatus rv; + if (verbosity > quiet) + PR_fprintf(debug, "%s: destroying group\n", shared->title); + rv = PR_DestroyWaitGroup(shared->group); + MW_ASSERT(PR_SUCCESS == rv); + PR_DestroyLock(shared->list_lock); + PR_DELETE(shared); +} /* DestroyShared */ + +static PRRecvWait *CreateRecvWait(PRFileDesc *fd, PRIntervalTime timeout) +{ + PRRecvWait *desc_out = PR_NEWZAP(PRRecvWait); + MW_ASSERT(NULL != desc_out); + + MW_ASSERT(NULL != fd); + desc_out->fd = fd; + desc_out->timeout = timeout; + desc_out->buffer.length = 120; + desc_out->buffer.start = PR_CALLOC(120); + + PR_AtomicIncrement(&desc_allocated); + + if (verbosity > chatty) + PrintRecvDesc(desc_out, "Allocated"); + return desc_out; +} /* CreateRecvWait */ + +static void DestroyRecvWait(PRRecvWait *desc_out) +{ + if (verbosity > chatty) + PrintRecvDesc(desc_out, "Destroying"); + PR_Close(desc_out->fd); + if (NULL != desc_out->buffer.start) + PR_DELETE(desc_out->buffer.start); + PR_Free(desc_out); + (void)PR_AtomicDecrement(&desc_allocated); +} /* DestroyRecvWait */ + +static void CancelGroup(Shared *shared) +{ + PRRecvWait *desc_out; + + if (verbosity > quiet) + PR_fprintf(debug, "%s Reclaiming wait descriptors\n", shared->title); + + do + { + desc_out = PR_CancelWaitGroup(shared->group); + if (NULL != desc_out) DestroyRecvWait(desc_out); + } while (NULL != desc_out); + + MW_ASSERT(0 == desc_allocated); + MW_ASSERT(PR_GROUP_EMPTY_ERROR == PR_GetError()); +} /* CancelGroup */ + +static void PR_CALLBACK ClientThread(void* arg) +{ + PRStatus rv; + PRInt32 bytes; + PRIntn empty_flags = 0; + PRNetAddr server_address; + unsigned char buffer[100]; + Shared *shared = (Shared*)arg; + PRFileDesc *server = PR_NewTCPSocket(); + if ((NULL == server) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) return; + MW_ASSERT(NULL != server); + + if (verbosity > chatty) + PR_fprintf(debug, "%s: Server socket @0x%x\n", shared->title, server); + + /* Initialize the buffer so that Purify won't complain */ + memset(buffer, 0, sizeof(buffer)); + + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address); + MW_ASSERT(PR_SUCCESS == rv); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: Client opening connection\n", shared->title); + rv = PR_Connect(server, &server_address, PR_INTERVAL_NO_TIMEOUT); + + if (PR_FAILURE == rv) + { + if (verbosity > silent) PL_FPrintError(debug, "Client connect failed"); + return; + } + + while (ops_done < ops_required) + { + bytes = PR_Send( + server, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); + if ((-1 == bytes) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + MW_ASSERT(sizeof(buffer) == bytes); + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Client sent %d bytes\n", + shared->title, sizeof(buffer)); + bytes = PR_Recv( + server, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Client received %d bytes\n", + shared->title, sizeof(buffer)); + if ((-1 == bytes) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + MW_ASSERT(sizeof(buffer) == bytes); + PR_Sleep(shared->timeout); + } + rv = PR_Close(server); + MW_ASSERT(PR_SUCCESS == rv); + +} /* ClientThread */ + +static void OneInThenCancelled(Shared *shared) +{ + PRStatus rv; + PRRecvWait *desc_out, *desc_in = PR_NEWZAP(PRRecvWait); + + shared->timeout = PR_INTERVAL_NO_TIMEOUT; + + desc_in->fd = PR_NewTCPSocket(); + desc_in->timeout = shared->timeout; + + if (verbosity > chatty) PrintRecvDesc(desc_in, "Adding desc"); + + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + + if (verbosity > chatty) PrintRecvDesc(desc_in, "Cancelling"); + rv = PR_CancelWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + + desc_out = PR_WaitRecvReady(shared->group); + MW_ASSERT(desc_out == desc_in); + MW_ASSERT(PR_MW_INTERRUPT == desc_out->outcome); + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready"); + + rv = PR_Close(desc_in->fd); + MW_ASSERT(PR_SUCCESS == rv); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: destroying group\n", shared->title); + + PR_DELETE(desc_in); +} /* OneInThenCancelled */ + +static void OneOpOneThread(Shared *shared) +{ + PRStatus rv; + PRRecvWait *desc_out, *desc_in = PR_NEWZAP(PRRecvWait); + + desc_in->fd = PR_NewTCPSocket(); + desc_in->timeout = shared->timeout; + + if (verbosity > chatty) PrintRecvDesc(desc_in, "Adding desc"); + + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + desc_out = PR_WaitRecvReady(shared->group); + MW_ASSERT(desc_out == desc_in); + MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome); + MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError()); + if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready"); + + rv = PR_Close(desc_in->fd); + MW_ASSERT(PR_SUCCESS == rv); + + PR_DELETE(desc_in); +} /* OneOpOneThread */ + +static void ManyOpOneThread(Shared *shared) +{ + PRStatus rv; + PRIntn index; + PRRecvWait *desc_in; + PRRecvWait *desc_out; + + if (verbosity > quiet) + PR_fprintf(debug, "%s: adding %d descs\n", shared->title, wait_objects); + + for (index = 0; index < wait_objects; ++index) + { + desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout); + + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + } + + while (ops_done < ops_required) + { + desc_out = PR_WaitRecvReady(shared->group); + MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome); + MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError()); + if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready/readding"); + rv = PR_AddWaitFileDesc(shared->group, desc_out); + MW_ASSERT(PR_SUCCESS == rv); + (void)PR_AtomicIncrement(&ops_done); + } + + CancelGroup(shared); +} /* ManyOpOneThread */ + +static void PR_CALLBACK SomeOpsThread(void *arg) +{ + PRRecvWait *desc_out; + PRStatus rv = PR_SUCCESS; + Shared *shared = (Shared*)arg; + do /* until interrupted */ + { + desc_out = PR_WaitRecvReady(shared->group); + if (NULL == desc_out) + { + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + if (verbosity > quiet) PR_fprintf(debug, "Aborted\n"); + break; + } + MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome); + MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError()); + if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready"); + + if (verbosity > chatty) PrintRecvDesc(desc_out, "Re-Adding"); + desc_out->timeout = shared->timeout; + rv = PR_AddWaitFileDesc(shared->group, desc_out); + PR_AtomicIncrement(&ops_done); + if (ops_done > ops_required) break; + } while (PR_SUCCESS == rv); + MW_ASSERT(PR_SUCCESS == rv); +} /* SomeOpsThread */ + +static void SomeOpsSomeThreads(Shared *shared) +{ + PRStatus rv; + PRThread **thread; + PRIntn index; + PRRecvWait *desc_in; + + thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * worker_threads); + + /* Create some threads */ + + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating threads\n", shared->title); + for (index = 0; index < worker_threads; ++index) + { + thread[index] = PR_CreateThread( + PR_USER_THREAD, SomeOpsThread, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + } + + /* then create some operations */ + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating desc\n", shared->title); + for (index = 0; index < wait_objects; ++index) + { + desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout); + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + } + + if (verbosity > quiet) + PR_fprintf(debug, "%s: sleeping\n", shared->title); + while (ops_done < ops_required) PR_Sleep(shared->timeout); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: interrupting/joining threads\n", shared->title); + for (index = 0; index < worker_threads; ++index) + { + rv = PR_Interrupt(thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + } + PR_DELETE(thread); + + CancelGroup(shared); +} /* SomeOpsSomeThreads */ + +static PRStatus ServiceRequest(Shared *shared, PRRecvWait *desc) +{ + PRInt32 bytes_out; + + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Service received %d bytes\n", + shared->title, desc->bytesRecv); + + if (0 == desc->bytesRecv) goto quitting; + if ((-1 == desc->bytesRecv) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) goto aborted; + + bytes_out = PR_Send( + desc->fd, desc->buffer.start, desc->bytesRecv, 0, shared->timeout); + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Service sent %d bytes\n", + shared->title, bytes_out); + + if ((-1 == bytes_out) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) goto aborted; + MW_ASSERT(bytes_out == desc->bytesRecv); + + return PR_SUCCESS; + +aborted: +quitting: + return PR_FAILURE; +} /* ServiceRequest */ + +static void PR_CALLBACK ServiceThread(void *arg) +{ + PRStatus rv = PR_SUCCESS; + PRRecvWait *desc_out = NULL; + Shared *shared = (Shared*)arg; + do /* until interrupted */ + { + if (NULL != desc_out) + { + desc_out->timeout = PR_INTERVAL_NO_TIMEOUT; + if (verbosity > chatty) + PrintRecvDesc(desc_out, "Service re-adding"); + rv = PR_AddWaitFileDesc(shared->group, desc_out); + MW_ASSERT(PR_SUCCESS == rv); + } + + desc_out = PR_WaitRecvReady(shared->group); + if (NULL == desc_out) + { + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + break; + } + + switch (desc_out->outcome) + { + case PR_MW_SUCCESS: + { + PR_AtomicIncrement(&ops_done); + if (verbosity > chatty) + PrintRecvDesc(desc_out, "Service ready"); + rv = ServiceRequest(shared, desc_out); + break; + } + case PR_MW_INTERRUPT: + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + rv = PR_FAILURE; /* if interrupted, then exit */ + break; + case PR_MW_TIMEOUT: + MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError()); + case PR_MW_FAILURE: + if (verbosity > silent) + PL_FPrintError(debug, "RecvReady failure"); + break; + default: + break; + } + } while (PR_SUCCESS == rv); + + 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) +{ + PRStatus rv; + PRIntn index; + PRRecvWait *desc_in; + PRThread **worker_thread; + Shared *shared = (Shared*)arg; + PRFileDesc *listener, *service; + PRNetAddr server_address, client_address; + + worker_thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * worker_threads); + if (verbosity > quiet) + PR_fprintf(debug, "%s: Server creating worker_threads\n", shared->title); + for (index = 0; index < worker_threads; ++index) + { + worker_thread[index] = PR_CreateThread( + PR_USER_THREAD, ServiceThread, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + } + + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &server_address); + MW_ASSERT(PR_SUCCESS == rv); + + listener = PR_NewTCPSocket(); MW_ASSERT(NULL != listener); + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Server listener socket @0x%x\n", + shared->title, listener); + rv = PR_Bind(listener, &server_address); MW_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(listener, 10); MW_ASSERT(PR_SUCCESS == rv); + while (ops_done < ops_required) + { + if (verbosity > quiet) + PR_fprintf(debug, "%s: Server accepting connection\n", shared->title); + service = PR_Accept(listener, &client_address, PR_INTERVAL_NO_TIMEOUT); + if (NULL == service) + { + if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) break; + PL_PrintError("Accept failed"); + MW_ASSERT(!"Accept failed"); + } + else + { + desc_in = CreateRecvWait(service, shared->timeout); + desc_in->timeout = PR_INTERVAL_NO_TIMEOUT; + if (verbosity > chatty) + PrintRecvDesc(desc_in, "Service adding"); + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + } + } + + if (verbosity > quiet) + PR_fprintf(debug, "%s: Server interrupting worker_threads\n", shared->title); + for (index = 0; index < worker_threads; ++index) + { + rv = PR_Interrupt(worker_thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(worker_thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + } + PR_DELETE(worker_thread); + + PR_Close(listener); + + CancelGroup(shared); + +} /* ServerThread */ + +static void RealOneGroupIO(Shared *shared) +{ + /* + ** Create a server that listens for connections and then services + ** requests that come in over those connections. The server never + ** deletes a connection and assumes a basic RPC model of operation. + ** + ** Use worker_threads threads to service how every many open ports + ** there might be. + ** + ** Oh, ya. Almost forget. Create (some) clients as well. + */ + PRStatus rv; + PRIntn index; + PRThread *server_thread, *enumeration_thread, **client_thread; + + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating server_thread\n", shared->title); + + server_thread = PR_CreateThread( + PR_USER_THREAD, ServerThread, shared, + PR_PRIORITY_HIGH, thread_scope, + 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); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating client_threads\n", shared->title); + client_thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * client_threads); + for (index = 0; index < client_threads; ++index) + { + client_thread[index] = PR_CreateThread( + PR_USER_THREAD, ClientThread, shared, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + } + + while (ops_done < ops_required) PR_Sleep(shared->timeout); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: interrupting/joining client_threads\n", shared->title); + for (index = 0; index < client_threads; ++index) + { + rv = PR_Interrupt(client_thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(client_thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + } + PR_DELETE(client_thread); + + 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); + rv = PR_JoinThread(server_thread); + MW_ASSERT(PR_SUCCESS == rv); +} /* RealOneGroupIO */ + +static void RunThisOne( + void (*func)(Shared*), const char *name, const char *test_name) +{ + Shared *shared; + if ((NULL == test_name) || (0 == PL_strcmp(name, test_name))) + { + if (verbosity > silent) + PR_fprintf(debug, "%s()\n", name); + shared = MakeShared(name); + ops_done = 0; + func(shared); /* run the test */ + MW_ASSERT(0 == desc_allocated); + DestroyShared(shared); + } +} /* RunThisOne */ + +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) +{ + PRIntn verbage = (PRIntn)verbosity; + return (Verbosity)(verbage += delta); +} /* ChangeVerbosity */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + const char *test_name = NULL; + PLOptState *opt = PL_CreateOptState(argc, argv, "dqGc:o:p:t:w:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + test_name = opt->value; + break; + case 'd': /* debug mode */ + if (verbosity < noisy) + verbosity = ChangeVerbosity(verbosity, 1); + break; + case 'q': /* debug mode */ + if (verbosity > silent) + verbosity = ChangeVerbosity(verbosity, -1); + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'c': /* number of client threads */ + client_threads = atoi(opt->value); + break; + case 'o': /* operations to compelete */ + ops_required = atoi(opt->value); + break; + case 'p': /* default port */ + default_port = atoi(opt->value); + break; + case 't': /* number of threads waiting */ + worker_threads = atoi(opt->value); + break; + case 'w': /* number of wait objects */ + wait_objects = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (verbosity > 0) + debug = PR_GetSpecialFD(PR_StandardError); + + RunThisOne(OneInThenCancelled, "OneInThenCancelled", test_name); + RunThisOne(OneOpOneThread, "OneOpOneThread", test_name); + RunThisOne(ManyOpOneThread, "ManyOpOneThread", test_name); + RunThisOne(SomeOpsSomeThreads, "SomeOpsSomeThreads", test_name); + RunThisOne(RealOneGroupIO, "RealOneGroupIO", test_name); + return 0; +} /* main */ + +/* multwait.c */ diff --git a/nsprpub/pr/tests/nameshm1.c b/nsprpub/pr/tests/nameshm1.c new file mode 100644 index 00000000000..e70f0e2afa8 --- /dev/null +++ b/nsprpub/pr/tests/nameshm1.c @@ -0,0 +1,599 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: nameshm1.c -- Test Named Shared Memory +** +** Description: +** nameshm1 tests Named Shared Memory. nameshm1 performs two tests of +** named shared memory. +** +** The first test is a basic test. The basic test operates as a single +** process. The process exercises all the API elements of the facility. +** This test also attempts to write to all locations in the shared +** memory. +** +** The second test is a client-server test. The client-server test +** creates a new instance of nameshm1, passing the -C argument to the +** new process; this creates the client-side process. The server-side +** (the instance of nameshm1 created from the command line) and the +** client-side interact via inter-process semaphores to verify that the +** shared memory segment can be read and written by both sides in a +** synchronized maner. +** +** Note: Because this test runs in two processes, the log files created +** by the test are not in chronological sequence; makes it hard to read. +** As a temporary circumvention, I changed the definition(s) of the +** _PUT_LOG() macro in prlog.c to force a flushall(), or equivalent. +** This causes the log entries to be emitted in true chronological +** order. +** +** Synopsis: nameshm1 [options] [name] +** +** Options: +** -d Enables debug trace via PR_LOG() +** -v Enables verbose mode debug trace via PR_LOG() +** -w Causes the basic test to attempt to write to the segment +** mapped as read-only. When this option is specified, the +** test should crash with a seg-fault; this is a destructive +** test and is considered successful when it seg-faults. +** +** -C Causes nameshm1 to start as the client-side of a +** client-server pair of processes. Only the instance +** of nameshm1 operating as the server-side process should +** specify the -C option when creating the client-side process; +** the -C option should not be specified at the command line. +** The client-side uses the shared memory segment created by +** the server-side to communicate with the server-side +** process. +** +** -p Specify the number of iterations the client-server tests +** should perform. Default: 1000. +** +** -s Size, in KBytes (1024), of the shared memory segment. +** Default: (10 * 1024) +** +** -i Number of client-side iterations. Default: 3 +** +** name specifies the name of the shared memory segment to be used. +** Default: /tmp/xxxNSPRshm +** +** +** See also: prshm.h +** +** /lth. Aug-1999. +*/ + +#include +#include +#include +#include +#include + +#define SEM_NAME1 "/tmp/nameshmSEM1" +#define SEM_NAME2 "/tmp/nameshmSEM2" +#define SEM_MODE 0666 +#define SHM_MODE 0666 + +#define NameSize (1024) + +PRIntn debug = 0; +PRIntn failed_already = 0; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRLogModuleInfo *lm; + +/* command line options */ +PRIntn optDebug = 0; +PRIntn optVerbose = 0; +PRUint32 optWriteRO = 0; /* test write to read-only memory. should crash */ +PRUint32 optClient = 0; +PRUint32 optCreate = 1; +PRUint32 optAttachRW = 1; +PRUint32 optAttachRO = 1; +PRUint32 optClose = 1; +PRUint32 optDelete = 1; +PRInt32 optPing = 1000; +PRUint32 optSize = (10 * 1024 ); +PRInt32 optClientIterations = 3; +char optName[NameSize] = "/tmp/xxxNSPRshm"; + +char buf[1024] = ""; + + +static void BasicTest( void ) +{ + PRSharedMemory *shm; + char *addr; /* address of shared memory segment */ + PRUint32 i; + PRInt32 rc; + + PR_LOG( lm, msgLevel, + ( "nameshm1: Begin BasicTest" )); + + if ( PR_FAILURE == PR_DeleteSharedMemory( optName )) { + PR_LOG( lm, msgLevel, + ("nameshm1: Initial PR_DeleteSharedMemory() failed. No problem")); + } else + PR_LOG( lm, msgLevel, + ("nameshm1: Initial PR_DeleteSharedMemory() success")); + + + shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE ); + if ( NULL == shm ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Create: success: %p", shm )); + + addr = PR_AttachSharedMemory( shm , 0 ); + if ( NULL == addr ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Attach: success: %p", addr )); + + /* fill memory with i */ + for ( i = 0; i < optSize ; i++ ) + { + *(addr + i) = i; + } + + rc = PR_DetachSharedMemory( shm, addr ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Detach: success: " )); + + rc = PR_CloseSharedMemory( shm ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Close: success: " )); + + rc = PR_DeleteSharedMemory( optName ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Delete: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Delete: success: " )); + + PR_LOG( lm, msgLevel, + ("nameshm1: BasicTest(): Passed")); + + return; +} /* end BasicTest() */ + +static void ReadOnlyTest( void ) +{ + PRSharedMemory *shm; + char *roAddr; /* read-only address of shared memory segment */ + PRInt32 rc; + + PR_LOG( lm, msgLevel, + ( "nameshm1: Begin ReadOnlyTest" )); + + shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE); + if ( NULL == shm ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Create: success: %p", shm )); + + + roAddr = PR_AttachSharedMemory( shm , PR_SHM_READONLY ); + if ( NULL == roAddr ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Attach: success: %p", roAddr )); + + if ( optWriteRO ) + { + *roAddr = 0x00; /* write to read-only memory */ + failed_already = 1; + PR_LOG( lm, msgLevel, ("nameshm1: Wrote to read-only memory segment!")); + return; + } + + rc = PR_DetachSharedMemory( shm, roAddr ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Detach: success: " )); + + rc = PR_CloseSharedMemory( shm ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Close: success: " )); + + rc = PR_DeleteSharedMemory( optName ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Destroy: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Destroy: success: " )); + + PR_LOG( lm, msgLevel, + ("nameshm1: ReadOnlyTest(): Passed")); + + return; +} /* end ReadOnlyTest() */ + +static void DoClient( void ) +{ + PRStatus rc; + PRSem *sem1, *sem2; + PRSharedMemory *shm; + PRUint32 *addr; + PRInt32 i; + + PR_LOG( lm, msgLevel, + ("nameshm1: DoClient(): Starting")); + + sem1 = PR_OpenSemaphore( SEM_NAME1, 0, 0, 0 ); + PR_ASSERT( sem1 ); + + sem2 = PR_OpenSemaphore( SEM_NAME2, 0, 0, 0 ); + PR_ASSERT( sem1 ); + + shm = PR_OpenSharedMemory( optName, optSize, 0, SHM_MODE ); + if ( NULL == shm ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Create: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Create: success: %p", shm )); + + addr = PR_AttachSharedMemory( shm , 0 ); + if ( NULL == addr ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Attach: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Attach: success: %p", addr )); + + PR_LOG( lm, msgLevel, + ( "Client found: %s", addr)); + + PR_Sleep(PR_SecondsToInterval(4)); + for ( i = 0 ; i < optPing ; i++ ) + { + rc = PR_WaitSemaphore( sem2 ); + PR_ASSERT( PR_FAILURE != rc ); + + (*addr)++; + PR_ASSERT( (*addr % 2) == 0 ); + if ( optVerbose ) + PR_LOG( lm, msgLevel, + ( "nameshm1: Client ping: %d, i: %d", *addr, i)); + + rc = PR_PostSemaphore( sem1 ); + PR_ASSERT( PR_FAILURE != rc ); + } + + rc = PR_CloseSemaphore( sem1 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_CloseSemaphore( sem2 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_DetachSharedMemory( shm, addr ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Detach: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Detach: success: " )); + + rc = PR_CloseSharedMemory( shm ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Close: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Close: success: " )); + + return; +} /* end DoClient() */ + +static void ClientServerTest( void ) +{ + PRStatus rc; + PRSem *sem1, *sem2; + PRProcess *proc; + PRInt32 exit_status; + PRSharedMemory *shm; + PRUint32 *addr; + PRInt32 i; + char *child_argv[8]; + char buf[24]; + + PR_LOG( lm, msgLevel, + ( "nameshm1: Begin ClientServerTest" )); + + rc = PR_DeleteSharedMemory( optName ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Destroy: failed. No problem")); + } else + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Destroy: success" )); + + + shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE); + if ( NULL == shm ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Create: success: %p", shm )); + + addr = PR_AttachSharedMemory( shm , 0 ); + if ( NULL == addr ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Attach: success: %p", addr )); + + sem1 = PR_OpenSemaphore( SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0 ); + PR_ASSERT( sem1 ); + + sem2 = PR_OpenSemaphore( SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 1 ); + PR_ASSERT( sem1 ); + + strcpy( (char*)addr, "FooBar" ); + + child_argv[0] = "nameshm1"; + child_argv[1] = "-C"; + child_argv[2] = "-p"; + sprintf( buf, "%d", optPing ); + child_argv[3] = buf; + child_argv[4] = optName; + child_argv[5] = NULL; + + proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); + PR_ASSERT( proc ); + + PR_Sleep( PR_SecondsToInterval(4)); + + *addr = 1; + for ( i = 0 ; i < optPing ; i++ ) + { + rc = PR_WaitSemaphore( sem1 ); + PR_ASSERT( PR_FAILURE != rc ); + + (*addr)++; + PR_ASSERT( (*addr % 2) == 1 ); + if ( optVerbose ) + PR_LOG( lm, msgLevel, + ( "nameshm1: Server pong: %d, i: %d", *addr, i)); + + + rc = PR_PostSemaphore( sem2 ); + PR_ASSERT( PR_FAILURE != rc ); + } + + rc = PR_WaitProcess( proc, &exit_status ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_CloseSemaphore( sem1 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_CloseSemaphore( sem2 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_DeleteSemaphore( SEM_NAME1 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_DeleteSemaphore( SEM_NAME2 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_DetachSharedMemory( shm, addr ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Detach: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Detach: success: " )); + + rc = PR_CloseSharedMemory( shm ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Close: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Close: success: " )); + + rc = PR_DeleteSharedMemory( optName ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Destroy: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Destroy: success" )); + + return; +} /* end ClientServerTest() */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "Cdvw:s:p:i:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'v': /* debug mode */ + optVerbose = 1; + /* no break! fall into debug option */ + case 'd': /* debug mode */ + debug = 1; + msgLevel = PR_LOG_DEBUG; + break; + case 'w': /* try writing to memory mapped read-only */ + optWriteRO = 1; + break; + case 'C': + optClient = 1; + break; + case 's': + optSize = atol(opt->value) * 1024; + break; + case 'p': + optPing = atol(opt->value); + break; + case 'i': + optClientIterations = atol(opt->value); + break; + default: + strcpy( optName, opt->value ); + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + PR_LOG( lm, msgLevel, + ( "nameshm1: Starting" )); + + if ( optClient ) + { + DoClient(); + } else { + BasicTest(); + if ( failed_already != 0 ) + goto Finished; + ReadOnlyTest(); + if ( failed_already != 0 ) + goto Finished; + ClientServerTest(); + } + +Finished: + if ( debug ) printf("%s\n", (failed_already)? "FAIL" : "PASS" ); + return( (failed_already)? 1 : 0 ); +} /* main() */ +/* end instrumt.c */ diff --git a/nsprpub/pr/tests/nbconn.c b/nsprpub/pr/tests/nbconn.c new file mode 100644 index 00000000000..099150a5164 --- /dev/null +++ b/nsprpub/pr/tests/nbconn.c @@ -0,0 +1,592 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * A test for nonblocking connect. Functions tested include PR_Connect, + * PR_Poll, and PR_GetConnectStatus. + * + * The test should be invoked with a host name, for example: + * nbconn www.netscape.com + * It will do a nonblocking connect to port 80 (HTTP) on that host, + * and when connected, issue the "GET /" HTTP command. + * + * You should run this test in three ways: + * 1. To a known web site, such as www.netscape.com. The HTML of the + * top-level page at the web site should be printed. + * 2. To a machine not running a web server at port 80. This test should + * fail. Ideally the error code should be PR_CONNECT_REFUSED_ERROR. + * But it is possible to return PR_UNKNOWN_ERROR on certain platforms. + * 3. To an unreachable machine, for example, a machine that is off line. + * The test should fail after the connect times out. Ideally the + * error code should be PR_IO_TIMEOUT_ERROR, but it is possible to + * return PR_UNKNOWN_ERROR on certain platforms. + */ + +#include "nspr.h" +#include "plgetopt.h" +#include +#include + +#ifdef XP_MAC +#define printf PR_LogPrint +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 +#define TCP_UNUSED_PORT 211 + +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; + PRPollDesc pd; + PRStatus rv; + PRSocketOptionData optData; + const char *hostname = NULL; + 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]; + timeout = PR_INTERVAL_NO_TIMEOUT; + if (index == 3) + timeout = PR_SecondsToInterval(10UL); +#endif + + + PR_STDIO_INIT(); +#ifndef XP_MAC + if (hostname) + default_case = 0; + else + default_case = 1; +#endif + + 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; + + 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); +#else + 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 (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); + } +#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); +#ifdef XP_MAC + } /* 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 = 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_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; + } + } + /* + * 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 (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; + } +#ifdef AIX + /* + * On AIX, set to unused/reserved port + */ + netaddr.inet.port = PR_htons(TCP_UNUSED_PORT); +#endif + 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 (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; + +} diff --git a/nsprpub/pr/tests/nblayer.c b/nsprpub/pr/tests/nblayer.c new file mode 100644 index 00000000000..4ecc955c3e5 --- /dev/null +++ b/nsprpub/pr/tests/nblayer.c @@ -0,0 +1,707 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prmem.h" +#include "prprf.h" +#include "prlog.h" +#include "prerror.h" +#include "prnetdb.h" +#include "prthread.h" + +#include "plerror.h" +#include "plgetopt.h" +#include "prwin16.h" + +#include +#include + +/* +** Testing layering of I/O +** +** The layered server +** A thread that acts as a server. It creates a TCP listener with a dummy +** layer pushed on top. Then listens for incoming connections. Each connection +** request for connection will be layered as well, accept one request, echo +** it back and close. +** +** The layered client +** Pretty much what you'd expect. +*/ + +static PRFileDesc *logFile; +static PRDescIdentity identity; +static PRNetAddr server_address; + +static PRIOMethods myMethods; + +typedef enum {rcv_get_debit, rcv_send_credit, rcv_data} RcvState; +typedef enum {xmt_send_debit, xmt_recv_credit, xmt_data} XmtState; + +struct PRFilePrivate +{ + RcvState rcvstate; + XmtState xmtstate; + PRInt32 rcvreq, rcvinprogress; + PRInt32 xmtreq, xmtinprogress; +}; + +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; + +static PRIntn minor_iterations = 5; +static PRIntn major_iterations = 1; +static Verbosity verbosity = quiet; +static PRUint16 default_port = 12273; + +static PRFileDesc *PushLayer(PRFileDesc *stack) +{ + PRStatus rv; + PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods); + layer->secret = PR_NEWZAP(PRFilePrivate); + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + PR_ASSERT(PR_SUCCESS == rv); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); + return stack; +} /* PushLayer */ + +static PRFileDesc *PopLayer(PRFileDesc *stack) +{ + PRFileDesc *popped = PR_PopIOLayer(stack, identity); + if (verbosity > quiet) + PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack); + PR_DELETE(popped->secret); + popped->dtor(popped); + return stack; +} /* PopLayer */ + +static void PR_CALLBACK Client(void *arg) +{ + PRStatus rv; + PRIntn mits; + PRInt32 ready; + PRUint8 buffer[100]; + PRPollDesc polldesc; + PRIntn empty_flags = 0; + PRIntn bytes_read, bytes_sent; + PRFileDesc *stack = (PRFileDesc*)arg; + + /* Initialize the buffer so that Purify won't complain */ + memset(buffer, 0, sizeof(buffer)); + + 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) /* 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); + if (verbosity > chatty) + PR_fprintf(logFile, "Client created connection\n"); + + for (mits = 0; mits < minor_iterations; ++mits) + { + bytes_sent = 0; + 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 (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) /* 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)); + PR_ASSERT(sizeof(buffer) == bytes_sent); + + 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 (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) /* 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); + if (verbosity > chatty) + PR_fprintf(logFile, "Client received %d bytes\n", bytes_read); + PR_ASSERT(bytes_read == bytes_sent); + } + + if (verbosity > quiet) + PR_fprintf(logFile, "Client shutting down stack\n"); + + rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); +} /* Client */ + +static void PR_CALLBACK Server(void *arg) +{ + PRStatus rv; + PRInt32 ready; + PRUint8 buffer[100]; + PRFileDesc *service; + PRUintn empty_flags = 0; + struct PRPollDesc polldesc; + PRIntn bytes_read, bytes_sent; + PRFileDesc *stack = (PRFileDesc*)arg; + PRNetAddr client_address; + + 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 | 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; } + } + } while (NULL == service); + PR_ASSERT(NULL != service); + + if (verbosity > quiet) + PR_fprintf(logFile, "Server accepting connection\n"); + + do + { + 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 (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) /* 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)); + + if (0 != bytes_read) + { + if (verbosity > chatty) + PR_fprintf(logFile, "Server received %d bytes\n", bytes_read); + PR_ASSERT(bytes_read > 0); + + bytes_sent = 0; + do + { + ready = PR_Send( + service, buffer + bytes_sent, bytes_read - bytes_sent, + empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (0 < ready) + { + bytes_sent += ready; + } + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) + { + polldesc.fd = service; + polldesc.out_flags = 0; + polldesc.in_flags = PR_POLL_WRITE; + 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; } + } + else break; + } while (bytes_sent < bytes_read); + PR_ASSERT(bytes_read == bytes_sent); + if (verbosity > chatty) + PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent); + } + } while (0 != bytes_read); + + if (verbosity > quiet) + PR_fprintf(logFile, "Server shutting down stack\n"); + rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); + +} /* Server */ + +static PRStatus PR_CALLBACK MyClose(PRFileDesc *fd) +{ + PR_DELETE(fd->secret); /* manage my secret file object */ + return (PR_GetDefaultIOMethods())->close(fd); /* let him do all the work */ +} /* MyClose */ + +static PRInt16 PR_CALLBACK MyPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + PRInt16 my_flags, new_flags; + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; + if (0 != (PR_POLL_READ & in_flags)) + { + /* client thinks he's reading */ + switch (mine->rcvstate) + { + case rcv_send_credit: + my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE; + break; + case rcv_data: + case rcv_get_debit: + my_flags = in_flags; + default: break; + } + } + else if (0 != (PR_POLL_WRITE & in_flags)) + { + /* client thinks he's writing */ + switch (mine->xmtstate) + { + case xmt_recv_credit: + my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ; + break; + case xmt_send_debit: + case xmt_data: + my_flags = in_flags; + default: break; + } + } + else PR_ASSERT(!"How'd I get here?"); + new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags); + if (verbosity > chatty) + PR_fprintf( + logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n", + in_flags, my_flags, *out_flags, new_flags); + return new_flags; +} /* MyPoll */ + +static PRFileDesc * PR_CALLBACK MyAccept( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRStatus rv; + PRFileDesc *newfd, *layer = fd; + PRFileDesc *newstack; + PRFilePrivate *newsecret; + + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + newsecret = PR_NEW(PRFilePrivate); + if (NULL == newsecret) + { + PR_DELETE(newstack); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + *newstack = *fd; /* make a copy of the accepting layer */ + *newsecret = *fd->secret; + newstack->secret = newsecret; + + newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout); + if (NULL == newfd) + { + PR_DELETE(newsecret); + PR_DELETE(newstack); + return NULL; + } + + /* this PR_PushIOLayer call cannot fail */ + rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return newfd; /* that's it */ +} + +static PRInt32 PR_CALLBACK MyRecv( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + char *b; + PRInt32 rv; + PRFileDesc *lo = fd->lower; + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; + + do + { + switch (mine->rcvstate) + { + case rcv_get_debit: + b = (char*)&mine->rcvreq; + mine->rcvreq = amount; + rv = lo->methods->recv( + lo, b + mine->rcvinprogress, + sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout); + if (0 == rv) goto closed; + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->rcvinprogress += rv; /* accumulate the read */ + if (mine->rcvinprogress < sizeof(mine->rcvreq)) break; /* loop */ + mine->rcvstate = rcv_send_credit; + mine->rcvinprogress = 0; + case rcv_send_credit: + b = (char*)&mine->rcvreq; + rv = lo->methods->send( + lo, b + mine->rcvinprogress, + sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout); + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->rcvinprogress += rv; /* accumulate the read */ + if (mine->rcvinprogress < sizeof(mine->rcvreq)) break; /* loop */ + mine->rcvstate = rcv_data; + mine->rcvinprogress = 0; + case rcv_data: + b = (char*)buf; + rv = lo->methods->recv( + lo, b + mine->rcvinprogress, + mine->rcvreq - mine->rcvinprogress, flags, timeout); + if (0 == rv) goto closed; + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->rcvinprogress += rv; /* accumulate the read */ + if (mine->rcvinprogress < amount) break; /* loop */ + mine->rcvstate = rcv_get_debit; + mine->rcvinprogress = 0; + return mine->rcvreq; /* << -- that's it! */ + default: + break; + } + } while (-1 != rv); + return rv; +closed: + mine->rcvinprogress = 0; + mine->rcvstate = rcv_get_debit; + return 0; +} /* MyRecv */ + +static PRInt32 PR_CALLBACK MySend( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + char *b; + PRInt32 rv; + PRFileDesc *lo = fd->lower; + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; + + do + { + switch (mine->xmtstate) + { + case xmt_send_debit: + b = (char*)&mine->xmtreq; + mine->xmtreq = amount; + rv = lo->methods->send( + lo, b - mine->xmtinprogress, + sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout); + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->xmtinprogress += rv; + if (mine->xmtinprogress < sizeof(mine->xmtreq)) break; + mine->xmtstate = xmt_recv_credit; + mine->xmtinprogress = 0; + case xmt_recv_credit: + b = (char*)&mine->xmtreq; + rv = lo->methods->recv( + lo, b + mine->xmtinprogress, + sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout); + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->xmtinprogress += rv; + if (mine->xmtinprogress < sizeof(mine->xmtreq)) break; + mine->xmtstate = xmt_data; + mine->xmtinprogress = 0; + case xmt_data: + b = (char*)buf; + rv = lo->methods->send( + lo, b + mine->xmtinprogress, + mine->xmtreq - mine->xmtinprogress, flags, timeout); + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->xmtinprogress += rv; + if (mine->xmtinprogress < amount) break; + mine->xmtstate = xmt_send_debit; + mine->xmtinprogress = 0; + return mine->xmtreq; /* <<-- That's the one! */ + default: + break; + } + } while (-1 != rv); + return rv; +} /* MySend */ + +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) +{ + PRIntn verbage = (PRIntn)verbosity + delta; + if (verbage < (PRIntn)silent) verbage = (PRIntn)silent; + else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy; + return (Verbosity)verbage; +} /* ChangeVerbosity */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PLOptStatus os; + PRFileDesc *client, *service; + PRNetAddr any_address; + const char *server_name = NULL; + const PRIOMethods *stubMethods; + PRThread *client_thread, *server_thread; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PRSocketOptionData socket_noblock, socket_nodelay; + PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + server_name = opt->value; + break; + case 'd': /* debug mode */ + if (verbosity < noisy) + verbosity = ChangeVerbosity(verbosity, 1); + break; + case 'q': /* debug mode */ + if (verbosity > silent) + verbosity = ChangeVerbosity(verbosity, -1); + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'C': /* number of threads waiting */ + major_iterations = atoi(opt->value); + break; + case 'c': /* number of client threads */ + minor_iterations = atoi(opt->value); + break; + case 'p': /* default port */ + default_port = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + + logFile = PR_GetSpecialFD(PR_StandardError); + identity = PR_GetUniqueIdentity("Dummy"); + stubMethods = PR_GetDefaultIOMethods(); + + /* + ** The protocol we're going to implement is one where in order to initiate + ** a send, the sender must first solicit permission. Therefore, every + ** send is really a send - receive - send sequence. + */ + myMethods = *stubMethods; /* first get the entire batch */ + myMethods.accept = MyAccept; /* then override the ones we care about */ + myMethods.recv = MyRecv; /* then override the ones we care about */ + myMethods.send = MySend; /* then override the ones we care about */ + myMethods.close = MyClose; /* then override the ones we care about */ + myMethods.poll = MyPoll; /* then override the ones we care about */ + + if (NULL == server_name) + rv = PR_InitializeNetAddr( + PR_IpAddrLoopback, default_port, &server_address); + else + { + rv = PR_StringToNetAddr(server_name, &server_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_InitializeNetAddr( + PR_IpAddrNull, default_port, &server_address); + } + PR_ASSERT(PR_SUCCESS == rv); + + socket_noblock.value.non_blocking = PR_TRUE; + socket_noblock.option = PR_SockOpt_Nonblocking; + socket_nodelay.value.no_delay = PR_TRUE; + socket_nodelay.option = PR_SockOpt_NoDelay; + + /* one type w/o layering */ + + while (major_iterations-- > 0) + { + if (verbosity > silent) + PR_fprintf(logFile, "Beginning non-layered test\n"); + + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + + rv = PR_SetSocketOption(client, &socket_noblock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(service, &socket_noblock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(client, &socket_nodelay); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(service, &socket_nodelay); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + 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 non-layered test\n"); + + /* with layering */ + if (verbosity > silent) + PR_fprintf(logFile, "Beginning layered test\n"); + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + + rv = PR_SetSocketOption(client, &socket_noblock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(service, &socket_noblock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(client, &socket_nodelay); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(service, &socket_nodelay); + PR_ASSERT(PR_SUCCESS == rv); + + PushLayer(client); + PushLayer(service); + + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + 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); + if (verbosity > silent) + PR_fprintf(logFile, "Ending layered test\n"); + } + return 0; +} /* main */ + +/* nblayer.c */ diff --git a/nsprpub/pr/tests/nonblock.c b/nsprpub/pr/tests/nonblock.c new file mode 100644 index 00000000000..102fd84b24f --- /dev/null +++ b/nsprpub/pr/tests/nonblock.c @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "prio.h" +#include "prerror.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" +#include "plerror.h" +#ifndef XP_MAC +#include "obsolete/probslet.h" +#else +#include "probslet.h" +#endif + +#include +#include +#include + +#define NUMBER_ROUNDS 5 + +#if defined(WIN16) +/* +** Make win16 unit_time interval 300 milliseconds, others get 100 +*/ +#define UNIT_TIME 200 /* unit time in milliseconds */ +#else +#define UNIT_TIME 100 /* unit time in milliseconds */ +#endif +#define CHUNK_SIZE 10 +#undef USE_PR_SELECT /* If defined, we use PR_Select. + * If not defined, use PR_Poll instead. */ + +#if defined(USE_PR_SELECT) +#include "pprio.h" +#endif + +#ifdef XP_MAC +int fprintf(FILE *stream, const char *fmt, ...) +{ +PR_LogPrint(fmt); +return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static void PR_CALLBACK +clientThreadFunc(void *arg) +{ + PRUintn port = (PRUintn)arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[CHUNK_SIZE]; + int i; + PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME); + PRSocketOptionData optval; + PRStatus retVal; + PRInt32 nBytes; + + /* Initialize the buffer so that Purify won't complain */ + memset(buf, 0, sizeof(buf)); + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons((PRUint16)port); + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip); + + /* time 1 */ + PR_Sleep(unitTime); + sock = PR_NewTCPSocket(); + optval.option = PR_SockOpt_Nonblocking; + optval.value.non_blocking = PR_TRUE; + PR_SetSocketOption(sock, &optval); + retVal = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + if (retVal == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) { +#if !defined(USE_PR_SELECT) + PRPollDesc pd; + PRInt32 n; + fprintf(stderr, "connect: EWOULDBLOCK, good\n"); + pd.fd = sock; + pd.in_flags = PR_POLL_WRITE; + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(n == 1); + PR_ASSERT(pd.out_flags == PR_POLL_WRITE); +#else + PR_fd_set writeSet; + PRInt32 n; + fprintf(stderr, "connect: EWOULDBLOCK, good\n"); + PR_FD_ZERO(&writeSet); + PR_FD_SET(sock, &writeSet); + n = PR_Select(0, NULL, &writeSet, NULL, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(n == 1); + PR_ASSERT(PR_FD_ISSET(sock, &writeSet)); +#endif + } + printf("client connected\n"); + fflush(stdout); + + /* time 4, 7, 11, etc. */ + for (i = 0; i < NUMBER_ROUNDS; i++) { + PR_Sleep(3 * unitTime); + nBytes = PR_Write(sock, buf, sizeof(buf)); + if (nBytes == -1) { + if (PR_GetError() == PR_WOULD_BLOCK_ERROR) { + fprintf(stderr, "write: EWOULDBLOCK\n"); + exit(1); + } else { + fprintf(stderr, "write: failed\n"); + } + } + printf("client sent %d bytes\n", nBytes); + fflush(stdout); + } + + PR_Close(sock); +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + PRFileDesc *listenSock, *sock; + PRUint16 listenPort; + PRNetAddr addr; + char buf[CHUNK_SIZE]; + PRThread *clientThread; + PRInt32 retVal; + PRSocketOptionData optval; + PRIntn i; + PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME); + +#ifdef XP_MAC + SetupMacPrintfLog("nonblock.log"); +#endif + + /* Create a listening socket */ + if ((listenSock = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + exit(1); + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + exit(1); + } + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + listenPort = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + exit(1); + } + + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on port %hu\n\n", + listenPort); + printf("%s", buf); + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + printf("client thread created.\n"); + + optval.option = PR_SockOpt_Nonblocking; + optval.value.non_blocking = PR_TRUE; + PR_SetSocketOption(listenSock, &optval); + /* time 0 */ + sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock != NULL || PR_GetError() != PR_WOULD_BLOCK_ERROR) { + PL_PrintError("First Accept\n"); + fprintf(stderr, "First PR_Accept() xxx\n" ); + exit(1); + } + printf("accept: EWOULDBLOCK, good\n"); + fflush(stdout); + /* time 2 */ + PR_Sleep(2 * unitTime); + sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + PL_PrintError("Second Accept\n"); + fprintf(stderr, "Second PR_Accept() failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("accept: succeeded, good\n"); + fflush(stdout); + PR_Close(listenSock); + + PR_SetSocketOption(sock, &optval); + + /* time 3, 5, 6, 8, etc. */ + for (i = 0; i < NUMBER_ROUNDS; i++) { + PR_Sleep(unitTime); + retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (retVal != -1 || PR_GetError() != PR_WOULD_BLOCK_ERROR) { + PL_PrintError("First Receive:\n"); + fprintf(stderr, "First PR_Recv: retVal: %ld, Error: %ld\n", + retVal, PR_GetError()); + exit(1); + } + printf("read: EWOULDBLOCK, good\n"); + fflush(stdout); + PR_Sleep(2 * unitTime); + retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (retVal != CHUNK_SIZE) { + PL_PrintError("Second Receive:\n"); + fprintf(stderr, "Second PR_Recv: retVal: %ld, Error: %ld\n", + retVal, PR_GetError()); + exit(1); + } + printf("read: %d bytes, good\n", retVal); + fflush(stdout); + } + PR_Close(sock); + + printf("All tests finished\n"); + printf("PASS\n"); + return 0; +} + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ + diff --git a/nsprpub/pr/tests/ntioto.c b/nsprpub/pr/tests/ntioto.c new file mode 100644 index 00000000000..0dc0072affb --- /dev/null +++ b/nsprpub/pr/tests/ntioto.c @@ -0,0 +1,318 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: ntioto.c +** Description: +** This test, ntioto.c, was designed to reproduce a bug reported by NES +** on WindowsNT (fibers implementation). NSPR was asserting in ntio.c +** after PR_AcceptRead() had timed out. I/O performed subsequent to the +** call to PR_AcceptRead() could complete on a CPU other than the one +** on which it was started. The assert in ntio.c detected this, then +** asserted. +** +** Design: +** This test will fail with an assert in ntio.c if the problem it was +** designed to catch occurs. It returns 0 otherwise. +** +** The main() thread initializes and tears things down. A file is +** opened for writing; this file will be written to by AcceptThread() +** and JitterThread(). Main() creates a socket for reading, listens +** and binds the socket. +** +** ConnectThread() connects to the socket created by main, then polls +** the "state" variable. When state is AllDone, ConnectThread() exits. +** +** AcceptThread() calls PR_AcceptRead() on the socket. He fully expects +** it to time out. After the timeout, AccpetThread() interacts with +** JitterThread() via a common condition variable and the state +** variable. The two threads ping-pong back and forth, each thread +** writes the the file opened by main. This should provoke the +** condition reported by NES (if we didn't fix it). +** +** The failure is not solid. It may fail within a few ping-pongs between +** AcceptThread() and JitterThread() or may take a while. The default +** iteration count, jitter, is set by DEFAULT_JITTER. This may be +** modified at the command line with the -j option. +** +*/ + +#include +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRIntn verbose = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ + +/* JITTER_DEFAULT: the number of times AcceptThread() and JitterThread() ping-pong */ +#define JITTER_DEFAULT 100000 +#define BASE_PORT 9867 + +PRIntervalTime timeout; +PRNetAddr listenAddr; +PRFileDesc *listenSock; +PRLock *ml; +PRCondVar *cv; +volatile enum { + RunJitter, + RunAcceptRead, + AllDone +} state = RunAcceptRead; +PRFileDesc *file1; +PRIntn iCounter = 0; +PRIntn jitter = JITTER_DEFAULT; +PRBool resume = PR_FALSE; + +/* +** Emit help text for this test +*/ +static void Help( void ) +{ + printf("Template: Help(): display your help message(s) here"); + exit(1); +} /* end Help() */ + + +/* +** static computation of PR_AcceptRead() buffer size. +*/ +#define ACCEPT_READ_DATASIZE 10 +#define ACCEPT_READ_BUFSIZE (PR_ACCEPT_READ_BUF_OVERHEAD + ACCEPT_READ_DATASIZE) + +static void AcceptThread(void *arg) +{ + PRIntn bytesRead; + char dataBuf[ACCEPT_READ_BUFSIZE]; + PRFileDesc *arSock; + PRNetAddr *arAddr; + + bytesRead = PR_AcceptRead( listenSock, + &arSock, + &arAddr, + dataBuf, + ACCEPT_READ_DATASIZE, + PR_SecondsToInterval(1)); + + if ( bytesRead == -1 && PR_GetError() == PR_IO_TIMEOUT_ERROR ) { + if ( debug ) printf("AcceptRead timed out\n"); + } else { + if ( debug ) printf("Oops! read: %d, error: %d\n", bytesRead, PR_GetError()); + } + + while( state != AllDone ) { + PR_Lock( ml ); + while( state != RunAcceptRead ) + PR_WaitCondVar( cv, PR_INTERVAL_NO_TIMEOUT ); + if ( ++iCounter >= jitter ) + state = AllDone; + else + state = RunJitter; + if ( verbose ) printf("."); + PR_NotifyCondVar( cv ); + PR_Unlock( ml ); + PR_Write( file1, ".", 1 ); + } + + return; +} /* end AcceptThread() */ + +static void JitterThread(void *arg) +{ + while( state != AllDone ) { + PR_Lock( ml ); + while( state != RunJitter && state != AllDone ) + PR_WaitCondVar( cv, PR_INTERVAL_NO_TIMEOUT ); + if ( state != AllDone) + state = RunAcceptRead; + if ( verbose ) printf("+"); + PR_NotifyCondVar( cv ); + PR_Unlock( ml ); + PR_Write( file1, "+", 1 ); + } + return; +} /* end Goofy() */ + +static void ConnectThread( void *arg ) +{ + PRStatus rv; + PRFileDesc *clientSock; + PRNetAddr serverAddress; + clientSock = PR_NewTCPSocket(); + + PR_ASSERT(clientSock); + + if ( resume ) { + if ( debug ) printf("pausing 3 seconds before connect\n"); + PR_Sleep( PR_SecondsToInterval(3)); + } + + memset(&serverAddress, 0, sizeof(serverAddress)); + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddress); + PR_ASSERT( PR_SUCCESS == rv ); + rv = PR_Connect( clientSock, + &serverAddress, + PR_SecondsToInterval(1)); + PR_ASSERT( PR_SUCCESS == rv ); + + /* that's all we do. ... Wait for the acceptread() to timeout */ + while( state != AllDone ) + PR_Sleep( PR_SecondsToInterval(1)); + return; +} /* end ConnectThread() */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRThread *tJitter; + PRThread *tAccept; + PRThread *tConnect; + PRStatus rv; + /* This test if valid for WinNT only! */ + +#if !defined(WINNT) + return 0; +#endif + + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdrvj:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'v': /* verbose mode */ + verbose = 1; + msgLevel = PR_LOG_DEBUG; + break; + case 'j': + jitter = atoi(opt->value); + if ( jitter == 0) + jitter = JITTER_DEFAULT; + break; + case 'r': + resume = PR_TRUE; + break; + case 'h': /* help message */ + Help(); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + /* set concurrency */ + PR_SetConcurrency( 4 ); + + /* setup thread synchronization mechanics */ + ml = PR_NewLock(); + cv = PR_NewCondVar( ml ); + + /* setup a tcp socket */ + memset(&listenAddr, 0, sizeof(listenAddr)); + rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr); + PR_ASSERT( PR_SUCCESS == rv ); + + listenSock = PR_NewTCPSocket(); + PR_ASSERT( listenSock ); + + rv = PR_Bind( listenSock, &listenAddr); + PR_ASSERT( PR_SUCCESS == rv ); + + rv = PR_Listen( listenSock, 5 ); + PR_ASSERT( PR_SUCCESS == rv ); + + /* open a file for writing, provoke bug */ + file1 = PR_Open("xxxTestFile", PR_CREATE_FILE | PR_RDWR, 666); + + /* create Connect thread */ + tConnect = PR_CreateThread( + PR_USER_THREAD, ConnectThread, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0 ); + PR_ASSERT( tConnect ); + + /* create jitter off thread */ + tJitter = PR_CreateThread( + PR_USER_THREAD, JitterThread, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0 ); + PR_ASSERT( tJitter ); + + /* create acceptread thread */ + tAccept = PR_CreateThread( + PR_USER_THREAD, AcceptThread, NULL, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, 0 ); + PR_ASSERT( tAccept ); + + /* wait for all threads to quit, then terminate gracefully */ + PR_JoinThread( tConnect ); + PR_JoinThread( tAccept ); + PR_JoinThread( tJitter ); + PR_Close( listenSock ); + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + PR_Close( file1 ); + PR_Delete( "xxxTestFile"); + + /* test return and exit */ + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end ntioto.c */ diff --git a/nsprpub/pr/tests/ntoh.c b/nsprpub/pr/tests/ntoh.c new file mode 100644 index 00000000000..e424f548019 --- /dev/null +++ b/nsprpub/pr/tests/ntoh.c @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * A test program for PR_htons, PR_ntohs, PR_htonl, PR_ntohl, + * PR_htonll, and PR_ntohll. + */ + +#include "prnetdb.h" + +#include +#include +#include + +/* Byte sequence in network byte order */ +static unsigned char bytes_n[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + +/* Integers in host byte order */ +static PRUint16 s_h = 0x0102; +static PRUint32 l_h = 0x01020304; +static PRUint64 ll_h = LL_INIT(0x01020304, 0x05060708); + +int main() +{ + union { + PRUint16 s; + PRUint32 l; + PRUint64 ll; + unsigned char bytes[8]; + } un; + + un.s = s_h; + printf("%u %u\n", + un.bytes[0], un.bytes[1]); + un.s = PR_htons(un.s); + printf("%u %u\n", + un.bytes[0], un.bytes[1]); + if (memcmp(un.bytes, bytes_n, 2)) { + fprintf(stderr, "PR_htons failed\n"); + exit(1); + } + un.s = PR_ntohs(un.s); + printf("%u %u\n", + un.bytes[0], un.bytes[1]); + if (un.s != s_h) { + fprintf(stderr, "PR_ntohs failed\n"); + exit(1); + } + + un.l = l_h; + printf("%u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]); + un.l = PR_htonl(un.l); + printf("%u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]); + if (memcmp(un.bytes, bytes_n, 4)) { + fprintf(stderr, "PR_htonl failed\n"); + exit(1); + } + un.l = PR_ntohl(un.l); + printf("%u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]); + if (un.l != l_h) { + fprintf(stderr, "PR_ntohl failed\n"); + exit(1); + } + + un.ll = ll_h; + printf("%u %u %u %u %u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3], + un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]); + un.ll = PR_htonll(un.ll); + printf("%u %u %u %u %u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3], + un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]); + if (memcmp(un.bytes, bytes_n, 8)) { + fprintf(stderr, "PR_htonll failed\n"); + exit(1); + } + un.ll = PR_ntohll(un.ll); + printf("%u %u %u %u %u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3], + un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]); + if (LL_NE(un.ll, ll_h)) { + fprintf(stderr, "PR_ntohll failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/obsints.c b/nsprpub/pr/tests/obsints.c new file mode 100644 index 00000000000..87182f557c9 --- /dev/null +++ b/nsprpub/pr/tests/obsints.c @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Test: obsints.c + * + * Description: make sure that protypes.h defines the obsolete integer + * types intn, uintn, uint, int8, uint8, int16, uint16, int32, uint32, + * int64, and uint64. + */ + +#include + +#ifdef NO_NSPR_10_SUPPORT + +/* nothing to do */ +int main() +{ + printf("PASS\n"); + return 0; +} + +#else /* NO_NSPR_10_SUPPORT */ + +#include "prtypes.h" /* which includes protypes.h */ + +int main() +{ + /* + * Compilation fails if any of these integer types are not + * defined by protypes.h. + */ + intn in; + uintn uin; + uint ui; + int8 i8; + uint8 ui8; + int16 i16; + uint16 ui16; + int32 i32; + uint32 ui32; + int64 i64; + uint64 ui64; + + printf("PASS\n"); + return 0; +} + +#endif /* NO_NSPR_10_SUPPORT */ diff --git a/nsprpub/pr/tests/op_2long.c b/nsprpub/pr/tests/op_2long.c new file mode 100644 index 00000000000..27f64d79079 --- /dev/null +++ b/nsprpub/pr/tests/op_2long.c @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: op_2long.c +** +** Description: Test Program to verify the PR_NAME_TOO_LONG_ERROR +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include +#include "plerror.h" +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +static PRFileDesc *t1; +PRIntn error_code; + +/* + * should exceed any system's maximum file name length + * Note: was set at 4096. This is legal on some unix (Linux 2.1+) platforms. + * + */ +#define TOO_LONG 5000 + +int main(int argc, char **argv) +{ + char nameTooLong[TOO_LONG]; + int i; + + /* Generate a really long pathname */ + for (i = 0; i < TOO_LONG - 1; i++) { + if (i % 10 == 0) { + nameTooLong[i] = '/'; + } else { + nameTooLong[i] = 'a'; + } + } + nameTooLong[TOO_LONG - 1] = 0; + +#ifdef XP_MAC + SetupMacPrintfLog("pr_open_re.log"); +#endif + + PR_STDIO_INIT(); + t1 = PR_Open(nameTooLong, PR_RDWR, 0666); + if (t1 == NULL) { + if (PR_GetError() == PR_NAME_TOO_LONG_ERROR) { + PL_PrintError("error code is"); + printf ("PASS\n"); + return 0; + } + else { + PL_PrintError("error code is"); + printf ("FAIL\n"); + return 1; + } + } + + else { + printf ("Test passed\n"); + return 0; + } + + + +} diff --git a/nsprpub/pr/tests/op_excl.c b/nsprpub/pr/tests/op_excl.c new file mode 100644 index 00000000000..b0bb6ace942 --- /dev/null +++ b/nsprpub/pr/tests/op_excl.c @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: op_excl.c +** +** Description: Test Program to verify function of PR_EXCL open flag +** +** Modification History: +** 27-Oct-1999 lth. Initial version +***********************************************************************/ + +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ +/* +** Emit help text for this test +*/ +static void Help( void ) +{ + printf("op_excl: Help"); + printf("op_excl [-d]"); + printf("-d enables debug messages"); + exit(1); +} /* end Help() */ + + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRFileDesc *fd; + PRStatus rv; + PRInt32 written; + char outBuf[] = "op_excl.c test file"; +#define OUT_SIZE sizeof(outBuf) +#define NEW_FILENAME "xxxExclNewFile" + + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hd"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'h': /* help message */ + Help(); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + /* + ** First, open a file, PR_EXCL, we believe not to exist + */ + fd = PR_Open( NEW_FILENAME, PR_CREATE_FILE | PR_EXCL | PR_WRONLY, 0666 ); + if ( NULL == fd ) { + if (debug) fprintf( stderr, "Open exclusive. Expected success, got failure\n"); + failed_already = 1; + goto Finished; + } + + written = PR_Write( fd, outBuf, OUT_SIZE ); + if ( OUT_SIZE != written ) { + if (debug) fprintf( stderr, "Write after open exclusive failed\n"); + failed_already = 1; + goto Finished; + } + + rv = PR_Close(fd); + if ( PR_FAILURE == rv ) { + if (debug) fprintf( stderr, "Close after open exclusive failed\n"); + failed_already = 1; + goto Finished; + } + + /* + ** Second, open the same file, PR_EXCL, expect it to fail + */ + fd = PR_Open( NEW_FILENAME, PR_CREATE_FILE | PR_EXCL | PR_WRONLY, 0666 ); + if ( NULL != fd ) { + if (debug) fprintf( stderr, "Open exclusive. Expected failure, got success\n"); + failed_already = 1; + PR_Close(fd); + } + + rv = PR_Delete( NEW_FILENAME ); + if ( PR_FAILURE == rv ) { + if (debug) fprintf( stderr, "PR_Delete() failed\n"); + failed_already = 1; + } + +Finished: + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end op_excl.c */ + diff --git a/nsprpub/pr/tests/op_filnf.c b/nsprpub/pr/tests/op_filnf.c new file mode 100644 index 00000000000..5f6762500bd --- /dev/null +++ b/nsprpub/pr/tests/op_filnf.c @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: op_filnf.c +** +** Description: Test Program to verify the PR_FILE_NOT_FOUND_ERROR +** This test program also uses the TRUNCATE option +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +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/ttools/err03.tmp", PR_TRUNCATE | PR_RDWR, 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; + } + } + PR_Close(t1); + printf ("opened a file that should not exist\n"); + printf ("FAIL\n"); + return 1; +} diff --git a/nsprpub/pr/tests/op_filok.c b/nsprpub/pr/tests/op_filok.c new file mode 100644 index 00000000000..acb86a7ef55 --- /dev/null +++ b/nsprpub/pr/tests/op_filok.c @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: op_filok.c +** +** Description: Test Program to verify the PR_Open finding an existing file. +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +/* + * The name of a file that is guaranteed to exist + * on every machine of a particular OS. + */ +#ifdef VMS +#define EXISTING_FILENAME "SYS$LOGIN:LOGIN.COM" +#elif XP_UNIX +#define EXISTING_FILENAME "/bin/sh" +#elif defined(WIN32) +#define EXISTING_FILENAME "c:/autoexec.bat" +#elif defined(OS2) +#define EXISTING_FILENAME "c:/config.sys" +#elif defined(BEOS) +#define EXISTING_FILENAME "/boot/beos/bin/sh" +#else +#error "Unknown OS" +#endif + +static PRFileDesc *t1; + +int main(int argc, char **argv) +{ + +#ifdef XP_MAC + SetupMacPrintfLog("pr_open_re.log"); +#endif + + PR_STDIO_INIT(); + + t1 = PR_Open(EXISTING_FILENAME, PR_RDONLY, 0666); + + if (t1 == NULL) { + 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; + } + } +} diff --git a/nsprpub/pr/tests/op_noacc.c b/nsprpub/pr/tests/op_noacc.c new file mode 100644 index 00000000000..ab1254dec36 --- /dev/null +++ b/nsprpub/pr/tests/op_noacc.c @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: op_noacc.c +** +** Description: Test Program to verify the PR_NO_ACCESS_RIGHTS_ERROR in PR_Open +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +static PRFileDesc *err01; +PRIntn error_code; + +int main(int argc, char **argv) +{ + + +#ifdef XP_MAC + 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(); + err01 = PR_Open("err01.tmp", PR_CREATE_FILE | PR_RDWR, 0); + if (err01 == NULL) + if (PR_GetError() == PR_NO_ACCESS_RIGHTS_ERROR) { + printf ("error code is %d\n",PR_GetError()); + printf ("PASS\n"); + return 0; + } + else { + printf ("FAIL\n"); + return 1; + } +} diff --git a/nsprpub/pr/tests/op_nofil.c b/nsprpub/pr/tests/op_nofil.c new file mode 100644 index 00000000000..20bc11e1515 --- /dev/null +++ b/nsprpub/pr/tests/op_nofil.c @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: op_nofil.c +** +** Description: Test Program to verify the PR_FILE_NOT_FOUND_ERROR +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +/* + * A file name that cannot exist + */ +#define NO_SUCH_FILE "/no/such/file.tmp" + +static PRFileDesc *t1; + +int main(int argc, char **argv) +{ + +#ifdef XP_MAC + SetupMacPrintfLog("pr_open_re.log"); +#endif + + PR_STDIO_INIT(); + t1 = PR_Open(NO_SUCH_FILE, PR_RDONLY, 0666); + if (t1 == NULL) { + if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) { + 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/nsprpub/pr/tests/openfile.c b/nsprpub/pr/tests/openfile.c new file mode 100644 index 00000000000..8f863c06dae --- /dev/null +++ b/nsprpub/pr/tests/openfile.c @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This test calls PR_OpenFile to create a bunch of files + * with various file modes. + */ + +#include "prio.h" +#include "prerror.h" +#include "prinit.h" + +#include +#include + +#define TEMPLATE_FILE_NAME "template.txt" + +int main() +{ + FILE *template; + char buf[32]; + PRInt32 nbytes; + PRFileDesc *fd; + + + /* Write in text mode. Let stdio deal with line endings. */ + template = fopen(TEMPLATE_FILE_NAME, "w"); + fputs("line 1\nline 2\n", template); + fclose(template); + + /* Read in binary mode */ + fd = PR_OpenFile(TEMPLATE_FILE_NAME, PR_RDONLY, 0666); + nbytes = PR_Read(fd, buf, sizeof(buf)); + PR_Close(fd); + PR_Delete(TEMPLATE_FILE_NAME); + + fd = PR_OpenFile("tfil0700.txt", PR_RDWR | PR_CREATE_FILE, 0700); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0500.txt", PR_RDWR | PR_CREATE_FILE, 0500); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0400.txt", PR_RDWR | PR_CREATE_FILE, 0400); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0644.txt", PR_RDWR | PR_CREATE_FILE, 0644); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0664.txt", PR_RDWR | PR_CREATE_FILE, 0664); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0660.txt", PR_RDWR | PR_CREATE_FILE, 0660); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0666.txt", PR_RDWR | PR_CREATE_FILE, 0666); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0640.txt", PR_RDWR | PR_CREATE_FILE, 0640); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + PR_Cleanup(); + return 0; +} diff --git a/nsprpub/pr/tests/parent.c b/nsprpub/pr/tests/parent.c new file mode 100644 index 00000000000..a81d5ec668c --- /dev/null +++ b/nsprpub/pr/tests/parent.c @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** file: parent.c +** description: test the process machinery +*/ + +#include "prmem.h" +#include "prprf.h" +#include "prinit.h" +#include "prproces.h" +#include "prinrval.h" + +typedef struct Child +{ + const char *name; + char **argv; + PRProcess *process; + PRProcessAttr *attr; +} Child; + +/* for the default test 'cvar -c 2000' */ +static char *default_argv[] = {"cvar", "-c", "2000", NULL}; + +static void PrintUsage(void) +{ + PR_fprintf(PR_GetSpecialFD(PR_StandardError), + "Usage: parent [-d] child [options]\n"); +} + +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); + + if (1 == argc) + { + /* no command-line arguments: run the default test */ + child->argv = default_argv; + } + else + { + argv += 1; /* don't care about our program name */ + while (*argv != NULL && argv[0][0] == '-') + { + if (argv[0][1] == 'd') + debug = PR_GetSpecialFD(PR_StandardError); + else + { + PrintUsage(); + return 2; /* not sufficient */ + } + argv += 1; + } + child->argv = argv; + } + + if (NULL == *child->argv) + { + PrintUsage(); + return 2; + } + + child->name = *child->argv; + if (NULL != debug) PR_fprintf(debug, "Forking %s\n", child->name); + + child->attr = PR_NewProcessAttr(); + PR_ProcessAttrSetStdioRedirect( + child->attr, PR_StandardOutput, + PR_GetSpecialFD(PR_StandardOutput)); + PR_ProcessAttrSetStdioRedirect( + child->attr, PR_StandardError, + PR_GetSpecialFD(PR_StandardError)); + + t_start = PR_IntervalNow(); + child->process = PR_CreateProcess( + child->name, child->argv, NULL, child->attr); + t_elapsed = (PRIntervalTime) (PR_IntervalNow() - t_start); + + PR_DestroyProcessAttr(child->attr); + + 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) + { + if (NULL != debug) PR_fprintf(debug, "Waiting for child to exit\n"); + rv = PR_WaitProcess(child->process, &test_status); + if (PR_SUCCESS == rv) + { + if (NULL != debug) + PR_fprintf( + debug, "Child exited %s\n", + (0 == test_status) ? "successfully" : "with error"); + } + else + { + test_status = 1; + if (NULL != debug) + PR_fprintf(debug, "PR_WaitProcess failed\n"); + } + } + PR_DELETE(child); + PR_Cleanup(); + return test_status; + +} /* main */ + +/* parent.c */ + diff --git a/nsprpub/pr/tests/peek.c b/nsprpub/pr/tests/peek.c new file mode 100644 index 00000000000..22fcfec699a --- /dev/null +++ b/nsprpub/pr/tests/peek.c @@ -0,0 +1,392 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * A test case for the PR_MSG_PEEK flag of PR_Recv(). + * + * Test both blocking and non-blocking sockets. + */ + +#include "nspr.h" + +#include +#include +#include + +#define BUFFER_SIZE 1024 + +static int iterations = 10; + +/* + * In iteration i, recv_amount[i] is the number of bytes we + * wish to receive, and send_amount[i] is the number of bytes + * we actually send. Therefore, the number of elements in the + * recv_amount or send_amount array should equal to 'iterations'. + * For this test to pass we need to ensure that + * recv_amount[i] <= BUFFER_SIZE, + * send_amount[i] <= BUFFER_SIZE, + * send_amount[i] <= recv_amount[i]. + */ +static PRInt32 recv_amount[10] = { + 16, 128, 256, 1024, 512, 512, 128, 256, 32, 32}; +static PRInt32 send_amount[10] = { + 16, 64, 128, 1024, 512, 256, 128, 64, 16, 32}; + +/* Blocking I/O */ +static void ServerB(void *arg) +{ + PRFileDesc *listenSock = (PRFileDesc *) arg; + PRFileDesc *sock; + char buf[BUFFER_SIZE]; + PRInt32 nbytes; + int i; + int j; + + sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == sock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + + for (i = 0; i < iterations; i++) { + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i, buf[j]); + exit(1); + } + } + fprintf(stderr, "server: peeked expected data\n"); + + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i, buf[j]); + exit(1); + } + } + fprintf(stderr, "server: peeked expected data\n"); + + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + 0, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i, buf[j]); + exit(1); + } + } + fprintf(stderr, "server: received expected data\n"); + + PR_Sleep(PR_SecondsToInterval(1)); + memset(buf, 2*i+1, send_amount[i]); + nbytes = PR_Send(sock, buf, send_amount[i], + 0, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Send failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes); + exit(1); + } + } + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +/* Non-blocking I/O */ +static void ClientNB(void *arg) +{ + PRFileDesc *sock; + PRSocketOptionData opt; + PRUint16 port = (PRUint16) arg; + PRNetAddr addr; + char buf[BUFFER_SIZE]; + PRPollDesc pd; + PRInt32 npds; + PRInt32 nbytes; + int i; + int j; + + sock = PR_OpenTCPSocket(PR_AF_INET6); + if (NULL == sock) { + fprintf(stderr, "PR_OpenTCPSocket failed\n"); + exit(1); + } + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_TRUE; + if (PR_SetSocketOption(sock, &opt) == PR_FAILURE) { + fprintf(stderr, "PR_SetSocketOption failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, port, &addr) + == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + if (PR_GetError() != PR_IN_PROGRESS_ERROR) { + fprintf(stderr, "PR_Connect failed\n"); + exit(1); + } + pd.fd = sock; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (-1 == npds) { + fprintf(stderr, "PR_Poll failed\n"); + exit(1); + } + if (1 != npds) { + fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); + exit(1); + } + if (PR_GetConnectStatus(&pd) == PR_FAILURE) { + fprintf(stderr, "PR_GetConnectStatus failed\n"); + exit(1); + } + } + + for (i = 0; i < iterations; i++) { + PR_Sleep(PR_SecondsToInterval(1)); + memset(buf, 2*i, send_amount[i]); + while ((nbytes = PR_Send(sock, buf, send_amount[i], + 0, PR_INTERVAL_NO_TIMEOUT)) == -1) { + if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { + fprintf(stderr, "PR_Send failed\n"); + exit(1); + } + pd.fd = sock; + pd.in_flags = PR_POLL_WRITE; + npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (-1 == npds) { + fprintf(stderr, "PR_Poll failed\n"); + exit(1); + } + if (1 != npds) { + fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); + exit(1); + } + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes); + exit(1); + } + + memset(buf, 0, sizeof(buf)); + while ((nbytes = PR_Recv(sock, buf, recv_amount[i], + PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT)) == -1) { + if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + pd.fd = sock; + pd.in_flags = PR_POLL_READ; + npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (-1 == npds) { + fprintf(stderr, "PR_Poll failed\n"); + exit(1); + } + if (1 != npds) { + fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); + exit(1); + } + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i+1) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i+1, buf[j]); + exit(1); + } + } + fprintf(stderr, "client: peeked expected data\n"); + + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i+1) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i+1, buf[j]); + exit(1); + } + } + fprintf(stderr, "client: peeked expected data\n"); + + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + 0, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i+1) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i+1, buf[j]); + exit(1); + } + } + fprintf(stderr, "client: received expected data\n"); + } + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +static void +RunTest(PRThreadScope scope, PRFileDesc *listenSock, PRUint16 port) +{ + PRThread *server, *client; + + server = PR_CreateThread(PR_USER_THREAD, ServerB, listenSock, + PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); + if (NULL == server) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + client = PR_CreateThread( + PR_USER_THREAD, ClientNB, (void *) port, + PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); + if (NULL == client) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + + if (PR_JoinThread(server) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + if (PR_JoinThread(client) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock; + PRNetAddr addr; + PRUint16 port; + + listenSock = PR_OpenTCPSocket(PR_AF_INET6); + if (NULL == listenSock) { + fprintf(stderr, "PR_OpenTCPSocket failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + port = PR_ntohs(addr.ipv6.port); + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + fprintf(stderr, "Running the test with local threads\n"); + RunTest(PR_LOCAL_THREAD, listenSock, port); + fprintf(stderr, "Running the test with global threads\n"); + RunTest(PR_GLOBAL_THREAD, listenSock, port); + + if (PR_Close(listenSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/perf.c b/nsprpub/pr/tests/perf.c new file mode 100644 index 00000000000..dda696820b4 --- /dev/null +++ b/nsprpub/pr/tests/perf.c @@ -0,0 +1,485 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include +#include +#include + +int _debug_on = 0; +#define DPRINTF(arg) if (_debug_on) printf arg + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +PRLock *lock; +PRMonitor *mon; +PRMonitor *mon2; + +#define DEFAULT_COUNT 1000 + +PRInt32 count; + +static void nop(int a, int b, int c) +{ +} + +static void LocalProcedureCall(void) +{ + PRInt32 i; + + for (i = 0; i < count; i++) { + nop(i, i, 5); + } +} + +static void DLLProcedureCall(void) +{ + PRInt32 i; + PRThreadState state; + PRThread *self = PR_GetCurrentThread(); + + for (i = 0; i < count; i++) { + state = PR_GetThreadState(self); + } +} + +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; + + for (i = 0; i < count; i++) { + PR_Lock(lock); + PR_Unlock(lock); + } +} + +static void IdleMonitor(void) +{ + PRInt32 i; + + for (i = 0; i < count; i++) { + PR_EnterMonitor(mon); + PR_ExitMonitor(mon); + } +} + +static void IdleCMonitor(void) +{ + PRInt32 i; + + for (i = 0; i < count; i++) { + PR_CEnterMonitor((void*)7); + PR_CExitMonitor((void*)7); + } +} + +/************************************************************************/ + +static void PR_CALLBACK dull(void *arg) +{ +} + +static void CDThread(void) +{ + PRInt32 i; + int num_threads = count; + + /* + * Cannot create too many threads + */ + if (num_threads > 1000) + num_threads = 1000; + + for (i = 0; i < num_threads; i++) { + PRThread *t = PR_CreateThread(PR_USER_THREAD, + dull, 0, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t) { + fprintf(stderr, "CDThread: cannot create thread %3d\n", i); + } else { + DPRINTF(("CDThread: created thread %3d \n",i)); + } + PR_Sleep(0); + } +} + +static int alive; +static int cxq; + +static void PR_CALLBACK CXReader(void *arg) +{ + PRInt32 i, n; + + PR_EnterMonitor(mon); + n = count / 2; + for (i = 0; i < n; i++) { + while (cxq == 0) { + DPRINTF(("CXReader: thread = 0x%lx waiting\n", + PR_GetCurrentThread())); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + --cxq; + PR_Notify(mon); + } + PR_ExitMonitor(mon); + + PR_EnterMonitor(mon2); + --alive; + PR_Notify(mon2); + PR_ExitMonitor(mon2); + DPRINTF(("CXReader: thread = 0x%lx exiting\n", PR_GetCurrentThread())); +} + +static void PR_CALLBACK CXWriter(void *arg) +{ + PRInt32 i, n; + + PR_EnterMonitor(mon); + n = count / 2; + for (i = 0; i < n; i++) { + while (cxq == 1) { + DPRINTF(("CXWriter: thread = 0x%lx waiting\n", + PR_GetCurrentThread())); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + ++cxq; + PR_Notify(mon); + } + PR_ExitMonitor(mon); + + PR_EnterMonitor(mon2); + --alive; + PR_Notify(mon2); + PR_ExitMonitor(mon2); + DPRINTF(("CXWriter: thread = 0x%lx exiting\n", PR_GetCurrentThread())); +} + +static void ContextSwitch(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *t1, *t2; + + PR_EnterMonitor(mon2); + alive = 2; + cxq = 0; + + t1 = PR_CreateThread(PR_USER_THREAD, + CXReader, 0, + PR_PRIORITY_NORMAL, + scope1, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t1) { + fprintf(stderr, "ContextSwitch: cannot create thread\n"); + } else { + DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n", + (scope1 == PR_GLOBAL_THREAD ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), + t1)); + } + t2 = PR_CreateThread(PR_USER_THREAD, + CXWriter, 0, + PR_PRIORITY_NORMAL, + scope2, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t2) { + fprintf(stderr, "ContextSwitch: cannot create thread\n"); + } else { + DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n", + (scope2 == PR_GLOBAL_THREAD ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), + t2)); + } + + /* Wait for both of the threads to exit */ + while (alive) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon2); +} + +static void ContextSwitchUU(void) +{ + ContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); +} + +static void ContextSwitchUK(void) +{ + ContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); +} + +static void ContextSwitchKU(void) +{ + ContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); +} + +static void ContextSwitchKK(void) +{ + ContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); +} + +/************************************************************************/ + +static void PR_CALLBACK SemaThread(void *argSema) +{ + PRSemaphore **sem = (PRSemaphore **)argSema; + PRInt32 i, n; + + n = count / 2; + for (i = 0; i < n; i++) { + DPRINTF(("SemaThread: thread = 0x%lx waiting on sem = 0x%lx\n", + PR_GetCurrentThread(), sem[0])); + PR_WaitSem(sem[0]); + DPRINTF(("SemaThread: thread = 0x%lx posting on sem = 0x%lx\n", + PR_GetCurrentThread(), sem[1])); + PR_PostSem(sem[1]); + } + + PR_EnterMonitor(mon2); + --alive; + PR_Notify(mon2); + PR_ExitMonitor(mon2); + DPRINTF(("SemaThread: thread = 0x%lx exiting\n", PR_GetCurrentThread())); +} + +static PRSemaphore *sem_set1[2]; +static PRSemaphore *sem_set2[2]; + +static void SemaContextSwitch(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *t1, *t2; + sem_set1[0] = PR_NewSem(1); + sem_set1[1] = PR_NewSem(0); + sem_set2[0] = sem_set1[1]; + sem_set2[1] = sem_set1[0]; + + PR_EnterMonitor(mon2); + alive = 2; + cxq = 0; + + t1 = PR_CreateThread(PR_USER_THREAD, + SemaThread, + sem_set1, + PR_PRIORITY_NORMAL, + scope1, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t1) { + fprintf(stderr, "SemaContextSwitch: cannot create thread\n"); + } else { + DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n", + (scope1 == PR_GLOBAL_THREAD ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), + t1)); + } + t2 = PR_CreateThread(PR_USER_THREAD, + SemaThread, + sem_set2, + PR_PRIORITY_NORMAL, + scope2, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t2) { + fprintf(stderr, "SemaContextSwitch: cannot create thread\n"); + } else { + DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n", + (scope2 == PR_GLOBAL_THREAD ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), + t2)); + } + + /* Wait for both of the threads to exit */ + while (alive) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon2); + + PR_DestroySem(sem_set1[0]); + PR_DestroySem(sem_set1[1]); +} + +static void SemaContextSwitchUU(void) +{ + SemaContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); +} + +static void SemaContextSwitchUK(void) +{ + SemaContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); +} + +static void SemaContextSwitchKU(void) +{ + SemaContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); +} + +static void SemaContextSwitchKK(void) +{ + SemaContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); +} + + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow() - start; + d = (double)PR_IntervalToMicroseconds(stop); + + printf("%40s: %6.2f usec\n", msg, d / count); +} + +int main(int argc, char **argv) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:"); + 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 'c': /* loop count */ + count = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == count) count = DEFAULT_COUNT; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_BlockClockInterrupts(); + PR_UnblockClockInterrupts(); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("perf.log"); +#endif + + lock = PR_NewLock(); + mon = PR_NewMonitor(); + mon2 = PR_NewMonitor(); + + 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"); + Measure(CDThread, "create/destroy thread pair"); + Measure(ContextSwitchUU, "context switch - user/user"); + Measure(ContextSwitchUK, "context switch - user/kernel"); + Measure(ContextSwitchKU, "context switch - kernel/user"); + Measure(ContextSwitchKK, "context switch - kernel/kernel"); + Measure(SemaContextSwitchUU, "sema context switch - user/user"); + Measure(SemaContextSwitchUK, "sema context switch - user/kernel"); + Measure(SemaContextSwitchKU, "sema context switch - kernel/user"); + Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel"); + + printf("--------------\n"); + printf("Adding 7 additional CPUs\n"); + + PR_SetConcurrency(8); + printf("--------------\n"); + + 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"); + Measure(CDThread, "create/destroy thread pair"); + Measure(ContextSwitchUU, "context switch - user/user"); + Measure(ContextSwitchUK, "context switch - user/kernel"); + Measure(ContextSwitchKU, "context switch - kernel/user"); + Measure(ContextSwitchKK, "context switch - kernel/kernel"); + Measure(SemaContextSwitchUU, "sema context switch - user/user"); + Measure(SemaContextSwitchUK, "sema context switch - user/kernel"); + Measure(SemaContextSwitchKU, "sema context switch - kernel/user"); + Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel"); + + PR_DestroyLock(lock); + PR_DestroyMonitor(mon); + PR_DestroyMonitor(mon2); + + PR_Cleanup(); + return 0; +} diff --git a/nsprpub/pr/tests/pipeping.c b/nsprpub/pr/tests/pipeping.c new file mode 100644 index 00000000000..dd18eb6f42b --- /dev/null +++ b/nsprpub/pr/tests/pipeping.c @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: pipeping.c + * + * Description: + * This test runs in conjunction with the pipepong test. + * This test creates two pipes and redirects the stdin and + * stdout of the pipepong test to the pipes. Then this + * test writes "ping" to the pipepong test and the pipepong + * test writes "pong" back. To run this pair of tests, + * just invoke pipeping. + * + * Tested areas: process creation, pipes, file descriptor + * inheritance, standard I/O redirection. + */ + +#include "prerror.h" +#include "prio.h" +#include "prproces.h" + +#include +#include +#include + +#ifdef XP_OS2 +static char *child_argv[] = { "pipepong.exe", NULL }; +#else +static char *child_argv[] = { "pipepong", NULL }; +#endif + +#define NUM_ITERATIONS 10 + +int main() +{ + PRFileDesc *in_pipe[2]; + PRFileDesc *out_pipe[2]; + PRStatus status; + PRProcess *process; + PRProcessAttr *attr; + char buf[1024]; + PRInt32 nBytes; + PRInt32 exitCode; + int idx; + + status = PR_CreatePipe(&in_pipe[0], &in_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + status = PR_CreatePipe(&out_pipe[0], &out_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + + status = PR_SetFDInheritable(in_pipe[0], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(in_pipe[1], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(out_pipe[0], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(out_pipe[1], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + + attr = PR_NewProcessAttr(); + if (attr == NULL) { + fprintf(stderr, "PR_NewProcessAttr failed\n"); + exit(1); + } + + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, out_pipe[0]); + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, in_pipe[1]); + + process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr); + if (process == NULL) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + PR_DestroyProcessAttr(attr); + status = PR_Close(out_pipe[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(in_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + strcpy(buf, "ping"); + printf("ping process: sending \"%s\"\n", buf); + nBytes = PR_Write(out_pipe[1], buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(in_pipe[0], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("ping process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "pong") != 0) { + fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n", + buf); + exit(1); + } + } + + status = PR_Close(in_pipe[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(out_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_WaitProcess(process, &exitCode); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exitCode == 0) { + printf("PASS\n"); + return 0; + } else { + printf("FAIL\n"); + return 1; + } +} diff --git a/nsprpub/pr/tests/pipeping2.c b/nsprpub/pr/tests/pipeping2.c new file mode 100644 index 00000000000..b1f2b4207a9 --- /dev/null +++ b/nsprpub/pr/tests/pipeping2.c @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: pipeping2.c + * + * Description: + * This test runs in conjunction with the pipepong2 test. + * This test creates two pipes and passes two pipe fd's + * to the pipepong2 test. Then this test writes "ping" to + * to the pipepong2 test and the pipepong2 test writes "pong" + * back. To run this pair of tests, just invoke pipeping2. + * + * Tested areas: process creation, pipes, file descriptor + * inheritance. + */ + +#include "prerror.h" +#include "prio.h" +#include "prproces.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +static char *child_argv[] = { "pipepong2", NULL }; + +int main() +{ + PRFileDesc *in_pipe[2]; + PRFileDesc *out_pipe[2]; + PRStatus status; + PRProcess *process; + PRProcessAttr *attr; + char buf[1024]; + PRInt32 nBytes; + PRInt32 exitCode; + int idx; + + status = PR_CreatePipe(&in_pipe[0], &in_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + status = PR_CreatePipe(&out_pipe[0], &out_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + + status = PR_SetFDInheritable(in_pipe[0], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(in_pipe[1], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(out_pipe[0], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(out_pipe[1], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + + attr = PR_NewProcessAttr(); + if (attr == NULL) { + fprintf(stderr, "PR_NewProcessAttr failed\n"); + exit(1); + } + + status = PR_ProcessAttrSetInheritableFD(attr, out_pipe[0], "PIPE_READ"); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n"); + exit(1); + } + status = PR_ProcessAttrSetInheritableFD(attr, in_pipe[1], "PIPE_WRITE"); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n"); + exit(1); + } + + process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr); + if (process == NULL) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + PR_DestroyProcessAttr(attr); + status = PR_Close(out_pipe[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(in_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + strcpy(buf, "ping"); + printf("ping process: sending \"%s\"\n", buf); + nBytes = PR_Write(out_pipe[1], buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(in_pipe[0], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + printf("ping process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "pong") != 0) { + fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n", + buf); + exit(1); + } + } + + status = PR_Close(in_pipe[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(out_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_WaitProcess(process, &exitCode); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exitCode == 0) { + printf("PASS\n"); + return 0; + } else { + printf("FAIL\n"); + return 1; + } +} diff --git a/nsprpub/pr/tests/pipepong.c b/nsprpub/pr/tests/pipepong.c new file mode 100644 index 00000000000..66771601f94 --- /dev/null +++ b/nsprpub/pr/tests/pipepong.c @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: pipepong.c + * + * Description: + * This test runs in conjunction with the pipeping test. + * The pipeping test creates two pipes and redirects the + * stdin and stdout of this test to the pipes. Then the + * pipeping test writes "ping" to this test and this test + * writes "pong" back. Note that this test does not depend + * on NSPR at all. To run this pair of tests, just invoke + * pipeping. + * + * Tested areas: process creation, pipes, file descriptor + * inheritance, standard I/O redirection. + */ + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +int main() +{ + char buf[1024]; + size_t nBytes; + int idx; + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + memset(buf, 0, sizeof(buf)); + nBytes = fread(buf, 1, 5, stdin); + fprintf(stderr, "pong process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "ping") != 0) { + fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n", + buf); + exit(1); + } + + strcpy(buf, "pong"); + fprintf(stderr, "pong process: sending \"%s\"\n", buf); + nBytes = fwrite(buf, 1, 5, stdout); + if (nBytes != 5) { + fprintf(stderr, "pong process: fwrite failed\n"); + exit(1); + } + fflush(stdout); + } + + return 0; +} diff --git a/nsprpub/pr/tests/pipepong2.c b/nsprpub/pr/tests/pipepong2.c new file mode 100644 index 00000000000..19494bbd274 --- /dev/null +++ b/nsprpub/pr/tests/pipepong2.c @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: pipepong2.c + * + * Description: + * This test runs in conjunction with the pipeping2 test. + * The pipeping2 test creates two pipes and passes two + * pipe fd's to this test. Then the pipeping2 test writes + * "ping" to this test and this test writes "pong" back. + * To run this pair of tests, just invoke pipeping2. + * + * Tested areas: process creation, pipes, file descriptor + * inheritance. + */ + +#include "prerror.h" +#include "prio.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +int main() +{ + PRFileDesc *pipe_read, *pipe_write; + PRStatus status; + char buf[1024]; + PRInt32 nBytes; + int idx; + + pipe_read = PR_GetInheritedFD("PIPE_READ"); + if (pipe_read == NULL) { + fprintf(stderr, "PR_GetInheritedFD failed\n"); + exit(1); + } + status = PR_SetFDInheritable(pipe_read, PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + pipe_write = PR_GetInheritedFD("PIPE_WRITE"); + if (pipe_write == NULL) { + fprintf(stderr, "PR_GetInheritedFD failed\n"); + exit(1); + } + status = PR_SetFDInheritable(pipe_write, PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(pipe_read, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("pong process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "ping") != 0) { + fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n", + buf); + exit(1); + } + + strcpy(buf, "pong"); + printf("pong process: sending \"%s\"\n", buf); + nBytes = PR_Write(pipe_write, buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed\n"); + exit(1); + } + } + + status = PR_Close(pipe_read); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(pipe_write); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + return 0; +} diff --git a/nsprpub/pr/tests/pipeself.c b/nsprpub/pr/tests/pipeself.c new file mode 100644 index 00000000000..5bb9791acc0 --- /dev/null +++ b/nsprpub/pr/tests/pipeself.c @@ -0,0 +1,260 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: pipeself.c + * + * Description: + * This test has two threads communicating with each other using + * two unidirectional pipes. The primordial thread is the ping + * thread and the other thread is the pong thread. The ping + * thread writes "ping" to the pong thread and the pong thread + * writes "pong" back. + */ + +#include "prio.h" +#include "prerror.h" +#include "prthread.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +static PRFileDesc *ping_in, *ping_out; +static PRFileDesc *pong_in, *pong_out; + +static void PongThreadFunc(void *arg) +{ + char buf[1024]; + int idx; + PRInt32 nBytes; + PRStatus status; + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(pong_in, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + printf("pong thread: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "pong thread: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "ping") != 0) { + fprintf(stderr, "pong thread: expected \"ping\" but got \"%s\"\n", + buf); + exit(1); + } + strcpy(buf, "pong"); + printf("pong thread: sending \"%s\"\n", buf); + nBytes = PR_Write(pong_out, buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + } + + status = PR_Close(pong_in); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(pong_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +int main() +{ + PRStatus status; + PRThread *pongThread; + char buf[1024]; + PRInt32 nBytes; + int idx; + + status = PR_CreatePipe(&ping_in, &pong_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + status = PR_CreatePipe(&pong_in, &ping_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + + pongThread = PR_CreateThread(PR_USER_THREAD, PongThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (pongThread == NULL) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + strcpy(buf, "ping"); + printf("ping thread: sending \"%s\"\n", buf); + nBytes = PR_Write(ping_out, buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(ping_in, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + printf("ping thread: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "ping thread: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "pong") != 0) { + fprintf(stderr, "ping thread: expected \"pong\" but got \"%s\"\n", + buf); + exit(1); + } + } + + status = PR_Close(ping_in); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(ping_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_JoinThread(pongThread); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + +#ifdef XP_UNIX + /* + * Test PR_Available for pipes + */ + status = PR_CreatePipe(&ping_in, &ping_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + nBytes = PR_Write(ping_out, buf, 250); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + nBytes = PR_Available(ping_in); + if (nBytes < 0) { + fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } else if (nBytes != 250) { + fprintf(stderr, "PR_Available: expected 250 bytes but got %d bytes\n", + nBytes); + exit(1); + } + printf("PR_Available: expected %d, got %d bytes\n",250, nBytes); + /* read some data */ + nBytes = PR_Read(ping_in, buf, 7); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + /* check available data */ + nBytes = PR_Available(ping_in); + if (nBytes < 0) { + fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } else if (nBytes != (250 - 7)) { + fprintf(stderr, "PR_Available: expected 243 bytes but got %d bytes\n", + nBytes); + exit(1); + } + printf("PR_Available: expected %d, got %d bytes\n",243, nBytes); + /* read all data */ + nBytes = PR_Read(ping_in, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } else if (nBytes != 243) { + fprintf(stderr, "PR_Read failed: expected %d, got %d bytes\n", + 243, nBytes); + exit(1); + } + /* check available data */ + nBytes = PR_Available(ping_in); + if (nBytes < 0) { + fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } else if (nBytes != 0) { + fprintf(stderr, "PR_Available: expected 0 bytes but got %d bytes\n", + nBytes); + exit(1); + } + printf("PR_Available: expected %d, got %d bytes\n", 0, nBytes); + + status = PR_Close(ping_in); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(ping_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +#endif /* XP_UNIX */ + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/poll_er.c b/nsprpub/pr/tests/poll_er.c new file mode 100755 index 00000000000..b68c798685c --- /dev/null +++ b/nsprpub/pr/tests/poll_er.c @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: prpoll_err.c +** +** Description: This program tests PR_Poll with sockets. +** error reporting operation is tested +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +#ifdef XP_BEOS +#include +int main() +{ + printf( "This test is not ported to the BeOS\n" ); + return 0; +} +#else + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "primpl.h" + +#include +#include +#include + +PRIntn failed_already=0; +PRIntn debug_mode; + +static void +ClientThreadFunc(void *arg) +{ + PRFileDesc *badFD = (PRFileDesc *) arg; + /* + * Make the fd invalid + */ +#if defined(XP_UNIX) + close(PR_FileDesc2NativeHandle(badFD)); +#elif defined(XP_OS2) + soclose(PR_FileDesc2NativeHandle(badFD)); +#elif defined(WIN32) || defined(WIN16) + closesocket(PR_FileDesc2NativeHandle(badFD)); +#elif defined(XP_MAC) + _PR_MD_CLOSE_SOCKET(PR_FileDesc2NativeHandle(badFD)); +#else +#error "Unknown architecture" +#endif +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *badFD; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + char buf[128]; + PRPollDesc pds0[10], pds1[10], *pds, *other_pds; + PRIntn npds; + PRInt32 retVal; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Poll with sockets.\n"); + printf("error reporting is tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the poll descriptor array */ + pds = pds0; + other_pds = pds1; + memset(pds, 0, sizeof(pds)); + pds[0].fd = listenSock1; + pds[0].in_flags = PR_POLL_READ; + pds[1].fd = listenSock2; + pds[1].in_flags = PR_POLL_READ; + npds = 2; + + + /* Testing bad fd */ + if (debug_mode) printf("PR_Poll should detect a bad file descriptor\n"); + if ((badFD = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a TCP socket\n"); + goto exit_now; + } + + pds[2].fd = badFD; + pds[2].in_flags = PR_POLL_READ; + npds = 3; + + if (PR_CreateThread(PR_USER_THREAD, ClientThreadFunc, + badFD, PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0) == NULL) { + fprintf(stderr, "cannot create thread\n"); + exit(1); + } + + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); + if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) { + fprintf(stderr, "Failed to detect the bad fd: " + "PR_Poll returns %d, out_flags is 0x%hx\n", + retVal, pds[2].out_flags); + failed_already=1; + goto exit_now; + } + if (debug_mode) printf("PR_Poll detected the bad fd. Test passed.\n\n"); + PR_Cleanup(); + goto exit_now; +exit_now: + if(failed_already) + return 1; + else + return 0; +} + +#endif /* XP_BEOS */ diff --git a/nsprpub/pr/tests/poll_nm.c b/nsprpub/pr/tests/poll_nm.c new file mode 100644 index 00000000000..63a64a630dc --- /dev/null +++ b/nsprpub/pr/tests/poll_nm.c @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: prpoll_norm.c +** +** Description: This program tests PR_Poll with sockets. +** Normal operation are tested +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" +#ifndef XP_MAC +#include "obsolete/probslet.h" +#else +#include "probslet.h" +#endif + +#ifndef XP_MAC +#include "private/pprio.h" +#else +#include "pprio.h" +#endif + +#include +#include +#include +PRIntn failed_already=0; +PRIntn debug_mode; + +#define NUM_ITERATIONS 5 + +#ifdef XP_MAC +int fprintf(FILE *stream, const char *fmt, ...) +{ +PR_LogPrint(fmt); +return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static void PR_CALLBACK +clientThreadFunc(void *arg) +{ + PRUintn port = (PRUintn) arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[128]; + int i; + PRStatus sts; + PRInt32 n; + + addr.inet.family = PR_AF_INET; + 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", port); + + for (i = 0; i < NUM_ITERATIONS; i++) { + sock = PR_NewTCPSocket(); + PR_ASSERT(sock != NULL); + + sts = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(sts == PR_SUCCESS); + + n = PR_Write(sock, buf, sizeof(buf)); + PR_ASSERT(n >= 0); + + sts = PR_Close(sock); + PR_ASSERT(sts == PR_SUCCESS); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + char buf[128]; + PRThread *clientThread; + PRPollDesc pds0[20], pds1[20], *pds, *other_pds; + PRIntn npds; + PRInt32 retVal; + PRIntn i, j; + PRSocketOptionData optval; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + debug_mode = 1; + SetupMacPrintfLog("poll_nm.log"); +#endif + + if (debug_mode) { + printf("This program tests PR_Poll with sockets.\n"); + printf("Normal operation are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + optval.option = PR_SockOpt_Nonblocking; + optval.value.non_blocking = PR_TRUE; + PR_SetSocketOption(listenSock1, &optval); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + PR_SetSocketOption(listenSock2, &optval); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the poll descriptor array */ + pds = pds0; + other_pds = pds1; + memset(pds, 0, sizeof(pds)); + pds[0].fd = listenSock1; + pds[0].in_flags = PR_POLL_READ; + pds[1].fd = listenSock2; + pds[1].in_flags = PR_POLL_READ; + /* Add some unused entries to test if they are ignored by PR_Poll() */ + memset(&pds[2], 0, sizeof(pds[2])); + memset(&pds[3], 0, sizeof(pds[3])); + memset(&pds[4], 0, sizeof(pds[4])); + npds = 5; + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort1, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + failed_already=1; + goto exit_now; + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort2, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + failed_already=1; + goto exit_now; + } + + if (debug_mode) { + printf("Two client threads are created. Each of them will\n"); + printf("send data to one of the two ports the server is listening on.\n"); + printf("The data they send is the port number. Each of them send\n"); + printf("the data five times, so you should see ten lines below,\n"); + printf("interleaved in an arbitrary order.\n"); + } + + /* two clients, three events per iteration: accept, read, close */ + i = 0; + while (i < 2 * 3 * NUM_ITERATIONS) { + PRPollDesc *tmp; + int nextIndex; + int nEvents = 0; + + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(retVal != 0); /* no timeout */ + if (retVal == -1) { + fprintf(stderr, "PR_Poll failed\n"); + failed_already=1; + goto exit_now; + } + + nextIndex = 2; + /* the two listening sockets */ + for (j = 0; j < 2; j++) { + other_pds[j] = pds[j]; + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); + if (pds[j].out_flags & PR_POLL_READ) { + PRFileDesc *sock; + + nEvents++; + sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + fprintf(stderr, "PR_Accept() failed\n"); + failed_already=1; + goto exit_now; + } + other_pds[nextIndex].fd = sock; + other_pds[nextIndex].in_flags = PR_POLL_READ; + nextIndex++; + } else if (pds[j].out_flags & PR_POLL_ERR) { + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); + failed_already=1; + goto exit_now; + } else if (pds[j].out_flags & PR_POLL_NVAL) { + fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n", + PR_FileDesc2NativeHandle(pds[j].fd)); + failed_already=1; + goto exit_now; + } + } + + for (j = 2; j < npds; j++) { + if (NULL == pds[j].fd) { + /* + * Keep the unused entries in the poll descriptor array + * for testing purposes. + */ + other_pds[nextIndex] = pds[j]; + nextIndex++; + continue; + } + + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); + if (pds[j].out_flags & PR_POLL_READ) { + PRInt32 nAvail; + PRInt32 nRead; + + nEvents++; + nAvail = PR_Available(pds[j].fd); + nRead = PR_Read(pds[j].fd, buf, sizeof(buf)); + PR_ASSERT(nAvail == nRead); + if (nRead == -1) { + fprintf(stderr, "PR_Read() failed\n"); + failed_already=1; + goto exit_now; + } else if (nRead == 0) { + PR_Close(pds[j].fd); + continue; + } else { + /* Just to be safe */ + buf[127] = '\0'; + if (debug_mode) printf("The server received \"%s\" from a client\n", buf); + } + } else if (pds[j].out_flags & PR_POLL_ERR) { + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); + failed_already=1; + goto exit_now; + } else if (pds[j].out_flags & PR_POLL_NVAL) { + fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n"); + failed_already=1; + goto exit_now; + } + other_pds[nextIndex] = pds[j]; + nextIndex++; + } + + PR_ASSERT(retVal == nEvents); + /* swap */ + tmp = pds; + pds = other_pds; + other_pds = tmp; + npds = nextIndex; + i += nEvents; + } + + if (debug_mode) printf("Tests passed\n"); + +exit_now: + + if (listenSock1) { + PR_Close(listenSock1); + } + if (listenSock2) { + PR_Close(listenSock2); + } + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/nsprpub/pr/tests/poll_to.c b/nsprpub/pr/tests/poll_to.c new file mode 100644 index 00000000000..93fcc79dcf5 --- /dev/null +++ b/nsprpub/pr/tests/poll_to.c @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: prpoll_to.c +** +** Description: This program tests PR_Poll with sockets. +** Timeout operation is tested +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" + +#ifndef XP_MAC +#include "private/pprio.h" +#else +#include "pprio.h" +#endif + +#include +#include +#include +PRIntn failed_already=0; +PRIntn debug_mode; + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + char buf[128]; + PRPollDesc pds0[10], pds1[10], *pds, *other_pds; + PRIntn npds; + PRInt32 retVal; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Poll with sockets.\n"); + printf("Timeout is tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the poll descriptor array */ + pds = pds0; + other_pds = pds1; + memset(pds, 0, sizeof(pds)); + pds[0].fd = listenSock1; + pds[0].in_flags = PR_POLL_READ; + pds[1].fd = listenSock2; + pds[1].in_flags = PR_POLL_READ; + npds = 2; + + /* Testing timeout */ + if (debug_mode) printf("PR_Poll should time out in 5 seconds\n"); + retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5)); + if (retVal != 0) { + PR_snprintf(buf, sizeof(buf), + "PR_Poll should time out and return 0, but it returns %ld\n", + retVal); + fprintf(stderr, "%s", buf); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (debug_mode) printf("PR_Poll timed out. Test passed.\n\n"); + +exit_now: + + if (listenSock1) { + PR_Close(listenSock1); + } + if (listenSock2) { + PR_Close(listenSock2); + } + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/nsprpub/pr/tests/pollable.c b/nsprpub/pr/tests/pollable.c new file mode 100644 index 00000000000..20da55a3791 --- /dev/null +++ b/nsprpub/pr/tests/pollable.c @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * 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 + +#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_DestroyPollableEvent(selfData.event); + + PR_fprintf(PR_STDOUT, "PASSED\n"); + return 0; +} diff --git a/nsprpub/pr/tests/prftest.c b/nsprpub/pr/tests/prftest.c new file mode 100644 index 00000000000..d3e7407d150 --- /dev/null +++ b/nsprpub/pr/tests/prftest.c @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: prftest.c + * Description: + * This is a simple test of the PR_snprintf() function defined + * in prprf.c. + */ + +#include "prlong.h" +#include "prprf.h" + +#include + +#define BUF_SIZE 128 + +int main() { + PRInt16 i16; + PRIntn n; + PRInt32 i32; + PRInt64 i64; + char buf[BUF_SIZE]; + char answer[BUF_SIZE]; + int i, rv = 0; + + i16 = -1; + n = -1; + i32 = -1; + LL_I2L(i64, i32); + + PR_snprintf(buf, BUF_SIZE, "%hx %x %lx %llx", i16, n, i32, i64); + strcpy(answer, "ffff "); + for (i = PR_BYTES_PER_INT * 2; i; i--) { + strcat(answer, "f"); + } + strcat(answer, " ffffffff ffffffffffffffff"); + + if (!strcmp(buf, answer)) { + printf("PR_snprintf test 1 passed\n"); + } else { + printf("PR_snprintf test 1 failed\n"); + printf("Converted string is %s\n", buf); + printf("Should be %s\n", answer); + rv = 1; + } + + i16 = -32; + n = 30; + i32 = 64; + LL_I2L(i64, 333); + PR_snprintf(buf, BUF_SIZE, "%d %hd %lld %ld", n, i16, i64, i32); + if (!strcmp(buf, "30 -32 333 64")) { + printf("PR_snprintf test 2 passed\n"); + } else { + printf("PR_snprintf test 2 failed\n"); + printf("Converted string is %s\n", buf); + printf("Should be 30 -32 333 64\n"); + rv = 1; + } + + return rv; +} diff --git a/nsprpub/pr/tests/prftest1.c b/nsprpub/pr/tests/prftest1.c new file mode 100644 index 00000000000..5ea26f65ec4 --- /dev/null +++ b/nsprpub/pr/tests/prftest1.c @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prftest1.c +** Description: +** This is a simple test of the PR_snprintf() function defined +** in prprf.c. +** +** 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. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" +#include "prttools.h" + +#include "prinit.h" +#include "prlong.h" +#include "prprf.h" + +#include + +#define BUF_SIZE 128 + +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static void Test_Result (int result) +{ + if (result == PASS) + printf ("PASS\n"); + else + printf ("FAIL\n"); +} + +int main( int argc, char *argv[]) +{ + PRInt16 i16; + PRIntn n; + PRInt32 i32; + PRInt64 i64; + char buf[BUF_SIZE]; + char answer[BUF_SIZE]; + int i; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + PR_STDIO_INIT(); + + i16 = -1; + n = -1; + i32 = -1; + LL_I2L(i64, i32); + + PR_snprintf(buf, BUF_SIZE, "%hx %x %lx %llx", i16, n, i32, i64); + strcpy(answer, "ffff "); + for (i = PR_BYTES_PER_INT * 2; i; i--) { + strcat(answer, "f"); + } + strcat(answer, " ffffffff ffffffffffffffff"); + + if (!strcmp(buf, answer)) { + if (debug_mode) printf("PR_snprintf test 1 passed\n"); + else Test_Result (PASS); + } else { + if (debug_mode) { + printf("PR_snprintf test 1 failed\n"); + printf("Converted string is %s\n", buf); + printf("Should be %s\n", answer); + } + else + Test_Result (FAIL); + } + + return 0; +} diff --git a/nsprpub/pr/tests/prftest2.c b/nsprpub/pr/tests/prftest2.c new file mode 100644 index 00000000000..0e5b2244b68 --- /dev/null +++ b/nsprpub/pr/tests/prftest2.c @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prftest2.c +** Description: +** This is a simple test of the PR_snprintf() function defined +** in prprf.c. +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prlong.h" +#include "prinit.h" +#include "prprf.h" + +#include + +#define BUF_SIZE 128 + +PRIntn failed_already=0; +PRIntn debug_mode; + +int main( int argc, char *argv[]) +{ + PRInt16 i16; + PRIntn n; + PRInt32 i32; + PRInt64 i64; + char buf[BUF_SIZE]; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + + PR_STDIO_INIT(); + i16 = -32; + n = 30; + i32 = 64; + LL_I2L(i64, 333); + PR_snprintf(buf, BUF_SIZE, "%d %hd %lld %ld", n, i16, i64, i32); + if (!strcmp(buf, "30 -32 333 64")) { + if (debug_mode) printf("PR_snprintf test 2 passed\n"); + } else { + if (debug_mode) { + printf("PR_snprintf test 2 failed\n"); + printf("Converted string is %s\n", buf); + printf("Should be 30 -32 333 64\n"); + } + else failed_already=1; + } + if(failed_already) + { + printf("FAILED\n"); + return 1; + } + else + { + printf("PASSED\n"); + return 0; + } +} diff --git a/nsprpub/pr/tests/primblok.c b/nsprpub/pr/tests/primblok.c new file mode 100644 index 00000000000..8a188834c8e --- /dev/null +++ b/nsprpub/pr/tests/primblok.c @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: primblok.c + * Purpose: testing whether the primordial thread can block in a + * native blocking function without affecting the correct + * functioning of NSPR I/O functions (Bugzilla bug #30746) + */ + +#if !defined(WINNT) + +#include + +int main() +{ + printf("This test is not relevant on this platform\n"); + return 0; +} + +#else /* WINNT */ + +#include "nspr.h" + +#include +#include +#include +#include + +#define TEST_FILE_NAME "primblok.dat" + +/* use InterlockedExchange to update this variable */ +static LONG iothread_done; + +static void PR_CALLBACK IOThread(void *arg) +{ + PRFileDesc *fd; + char buf[32]; + PRInt32 nbytes; + + /* Give the primordial thread one second to block */ + Sleep(1000); + + /* + * See if our PR_Write call will hang when the primordial + * thread is blocking in a native blocking function. + */ + fd = PR_Open(TEST_FILE_NAME, PR_WRONLY|PR_CREATE_FILE, 0666); + if (NULL == fd) { + fprintf(stderr, "PR_Open failed\n"); + exit(1); + } + memset(buf, 0xaf, sizeof(buf)); + fprintf(stderr, "iothread: calling PR_Write\n"); + nbytes = PR_Write(fd, buf, sizeof(buf)); + fprintf(stderr, "iothread: PR_Write returned\n"); + if (nbytes != sizeof(buf)) { + fprintf(stderr, "PR_Write returned %d\n", nbytes); + exit(1); + } + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_Delete failed\n"); + exit(1); + } + + /* Tell the main thread that we are done */ + InterlockedExchange(&iothread_done, 1); +} + +int main() +{ + PRThread *iothread; + + /* Must be a global thread */ + iothread = PR_CreateThread( + PR_USER_THREAD, IOThread, NULL, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (iothread == NULL) { + fprintf(stderr, "cannot create thread\n"); + exit(1); + } + + /* + * Block in a native blocking function. + * Give iothread 5 seconds to finish its task. + */ + Sleep(5000); + + /* + * Is iothread done or is it hung? + * + * I'm actually only interested in reading the value + * of iothread_done. I'm using InterlockedExchange as + * a thread-safe way to read iothread_done. + */ + if (InterlockedExchange(&iothread_done, 1) == 0) { + fprintf(stderr, "iothread is hung\n"); + fprintf(stderr, "FAILED\n"); + exit(1); + } + + if (PR_JoinThread(iothread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + printf("PASSED\n"); + return 0; +} /* main */ + +#endif /* WINNT */ diff --git a/nsprpub/pr/tests/priotest.c b/nsprpub/pr/tests/priotest.c new file mode 100644 index 00000000000..16def03d15a --- /dev/null +++ b/nsprpub/pr/tests/priotest.c @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: priotest.c + * Purpose: testing priorities + */ + +#ifdef XP_MAC +#error "This test does not run on Macintosh" +#else + + +#include "prcmon.h" +#include "prinit.h" +#include "prinrval.h" +#include "prlock.h" +#include "prlog.h" +#include "prmon.h" +#include "prprf.h" +#include "prthread.h" +#include "prtypes.h" + +#include "plerror.h" +#include "plgetopt.h" + +#include +#include + +#define DEFAULT_DURATION 5 + +static PRBool failed = PR_FALSE; +static PRIntervalTime oneSecond; +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE; + +static PRUint32 PerSecond(PRIntervalTime timein) +{ + PRUint32 loop = 0; + while (((PRIntervalTime)(PR_IntervalNow()) - timein) < oneSecond) + loop += 1; + return loop; +} /* PerSecond */ + +static void PR_CALLBACK Low(void *arg) +{ + PRUint32 t3 = 0, t2 = 0, t1 = 0, t0, *tn = (PRUint32*)arg; + while (1) + { + t0 = PerSecond(PR_IntervalNow()); + *tn = (t3 + 3 * t2 + 3 * t1 + t0) / 8; + t3 = t2; t2 = t1; t1 = t0; + } +} /* Low */ + +static void PR_CALLBACK High(void *arg) +{ + PRUint32 t3 = 0, t2 = 0, t1 = 0, t0, *tn = (PRUint32*)arg; + while (1) + { + PRIntervalTime timein = PR_IntervalNow(); + PR_Sleep(oneSecond >> 2); /* 0.25 seconds */ + t0 = PerSecond(timein); + *tn = (t3 + 3 * t2 + 3 * t1 + t0) / 8; + t3 = t2; t2 = t1; t1 = t0; + } +} /* High */ + +static void Help(void) +{ + PR_fprintf( + debug_out, "Usage: priotest [-d] [-c n]\n"); + PR_fprintf( + debug_out, "-c n\tduration of test in seconds (default: %d)\n", DEFAULT_DURATION); + PR_fprintf( + debug_out, "-d\tturn on debugging output (default: FALSE)\n"); +} /* Help */ + +static void RudimentaryTests(void) +{ + /* + ** Try some rudimentary tests like setting valid priority and + ** getting it back, or setting invalid priorities and getting + ** back a valid answer. + */ + PRThreadPriority priority; + PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_URGENT); + priority = PR_GetThreadPriority(PR_GetCurrentThread()); + failed = ((PR_TRUE == failed) || (PR_PRIORITY_URGENT != priority)) + ? PR_TRUE : PR_FALSE; + if (debug_mode && (PR_PRIORITY_URGENT != priority)) + { + PR_fprintf(debug_out, "PR_[S/G]etThreadPriority() failed\n"); + } + + + PR_SetThreadPriority( + PR_GetCurrentThread(), (PRThreadPriority)(PR_PRIORITY_FIRST - 1)); + priority = PR_GetThreadPriority(PR_GetCurrentThread()); + failed = ((PR_TRUE == failed) || (PR_PRIORITY_FIRST != priority)) + ? PR_TRUE : PR_FALSE; + if (debug_mode && (PR_PRIORITY_FIRST != priority)) + { + PR_fprintf(debug_out, "PR_SetThreadPriority(-1) failed\n"); + } + + PR_SetThreadPriority( + PR_GetCurrentThread(), (PRThreadPriority)(PR_PRIORITY_LAST + 1)); + priority = PR_GetThreadPriority(PR_GetCurrentThread()); + failed = ((PR_TRUE == failed) || (PR_PRIORITY_LAST != priority)) + ? PR_TRUE : PR_FALSE; + if (debug_mode && (PR_PRIORITY_LAST != priority)) + { + PR_fprintf(debug_out, "PR_SetThreadPriority(+1) failed\n"); + } + +} /* RudimentataryTests */ + +static void CreateThreads(PRUint32 *lowCount, PRUint32 *highCount) +{ + (void)PR_CreateThread( + PR_USER_THREAD, Low, lowCount, PR_PRIORITY_LOW, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + (void)PR_CreateThread( + PR_USER_THREAD, High, highCount, PR_PRIORITY_HIGH, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); +} /* CreateThreads */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRIntn duration = DEFAULT_DURATION; + PRUint32 totalCount, highCount = 0, lowCount = 0; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdc:"); + + debug_out = PR_STDOUT; + oneSecond = PR_SecondsToInterval(1); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* test duration */ + duration = atoi(opt->value); + break; + case 'h': /* help message */ + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + + if (duration == 0) duration = DEFAULT_DURATION; + + RudimentaryTests(); + + printf("Priority test: running for %d seconds\n\n", duration); + + (void)PerSecond(PR_IntervalNow()); + totalCount = PerSecond(PR_IntervalNow()); + + PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_URGENT); + + if (debug_mode) + { + PR_fprintf(debug_out, + "The high priority thread should get approximately three\n"); + PR_fprintf( debug_out, + "times what the low priority thread manages. A maximum of \n"); + PR_fprintf( debug_out, "%d cycles are available.\n\n", totalCount); + } + + duration = (duration + 4) / 5; + CreateThreads(&lowCount, &highCount); + while (duration--) + { + PRIntn loop = 5; + while (loop--) PR_Sleep(oneSecond); + if (debug_mode) + PR_fprintf(debug_out, "high : low :: %d : %d\n", highCount, lowCount); + } + + + PR_ProcessExit((failed) ? 1 : 0); + + PR_ASSERT(!"You can't get here -- but you did!"); + return 1; /* or here */ + +} /* main */ + +#endif /* ifdef XP_MAC */ + +/* priotest.c */ diff --git a/nsprpub/pr/tests/provider.c b/nsprpub/pr/tests/provider.c new file mode 100644 index 00000000000..57fa07b0b14 --- /dev/null +++ b/nsprpub/pr/tests/provider.c @@ -0,0 +1,1443 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * + * 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 +#include + + +#if defined(XP_UNIX) +#include +#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 13000 +#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_uithread, 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); + PR_Assert(s, file, ln); +} /* _MY_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), "%H:%M:%S", &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_GetCurrentThread(); + 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_GetCurrentThread())); + 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_GetCurrentThread(), 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_GetCurrentThread(); + 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_GetCurrentThread())); + 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 + +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(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) +#include + +static void *uithread_start(void *arg) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); + return NULL; +} /* uithread_start */ +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + +#if defined(IRIX) && !defined(_PR_PTHREADS) +#include +#include +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 /* 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_uithread: +#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + rv = PR_SUCCESS; + break; +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + 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_JOINABLE_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 = _PT_PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setstacksize(&tattr, 64 * 1024); + PR_ASSERT(0 == rv); + + rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object); + (void)_PT_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_uithread: +#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + { + int rv; + thread_t id; + long flags; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + + flags = THR_DETACHED; + + rv = thr_create(NULL, NULL, uithread_start, start_object, flags, &id); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + 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_GetCurrentThread(), 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_GetCurrentThread(); + + 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_GetCurrentThread(), 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_GetCurrentThread(); + PRSocketOptionData sockOpt; + + server->listener = PR_Socket(domain, SOCK_STREAM, protocol); + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(server->listener, &sockOpt); + TEST_ASSERT(PR_SUCCESS == rv); + + memset(&serverAddress, 0, sizeof(serverAddress)); + 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 threads allowed in accept (5)\n"); + PR_fprintf(debug_out, "\t-b backlock for listen (5)\n"); + PR_fprintf(debug_out, "\t-c number of clients to create (1)\n"); + PR_fprintf(debug_out, "\t-w minimal number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-W maximum number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-e duration of the test in seconds (10)\n"); + PR_fprintf(debug_out, "\t-s dsn name of server (localhost)\n"); + PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n"); + PR_fprintf(debug_out, "\t-T thread provider ('n' | 'p' | 'u' | 'w')(n)\n"); + PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n"); + PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n"); + 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; + char *thread_type; + + 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 threads allowed in accept + * -b backlock for listen + * -c number of clients to create + * -w minimal number of server threads + * -W maximum number of server threads + * -e duration of the test in seconds + * -s 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"); + +#if defined(WIN32) + thread_provider = thread_win32; +#elif defined(_PR_PTHREADS) + thread_provider = thread_pthread; +#elif defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + thread_provider = thread_uithread; +#elif defined(IRIX) + thread_provider = thread_sproc; +#else + thread_provider = thread_nspr; +#endif + + 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; + case '6': /* Use IPv6 */ + domain = PR_AF_INET6; + break; + 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 ('u' == *opt->value) thread_provider = thread_uithread; + 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_GetCurrentThread()); + + 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_GetCurrentThread())); + + 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_GetCurrentThread())); + + 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_GetCurrentThread())); + + 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_GetCurrentThread(), 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_GetCurrentThread(), 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_GetCurrentThread())); + 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_GetCurrentThread(), execution)); + + WaitForCompletion(execution); + + TimeOfDayMessage("Shutting down", PR_GetCurrentThread()); + + 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_GetCurrentThread(), 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_GetCurrentThread(), 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_GetCurrentThread(), 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_GetCurrentThread(), 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_GetCurrentThread())); + + if (thread_provider == thread_win32) + thread_type = "\nWin32 Thread Statistics\n"; + else if (thread_provider == thread_pthread) + thread_type = "\npthread Statistics\n"; + else if (thread_provider == thread_uithread) + thread_type = "\nUnix International (UI) Thread Statistics\n"; + else if (thread_provider == thread_sproc) + thread_type = "\nsproc Statistics\n"; + else { + PR_ASSERT(thread_provider == thread_nspr); + thread_type = "\nPRThread Statistics\nn"; + } + + PT_FPrintStats(debug_out, thread_type); + + TimeOfDayMessage("Test exiting at", PR_GetCurrentThread()); + PR_Cleanup(); + return 0; +} /* main */ + +/* cltsrv.c */ diff --git a/nsprpub/pr/tests/prpoll.c b/nsprpub/pr/tests/prpoll.c new file mode 100644 index 00000000000..1dfdb074b36 --- /dev/null +++ b/nsprpub/pr/tests/prpoll.c @@ -0,0 +1,378 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifdef WIN32 +#include +#endif + +#ifdef XP_OS2_VACPP +#include /* for close() */ +#endif + +#ifdef XP_UNIX +#include /* for close() */ +#endif + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" + +#ifndef XP_MAC +#include "private/pprio.h" +#else +#include "pprio.h" +#endif + +#define CLIENT_LOOPS 5 +#define BUF_SIZE 128 + +#include +#include +#include + +static void +clientThreadFunc(void *arg) +{ + PRUint16 port = (PRUint16) arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[BUF_SIZE]; + int i; + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons(port); + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + PR_snprintf(buf, sizeof(buf), "%hu", port); + + for (i = 0; i < 5; i++) { + sock = PR_NewTCPSocket(); + PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + + PR_Write(sock, buf, sizeof(buf)); + PR_Close(sock); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *badFD; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + char buf[BUF_SIZE]; + PRThread *clientThread; + PRPollDesc pds0[10], pds1[10], *pds, *other_pds; + PRIntn npds; + PRInt32 retVal; + PRInt32 rv; + PROsfd sd; + struct sockaddr_in saddr; + PRIntn saddr_len; + PRUint16 listenPort3; + PRFileDesc *socket_poll_fd; + PRIntn i, j; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + printf("This program tests PR_Poll with sockets.\n"); + printf("Timeout, error reporting, and normal operation are tested.\n\n"); + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + exit(1); + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + exit(1); + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + exit(1); + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + exit(1); + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + exit(1); + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + exit(1); + } + /* Set up the poll descriptor array */ + pds = pds0; + other_pds = pds1; + memset(pds, 0, sizeof(pds)); + npds = 0; + pds[npds].fd = listenSock1; + pds[npds].in_flags = PR_POLL_READ; + npds++; + pds[npds].fd = listenSock2; + pds[npds].in_flags = PR_POLL_READ; + npds++; + + sd = socket(AF_INET, SOCK_STREAM, 0); + PR_ASSERT(sd >= 0); + memset((char *) &saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_port = htons(0); + + rv = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)); + PR_ASSERT(rv == 0); + saddr_len = sizeof(saddr); + rv = getsockname(sd, (struct sockaddr *) &saddr, &saddr_len); + PR_ASSERT(rv == 0); + listenPort3 = ntohs(saddr.sin_port); + + rv = listen(sd, 5); + PR_ASSERT(rv == 0); + pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd); + PR_ASSERT(pds[npds].fd); + pds[npds].in_flags = PR_POLL_READ; + npds++; + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu, %hu and %hu\n\n", + listenPort1, listenPort2, listenPort3); + printf("%s", buf); + + /* Testing timeout */ + printf("PR_Poll should time out in 5 seconds\n"); + retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5)); + if (retVal != 0) { + PR_snprintf(buf, sizeof(buf), + "PR_Poll should time out and return 0, but it returns %ld\n", + retVal); + fprintf(stderr, "%s", buf); + exit(1); + } + printf("PR_Poll timed out. Test passed.\n\n"); + + /* Testing bad fd */ + printf("PR_Poll should detect a bad file descriptor\n"); + if ((badFD = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a TCP socket\n"); + exit(1); + } + + pds[npds].fd = badFD; + pds[npds].in_flags = PR_POLL_READ; + npds++; + PR_Close(badFD); /* make the fd bad */ +#if 0 + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); + if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) { + fprintf(stderr, "Failed to detect the bad fd: " + "PR_Poll returns %d, out_flags is 0x%hx\n", + retVal, pds[npds - 1].out_flags); + exit(1); + } + printf("PR_Poll detected the bad fd. Test passed.\n\n"); +#endif + npds--; + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort1, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort2, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort3, + PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + + printf("Three client threads are created. Each of them will\n"); + printf("send data to one of the three ports the server is listening on.\n"); + printf("The data they send is the port number. Each of them send\n"); + printf("the data five times, so you should see ten lines below,\n"); + printf("interleaved in an arbitrary order.\n"); + + /* 30 events total */ + i = 0; + while (i < 30) { + PRPollDesc *tmp; + int nextIndex; + int nEvents = 0; + + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(retVal != 0); /* no timeout */ + if (retVal == -1) { + fprintf(stderr, "PR_Poll failed\n"); + exit(1); + } + + nextIndex = 3; + /* the three listening sockets */ + for (j = 0; j < 3; j++) { + other_pds[j] = pds[j]; + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); + if (pds[j].out_flags & PR_POLL_READ) { + PRFileDesc *sock; + + nEvents++; + if (j == 2) { + PROsfd newsd; + newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0); + if (newsd == -1) { + fprintf(stderr, "accept() failed\n"); + exit(1); + } + other_pds[nextIndex].fd = PR_CreateSocketPollFd(newsd); + PR_ASSERT(other_pds[nextIndex].fd); + other_pds[nextIndex].in_flags = PR_POLL_READ; + } else { + sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + fprintf(stderr, "PR_Accept() failed\n"); + exit(1); + } + other_pds[nextIndex].fd = sock; + other_pds[nextIndex].in_flags = PR_POLL_READ; + } + nextIndex++; + } else if (pds[j].out_flags & PR_POLL_ERR) { + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); + exit(1); + } else if (pds[j].out_flags & PR_POLL_NVAL) { + fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n", + PR_FileDesc2NativeHandle(pds[j].fd)); + exit(1); + } + } + + for (j = 3; j < npds; j++) { + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); + if (pds[j].out_flags & PR_POLL_READ) { + PRInt32 nBytes; + + nEvents++; + /* XXX: This call is a hack and should be fixed */ + if (PR_GetDescType(pds[j].fd) == (PRDescType) 0) { + nBytes = recv(PR_FileDesc2NativeHandle(pds[j].fd), buf, + sizeof(buf), 0); + if (nBytes == -1) { + fprintf(stderr, "recv() failed\n"); + exit(1); + } + printf("Server read %d bytes from native fd %d\n",nBytes, + PR_FileDesc2NativeHandle(pds[j].fd)); +#ifdef WIN32 + closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd)); +#else + close(PR_FileDesc2NativeHandle(pds[j].fd)); +#endif + PR_DestroySocketPollFd(pds[j].fd); + } else { + nBytes = PR_Read(pds[j].fd, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read() failed\n"); + exit(1); + } + PR_Close(pds[j].fd); + } + /* Just to be safe */ + buf[BUF_SIZE - 1] = '\0'; + printf("The server received \"%s\" from a client\n", buf); + } else if (pds[j].out_flags & PR_POLL_ERR) { + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); + exit(1); + } else if (pds[j].out_flags & PR_POLL_NVAL) { + fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n"); + exit(1); + } else { + other_pds[nextIndex] = pds[j]; + nextIndex++; + } + } + + PR_ASSERT(retVal == nEvents); + /* swap */ + tmp = pds; + pds = other_pds; + other_pds = tmp; + npds = nextIndex; + i += nEvents; + } + PR_DestroySocketPollFd(socket_poll_fd); + + printf("All tests finished\n"); + PR_Cleanup(); + return 0; +} diff --git a/nsprpub/pr/tests/prpollml.c b/nsprpub/pr/tests/prpollml.c new file mode 100644 index 00000000000..d20f1967660 --- /dev/null +++ b/nsprpub/pr/tests/prpollml.c @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This test exercises the code that allocates and frees the syspoll_list + * array of PRThread in the pthreads version. This test is intended to be + * run under Purify to verify that there is no memory leak. + */ + +#include "nspr.h" + +#include +#include +#include + +#define POLL_DESC_COUNT 256 /* This should be greater than the + * STACK_POLL_DESC_COUNT macro in + * ptio.c to cause syspoll_list to + * be created. */ + +static PRPollDesc pd[POLL_DESC_COUNT]; + +static void Test(void) +{ + int i; + PRInt32 rv; + PRIntervalTime timeout; + + timeout = PR_MillisecondsToInterval(10); + /* cause syspoll_list to grow */ + for (i = 1; i <= POLL_DESC_COUNT; i++) { + rv = PR_Poll(pd, i, timeout); + if (rv != 0) { + fprintf(stderr, + "PR_Poll should time out but returns %d (%d, %d)\n", + (int) rv, (int) PR_GetError(), (int) PR_GetOSError()); + exit(1); + } + } + /* syspoll_list should be large enough for all these */ + for (i = POLL_DESC_COUNT; i >= 1; i--) { + rv = PR_Poll(pd, i, timeout); + if (rv != 0) { + fprintf(stderr, "PR_Poll should time out but returns %d\n", + (int) rv); + exit(1); + } + } +} + +static void ThreadFunc(void *arg) +{ + Test(); +} + +int main(int argc, char **argv) +{ + int i; + PRThread *thread; + PRFileDesc *sock; + PRNetAddr addr; + + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons(0); + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + for (i = 0; i < POLL_DESC_COUNT; i++) { + sock = PR_NewTCPSocket(); + if (sock == NULL) { + fprintf(stderr, "PR_NewTCPSocket failed (%d, %d)\n", + (int) PR_GetError(), (int) PR_GetOSError()); + fprintf(stderr, "Ensure the per process file descriptor limit " + "is greater than %d.", POLL_DESC_COUNT); + exit(1); + } + if (PR_Bind(sock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed (%d, %d)\n", + (int) PR_GetError(), (int) PR_GetOSError()); + exit(1); + } + if (PR_Listen(sock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed (%d, %d)\n", + (int) PR_GetError(), (int) PR_GetOSError()); + exit(1); + } + + pd[i].fd = sock; + pd[i].in_flags = PR_POLL_READ; + } + + /* first run the test on the primordial thread */ + Test(); + + /* then run the test on all three kinds of threads */ + thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == thread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(thread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == thread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(thread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == thread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(thread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + for (i = 0; i < POLL_DESC_COUNT; i++) { + if (PR_Close(pd[i].fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + PR_Cleanup(); + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/prselect.c b/nsprpub/pr/tests/prselect.c new file mode 100644 index 00000000000..ff6ebdc6816 --- /dev/null +++ b/nsprpub/pr/tests/prselect.c @@ -0,0 +1,372 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1997 - Netscape Communications Corporation +** +** Name: prselect_err.c +** +** Description: tests PR_Select with sockets Error condition functions. +** +** 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. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" +#include "prttools.h" + + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prerror.h" +#include "prnetdb.h" + +#include +#include +#include + +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static Test_Result (int result) +{ + if (result == PASS) + printf ("PASS\n"); + else + printf ("FAIL\n"); +} + +static void +clientThreadFunc(void *arg) +{ + PRUint16 port = (PRUint16) arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[128]; + int i; + + addr.inet.family = AF_INET; + addr.inet.port = PR_htons(port); + addr.inet.ip = PR_htonl(INADDR_LOOPBACK); + PR_snprintf(buf, sizeof(buf), "%hu", port); + + for (i = 0; i < 5; i++) { + sock = PR_NewTCPSocket(); + PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + PR_Write(sock, buf, sizeof(buf)); + PR_Close(sock); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *badFD; + PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds; + PRIntn nfds; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + PR_fd_set readFdSet; + char buf[128]; + PRThread *clientThread; + PRInt32 retVal; + PRIntn i, j; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Select with sockets. Timeout, error\n"); + printf("reporting, and normal operation are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + printf("%s", buf); + + /* Set up the fd set */ + PR_FD_ZERO(&readFdSet); + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + /* Testing timeout */ + if (debug_mode) printf("PR_Select should time out in 5 seconds\n"); + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_SecondsToInterval(5)); + if (retVal != 0) { + PR_snprintf(buf, sizeof(buf), + "PR_Select should time out and return 0, but it returns %ld\n", + retVal); + fprintf(stderr, "%s", buf); + if (retVal == -1) { + fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), + PR_GetOSError()); + if (!debug_mode) Test_Result(FAIL); + } + exit(1); + } + if (debug_mode) printf("PR_Select timed out. Test passed.\n\n"); + else Test_Result(PASS); + + /* Testing bad fd */ + printf("PR_Select should detect a bad file descriptor\n"); + if ((badFD = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a TCP socket\n"); + exit(1); + } + + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + PR_FD_SET(badFD, &readFdSet); + PR_Close(badFD); /* make the fd bad */ + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_INTERVAL_NO_TIMEOUT); + if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) { + fprintf(stderr, "Failed to detect the bad fd: " + "PR_Select returns %d\n", retVal); + if (retVal == -1) { + fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), + PR_GetOSError()); + } + exit(1); + } + printf("PR_Select detected a bad fd. Test passed.\n\n"); + PR_FD_CLR(badFD, &readFdSet); + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort1, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort2, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + printf("Two client threads are created. Each of them will\n"); + printf("send data to one of the two ports the server is listening on.\n"); + printf("The data they send is the port number. Each of them send\n"); + printf("the data five times, so you should see ten lines below,\n"); + printf("interleaved in an arbitrary order.\n"); + + /* set up the fd array */ + fds = fds0; + other_fds = fds1; + fds[0] = listenSock1; + fds[1] = listenSock2; + nfds = 2; + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + /* 20 events total */ + i = 0; + while (i < 20) { + PRFileDesc **tmp; + int nextIndex; + int nEvents = 0; + + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(retVal != 0); /* no timeout */ + if (retVal == -1) { + fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + + nextIndex = 2; + /* the two listening sockets */ + for (j = 0; j < 2; j++) { + other_fds[j] = fds[j]; + if (PR_FD_ISSET(fds[j], &readFdSet)) { + PRFileDesc *sock; + + nEvents++; + sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + fprintf(stderr, "PR_Accept() failed\n"); + exit(1); + } + other_fds[nextIndex] = sock; + PR_FD_SET(sock, &readFdSet); + nextIndex++; + } + PR_FD_SET(fds[j], &readFdSet); + } + + for (j = 2; j < nfds; j++) { + if (PR_FD_ISSET(fds[j], &readFdSet)) { + PRInt32 nBytes; + + PR_FD_CLR(fds[j], &readFdSet); + nEvents++; + nBytes = PR_Read(fds[j], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read() failed\n"); + exit(1); + } + /* Just to be safe */ + buf[127] = '\0'; + PR_Close(fds[j]); + printf("The server received \"%s\" from a client\n", buf); + } else { + PR_FD_SET(fds[j], &readFdSet); + other_fds[nextIndex] = fds[j]; + nextIndex++; + } + } + + PR_ASSERT(retVal == nEvents); + /* swap */ + tmp = fds; + fds = other_fds; + other_fds = tmp; + nfds = nextIndex; + i += nEvents; + } + + printf("All tests finished\n"); + PR_Cleanup(); + return 0; +} diff --git a/nsprpub/pr/tests/prttools.h b/nsprpub/pr/tests/prttools.h new file mode 100644 index 00000000000..dc38f316a07 --- /dev/null +++ b/nsprpub/pr/tests/prttools.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Used in Regress Tool */ +#define NOSTATUS 2 +#define PASS 1 +#define FAIL 0 + +PRIntn debug_mode=0; diff --git a/nsprpub/pr/tests/randseed.c b/nsprpub/pr/tests/randseed.c new file mode 100644 index 00000000000..fc1fbaebd82 --- /dev/null +++ b/nsprpub/pr/tests/randseed.c @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: rngseed.c +** Description: +** Test NSPR's Random Number Seed generator +** +** Initial test: Just make sure it outputs some data. +** +** ... more? ... check some iterations to ensure it is random (no dupes) +** ... more? ... histogram distribution of random numbers +*/ + +#include "plgetopt.h" +#include "nspr.h" +#include "prrng.h" +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ + +PRIntn optRandCount = 30; +char buf[40]; +PRSize bufSize = sizeof(buf); +PRSize rSize; +PRIntn i; + +/* +** Emit help text for this test +*/ +static void Help( void ) +{ + printf("Template: Help(): display your help message(s) here"); + exit(1); +} /* end Help() */ + +static void PrintRand( void *buf, PRIntn size ) +{ + PRUint32 *rp = buf; + PRIntn i; + + printf("%4.4d--\n", size ); + while (size > 0 ) { + switch( size ) { + case 1 : + printf("%2.2X\n", *(rp++) ); + size -= 4; + break; + case 2 : + printf("%4.4X\n", *(rp++) ); + size -= 4; + break; + case 3 : + printf("%6.6X\n", *(rp++) ); + size -= 4; + break; + default: + while ( size >= 4) { + PRIntn i = 3; + do { + printf("%8.8X ", *(rp++) ); + size -= 4; + } while( i-- ); + i = 3; + printf("\n"); + } + break; + } /* end switch() */ + } /* end while() */ +} /* end PrintRand() */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdv"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'v': /* verbose mode */ + msgLevel = PR_LOG_DEBUG; + break; + case 'h': /* help message */ + Help(); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + for ( i = 0; i < optRandCount ; i++ ) { + memset( buf, 0, bufSize ); + rSize = PR_GetRandomNoise( buf, bufSize ); + if (!rSize) { + fprintf(stderr, "Not implemented\n" ); + failed_already = PR_TRUE; + break; + } + if (debug) PrintRand( buf, rSize ); + } + + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end template.c */ + diff --git a/nsprpub/pr/tests/ranfile.c b/nsprpub/pr/tests/ranfile.c new file mode 100644 index 00000000000..a024bcd8b1e --- /dev/null +++ b/nsprpub/pr/tests/ranfile.c @@ -0,0 +1,433 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Contact: AOF +** +** Name: ranfile.c +** +** Description: Test to hammer on various components of NSPR +** Modification History: +** 20-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prthread.h" +#include "prlock.h" +#include "prcvar.h" +#include "prmem.h" +#include "prinrval.h" +#include "prio.h" + +#include +#include + +static PRIntn debug_mode = 0; +static PRIntn failed_already=0; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +typedef enum {sg_go, sg_stop, sg_done} Action; +typedef enum {sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem; + +typedef struct Hammer_s { + PRLock *ml; + PRCondVar *cv; + PRUint32 id; + PRUint32 limit; + PRUint32 writes; + PRThread *thread; + PRIntervalTime timein; + Action action; + Problem problem; +} Hammer_t; + +#define DEFAULT_LIMIT 10 +#define DEFAULT_THREADS 2 +#define DEFAULT_LOOPS 1 + +static PRInt32 pageSize = 1024; +static const char* baseName = "./"; +static const char *programName = "Random File"; + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +/*********************************************************************** +** PRIVATE FUNCTION: Random +** DESCRIPTION: +** Generate a pseudo-random number +** INPUTS: None +** OUTPUTS: None +** RETURN: A pseudo-random unsigned number, 32-bits wide +** SIDE EFFECTS: +** Updates random seed (a static) +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: +** Uses the current interval timer value, promoted to a 64 bit +** float as a multiplier for a static residue (which begins +** as an uninitialized variable). The result is bits [16..48) +** of the product. Seed is then updated with the return value +** promoted to a float-64. +***********************************************************************/ +static PRUint32 Random(void) +{ + PRUint32 rv; + PRUint64 shift; + static PRFloat64 seed = 0x58a9382; /* Just make sure it isn't 0! */ + PRFloat64 random = seed * (PRFloat64)PR_IntervalNow(); + LL_USHR(shift, *((PRUint64*)&random), 16); + LL_L2UI(rv, shift); + seed = (PRFloat64)rv; + return rv; +} /* Random */ + +/*********************************************************************** +** PRIVATE FUNCTION: Thread +** DESCRIPTION: +** Hammer on the file I/O system +** INPUTS: A pointer to the thread's private data +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** Creates, accesses and deletes a file +** RESTRICTIONS: +** (Currently) must have file create permission in "/usr/tmp". +** MEMORY: NA +** ALGORITHM: +** This function is a root of a thread +** 1) Creates a (hopefully) unique file in /usr/tmp/ +** 2) Writes a zero to a random number of sequential pages +** 3) Closes the file +** 4) Reopens the file +** 5) Seeks to a random page within the file +** 6) Writes a one byte on that page +** 7) Repeat steps [5..6] for each page in the file +** 8) Close and delete the file +** 9) Repeat steps [1..8] until told to stop +** 10) Notify complete and return +***********************************************************************/ +static void PR_CALLBACK Thread(void *arg) +{ + PRUint32 index; + char filename[30]; + const char zero = 0; + PRFileDesc *file = NULL; + PRStatus rv = PR_SUCCESS; + Hammer_t *cd = (Hammer_t*)arg; + + (void)sprintf(filename, "%ssg%04ld.dat", baseName, cd->id); + + if (debug_mode) printf("Starting work on %s\n", filename); + + while (PR_TRUE) + { + PRUint32 bytes; + PRUint32 minor = (Random() % cd->limit) + 1; + PRUint32 random = (Random() % cd->limit) + 1; + PRUint32 pages = (Random() % cd->limit) + 10; + while (minor-- > 0) + { + cd->problem = sg_okay; + if (cd->action != sg_go) goto finished; + cd->problem = sg_open; + file = PR_Open(filename, PR_RDWR|PR_CREATE_FILE, 0666); + if (file == NULL) goto finished; + for (index = 0; index < pages; index++) + { + cd->problem = sg_okay; + if (cd->action != sg_go) goto close; + cd->problem = sg_seek; + bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET); + if (bytes != pageSize * index) goto close; + cd->problem = sg_write; + bytes = PR_Write(file, &zero, sizeof(zero)); + if (bytes <= 0) goto close; + cd->writes += 1; + } + cd->problem = sg_close; + rv = PR_Close(file); + if (rv != PR_SUCCESS) goto purge; + + cd->problem = sg_okay; + if (cd->action != sg_go) goto purge; + + cd->problem = sg_open; + file = PR_Open(filename, PR_RDWR, 0666); + for (index = 0; index < pages; index++) + { + cd->problem = sg_okay; + if (cd->action != sg_go) goto close; + cd->problem = sg_seek; + bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET); + if (bytes != pageSize * index) goto close; + cd->problem = sg_write; + bytes = PR_Write(file, &zero, sizeof(zero)); + if (bytes <= 0) goto close; + cd->writes += 1; + random = (random + 511) % pages; + } + cd->problem = sg_close; + rv = PR_Close(file); + if (rv != PR_SUCCESS) goto purge; + cd->problem = sg_delete; + rv = PR_Delete(filename); + if (rv != PR_SUCCESS) goto finished; + } + } + +close: + (void)PR_Close(file); +purge: + (void)PR_Delete(filename); +finished: + PR_Lock(cd->ml); + cd->action = sg_done; + PR_NotifyCondVar(cd->cv); + PR_Unlock(cd->ml); + + if (debug_mode) printf("Ending work on %s\n", filename); + + return; +} /* Thread */ + +static Hammer_t hammer[100]; +static PRCondVar *cv; +/*********************************************************************** +** PRIVATE FUNCTION: main +** DESCRIPTION: +** Hammer on the file I/O system +** INPUTS: The usual argc and argv +** argv[0] - program name (not used) +** argv[1] - the number of times to execute the major loop +** argv[2] - the number of threads to toss into the batch +** argv[3] - the clipping number applied to randoms +** default values: loops = 2, threads = 10, limit = 57 +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** Creates, accesses and deletes lots of files +** RESTRICTIONS: +** (Currently) must have file create permission in "/usr/tmp". +** MEMORY: NA +** ALGORITHM: +** 1) Fork a "Thread()" +** 2) Wait for 'interleave' seconds +** 3) For [0..'threads') repeat [1..2] +** 4) Mark all objects to stop +** 5) Collect the threads, accumulating the results +** 6) For [0..'loops') repeat [1..5] +** 7) Print accumulated results and exit +** +** Characteristic output (from IRIX) +** Random File: Using loops = 2, threads = 10, limit = 57 +** Random File: [min [avg] max] writes/sec average +***********************************************************************/ +int main (int argc, char *argv[]) +{ + PRLock *ml; + PRUint32 id = 0; + int active, poll; + PRIntervalTime interleave; + PRIntervalTime duration = 0; + int limit = 0, loops = 0, threads = 0, times; + PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0, durationTot = 0, writesMax = 0; + + const char *where[] = {"okay", "open", "close", "delete", "write", "seek"}; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'l': /* limiting number */ + limit = atoi(opt->value); + break; + case 't': /* number of threads */ + threads = atoi(opt->value); + break; + case 'i': /* iteration counter */ + loops = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + interleave = PR_SecondsToInterval(10); + +#ifdef XP_MAC + SetupMacPrintfLog("ranfile.log"); + debug_mode = 1; +#endif + + ml = PR_NewLock(); + cv = PR_NewCondVar(ml); + + if (loops == 0) loops = DEFAULT_LOOPS; + if (limit == 0) limit = DEFAULT_LIMIT; + if (threads == 0) threads = DEFAULT_THREADS; + + if (debug_mode) printf( + "%s: Using loops = %d, threads = %d, limit = %d and %s threads\n", + programName, loops, threads, limit, + (thread_scope == PR_LOCAL_THREAD) ? "LOCAL" : "GLOBAL"); + + for (times = 0; times < loops; ++times) + { + if (debug_mode) printf("%s: Setting concurrency level to %d\n", programName, times + 1); + PR_SetConcurrency(times + 1); + for (active = 0; active < threads; active++) + { + hammer[active].ml = ml; + hammer[active].cv = cv; + hammer[active].id = id++; + hammer[active].writes = 0; + hammer[active].action = sg_go; + hammer[active].problem = sg_okay; + hammer[active].limit = (Random() % limit) + 1; + hammer[active].timein = PR_IntervalNow(); + hammer[active].thread = PR_CreateThread( + PR_USER_THREAD, Thread, &hammer[active], + PR_GetThreadPriority(PR_GetCurrentThread()), + thread_scope, PR_JOINABLE_THREAD, 0); + + PR_Lock(ml); + PR_WaitCondVar(cv, interleave); /* start new ones slowly */ + PR_Unlock(ml); + } + + /* + * The last thread started has had the opportunity to run for + * 'interleave' seconds. Now gather them all back in. + */ + PR_Lock(ml); + for (poll = 0; poll < threads; poll++) + { + if (hammer[poll].action == sg_go) /* don't overwrite done */ + hammer[poll].action = sg_stop; /* ask him to stop */ + } + PR_Unlock(ml); + + while (active > 0) + { + for (poll = 0; poll < threads; poll++) + { + PR_Lock(ml); + while (hammer[poll].action < sg_done) + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(ml); + + active -= 1; /* this is another one down */ + (void)PR_JoinThread(hammer[poll].thread); + hammer[poll].thread = NULL; + if (hammer[poll].problem == sg_okay) + { + duration = PR_IntervalToMilliseconds( + PR_IntervalNow() - hammer[poll].timein); + writes = hammer[poll].writes * 1000 / duration; + if (writes < writesMin) + writesMin = writes; + if (writes > writesMax) + writesMax = writes; + writesTot += hammer[poll].writes; + durationTot += duration; + } + else + if (debug_mode) printf( + "%s: test failed %s after %ld seconds\n", + programName, where[hammer[poll].problem], duration); + else failed_already=1; + } + } + } + if (debug_mode) printf( + "%s: [%ld [%ld] %ld] writes/sec average\n", + programName, writesMin, writesTot * 1000 / durationTot, writesMax); + + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + + if (failed_already) + { + printf("FAIL\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } +} /* main */ diff --git a/nsprpub/pr/tests/rmdir.c b/nsprpub/pr/tests/rmdir.c new file mode 100644 index 00000000000..81689e8d8d8 --- /dev/null +++ b/nsprpub/pr/tests/rmdir.c @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: rmdir.c +** Description: Demonstrate bugzilla 80884. +** +** after fix to unix_errors.c, message should report correct +** failure of PR_Rmdir(). +** +** +** +*/ + +#include +#include +#include +#include +#include "plgetopt.h" + +#define DIRNAME "xxxBug80884/" +#define FILENAME "file80883" + +PRBool failed_already = PR_FALSE; +PRBool debug_mode = PR_FALSE; + +PRLogModuleInfo *lm; + +/* +** Help() -- print Usage information +*/ +static void Help( void ) { + fprintf(stderr, "template usage:\n" + "\t-d debug mode\n" + ); +} /* --- end Help() */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dh"); + PRFileDesc* fd; + PRErrorCode err; + + /* parse command line options */ + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + lm = PR_NewLogModule( "testcase" ); + + (void) PR_MkDir( DIRNAME, 0777); + fd = PR_Open( DIRNAME FILENAME, PR_CREATE_FILE|PR_RDWR, 0666); + if (fd == 0) { + PRErrorCode err = PR_GetError(); + fprintf(stderr, "create file fails: %d: %s\n", err, + PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); + failed_already = PR_TRUE; + goto Finished; + } + + PR_Close(fd); + + if (PR_RmDir( DIRNAME ) == PR_SUCCESS) { + fprintf(stderr, "remove directory succeeds\n"); + failed_already = PR_TRUE; + goto Finished; + } + + err = PR_GetError(); + fprintf(stderr, "remove directory fails with: %d: %s\n", err, + PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); + + (void) PR_Delete( DIRNAME FILENAME); + (void) PR_RmDir( DIRNAME ); + + return 0; + +Finished: + if ( debug_mode ) printf("%s\n", ( failed_already ) ? "FAILED" : "PASS" ); + return( (failed_already)? 1 : 0 ); +} /* --- end main() */ +/* --- end template.c */ diff --git a/nsprpub/pr/tests/runtests.sh b/nsprpub/pr/tests/runtests.sh new file mode 100755 index 00000000000..f9149481494 --- /dev/null +++ b/nsprpub/pr/tests/runtests.sh @@ -0,0 +1,298 @@ +#!/bin/sh +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# runtests.sh +# Bourne shell script for nspr tests +# + +SYSTEM_INFO=`uname -a` +OS_ARCH=`uname -s` + +if [ $OS_ARCH = "Windows_NT" ] || [ $OS_ARCH = "OS/2" ] +then + NULL_DEVICE=nul +else + NULL_DEVICE=/dev/null + FILE_D=`ulimit -n` + if [ $FILE_D -lt 512 ] + then + ulimit -n 512 + fi +fi + +# +# Irrevelant tests +# +#bug1test - used to demonstrate a bug on NT +#bigfile2 - requires 4Gig file creation. See BugZilla #5451 +#bigfile3 - requires 4Gig file creation. See BugZilla #5451 +#dbmalloc - obsolete; originally for testing debug version of nspr's malloc +#dbmalloc1 - obsolete; originally for testing debug version of nspr's malloc +#depend - obsolete; used to test a initial spec for library dependencies +#dceemu - used to tests special functions in NSPR for DCE emulation +#ipv6 - IPV6 not in use by NSPR clients +#mbcs - tests use of multi-byte charset for filenames. See BugZilla #25140 +#sproc_ch - obsolete; sproc-based tests for Irix +#sproc_p - obsolete; sproc-based tests for Irix +#io_timeoutk - obsolete; subsumed in io_timeout +#io_timeoutu - obsolete; subsumed in io_timeout +#prftest1 - obsolete; subsumed by prftest +#prftest2 - obsolete; subsumed by prftest +#prselect - obsolete; PR_Select is obsolete +#select2 - obsolete; PR_Select is obsolete +#sem - obsolete; PRSemaphore is obsolete +#stat - for OS2? +#suspend - private interfaces PR_SuspendAll, PR_ResumeAll, etc.. +#thruput - needs to be run manually as client/server +#time - used to measure time with native calls and nspr calls +#tmoacc - should be run with tmocon +#tmocon - should be run with tmoacc +#op_noacc - limited use +#yield - limited use for PR_Yield + +# +# Tests not run (but should) +# + +#forktest (failed on IRIX) +#nbconn - fails on some platforms +#poll_er - fails on some platforms? limited use? +#prpoll - the bad-FD test needs to be moved to a different test +#sleep - specific to OS/2 + +LOGFILE=${NSPR_TEST_LOGFILE:-$NULL_DEVICE} + +# +# Tests run on all platforms +# + +TESTS=" +accept +acceptread +acceptreademu +affinity +alarm +anonfm +atomic +attach +bigfile +cleanup +cltsrv +concur +cvar +cvar2 +dlltest +dtoa +errcodes +exit +fdcach +fileio +foreign +formattm +fsync +gethost +getproto +i2l +initclk +inrval +instrumt +intrio +intrupt +io_timeout +ioconthr +join +joinkk +joinku +joinuk +joinuu +layer +lazyinit +libfilename +lltest +lock +lockfile +logger +many_cv +multiwait +nameshm1 +nblayer +nonblock +ntioto +ntoh +op_2long +op_excl +op_filnf +op_filok +op_nofil +parent +peek +perf +pipeping +pipeping2 +pipeself +poll_nm +poll_to +pollable +prftest +primblok +provider +prpollml +ranfile +randseed +rwlocktest +sel_spd +selct_er +selct_nm +selct_to +selintr +sema +semaerr +semaping +sendzlf +server_test +servr_kk +servr_uk +servr_ku +servr_uu +short_thread +sigpipe +socket +sockopt +sockping +sprintf +stack +stdio +str2addr +strod +switch +system +testbit +testfile +threads +timemac +timetest +tpd +udpsrv +vercheck +version +writev +xnotify +zerolen" + +rval=0 + + +# +# When set, value of the environment variable TEST_TIMEOUT is the maximum +# time (secs) allowed for a test program beyond which it is terminated. +# If TEST_TIMEOUT is not set or if it's value is 0, then test programs +# don't timeout. +# +# Running runtests.ksh under MKS toolkit on NT, 95, 98 does not cause +# timeout detection correctly. For these platforms, do not attempt timeout +# test. (lth). +# +# + +OS_PLATFORM=`uname` +OBJDIR=`basename $PWD` +printf "\nNSPR Test Results - $OBJDIR\n\n" +printf "BEGIN\t\t\t`date`\n" +printf "NSPR_TEST_LOGFILE\t${LOGFILE}\n\n" +printf "Test\t\t\tResult\n\n" +if [ $OS_PLATFORM = "Windows_95" ] || [ $OS_PLATFORM = "Windows_98" ] || [ $OS_PLATFORM = "Windows_NT" ] || [ $OS_PLATFORM = "OS/2" ] ; then + for prog in $TESTS + do + printf "$prog" + printf "\nBEGIN TEST: $prog\n\n" >> ${LOGFILE} 2>&1 + ./$prog >> ${LOGFILE} 2>&1 + if [ 0 = $? ] ; then + printf "\t\t\tPassed\n"; + else + printf "\t\t\tFAILED\n"; + rval=1 + fi; + printf "\nEND TEST: $prog\n\n" >> ${LOGFILE} 2>&1 + done +else + for prog in $TESTS + do + printf "$prog" + printf "\nBEGIN TEST: $prog\n\n" >> ${LOGFILE} 2>&1 + export test_rval + ./$prog >> ${LOGFILE} 2>&1 & + test_pid=$! + sleep_pid=0 + if test -n "$TEST_TIMEOUT" && test "$TEST_TIMEOUT" -gt 0 + then + (sleep $TEST_TIMEOUT; kill $test_pid >/dev/null 2>&1 ) & + sleep_pid=$! + fi + wait $test_pid + test_rval=$? + [ $sleep_pid -eq 0 ] || kill $sleep_pid >/dev/null 2>&1 + if [ 0 = $test_rval ] ; then + printf "\t\t\tPassed\n"; + else + printf "\t\t\tFAILED\n"; + rval=1 + fi; + printf "\nEND TEST: $prog\n\n" >> ${LOGFILE} 2>&1 + done +fi; + +printf "END\t\t\t`date`\n" +exit $rval + + + + + + + + + + + + + + + + + diff --git a/nsprpub/pr/tests/runy2ktests.ksh b/nsprpub/pr/tests/runy2ktests.ksh new file mode 100644 index 00000000000..e7a325019dc --- /dev/null +++ b/nsprpub/pr/tests/runy2ktests.ksh @@ -0,0 +1,269 @@ +#!/bin/ksh +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# runy2ktests.ksh +# Set system clock to Y2K dates of interest and run the Y2K tests. +# Needs root/administrator privilege +# +# WARNING: Because this script needs to be run with root/administrator +# privilege, thorough understanding of the script and extreme +# caution are urged. +# + +# +# SECTION I +# Define variables +# + +SYSTEM_INFO=`uname -a` +OS_ARCH=`uname -s` +if [ $OS_ARCH = "Windows_NT" ] || [ $OS_ARCH = "Windows_95" ] +then + NULL_DEVICE=nul +else + NULL_DEVICE=/dev/null +fi + +# +# Test dates for NSPR Y2K tests +# +Y2KDATES=" 123123591998.55 + 090923591999.55 + 123123591999.55 + 022823592000.55 + 022923592000.55 + 123123592000.55" + +Y2KDATES_AIX=" 12312359.5598 + 09092359.5599 + 12312359.5599 + 02282359.5500 + 02292359.5500 + 12312359.5500" + +Y2KDATES_HPUX=" 123123591998 + 090923591999 + 123123591999 + 022823592000 + 022923592000 + 123123592000" + +Y2KDATES_MKS=" 1231235998.55 + 0909235999.55 + 1231235999.55 + 0228235900.55 + 0229235900.55 + 1231235900.55" + +# +# NSPR Y2K tests +# +Y2KTESTS=" +y2k \n +y2ktmo \n +y2k \n +../runtests.ksh" + +Y2KTESTS_HPUX=" +y2k \n +y2ktmo -l 60\n +y2k \n +../runtests.ksh" + +# +# SECTION II +# Define functions +# + +save_date() +{ + case $OS_ARCH in + AIX) + SAVED_DATE=`date "+%m%d%H%M.%S%y"` + ;; + HP-UX) + SAVED_DATE=`date "+%m%d%H%M%Y"` + ;; + Windows_NT) + SAVED_DATE=`date "+%m%d%H%M%y.%S"` + ;; + Windows_95) + SAVED_DATE=`date "+%m%d%H%M%y.%S"` + ;; + *) + SAVED_DATE=`date "+%m%d%H%M%Y.%S"` + ;; + esac +} + +set_date() +{ + case $OS_ARCH in + Windows_NT) +# +# The date command in MKS Toolkit releases 5.1 and 5.2 +# uses the current DST status for the date we want to +# set the system clock to. However, the DST status for +# that date may be different from the current DST status. +# We can work around this problem by invoking the date +# command with the same date twice. +# + date "$1" > $NULL_DEVICE + date "$1" > $NULL_DEVICE + ;; + *) + date "$1" > $NULL_DEVICE + ;; + esac +} + +restore_date() +{ + set_date "$SAVED_DATE" +} + +savedate() +{ + case $OS_ARCH in + AIX) + SAVED_DATE=`date "+%m%d%H%M.%S%y"` + ;; + HP-UX) + SAVED_DATE=`date "+%m%d%H%M%Y"` + ;; + Windows_NT) + SAVED_DATE=`date "+%m%d%H%M%y.%S"` + ;; + Windows_95) + SAVED_DATE=`date "+%m%d%H%M%y.%S"` + ;; + *) + SAVED_DATE=`date "+%m%d%H%M%Y.%S"` + ;; + esac +} + +set_y2k_test_parameters() +{ +# +# set dates +# + case $OS_ARCH in + AIX) + DATES=$Y2KDATES_AIX + ;; + HP-UX) + DATES=$Y2KDATES_HPUX + ;; + Windows_NT) + DATES=$Y2KDATES_MKS + ;; + Windows_95) + DATES=$Y2KDATES_MKS + ;; + *) + DATES=$Y2KDATES + ;; + esac + +# +# set tests +# + case $OS_ARCH in + HP-UX) + TESTS=$Y2KTESTS_HPUX + ;; + *) + TESTS=$Y2KTESTS + ;; + esac +} + +# +# runtests: +# - runs each test in $TESTS after setting the +# system clock to each date in $DATES +# + +runtests() +{ +for newdate in ${DATES} +do + set_date $newdate + echo $newdate + echo "BEGIN\t\t\t`date`" + echo "Date\t\t\t\t\tTest\t\t\tResult" + echo $TESTS | while read prog + do + echo "`date`\t\t\c" + echo "$prog\c" + ./$prog >> ${LOGFILE} 2>&1 + if [ 0 = $? ] ; then + echo "\t\t\tPassed"; + else + echo "\t\t\tFAILED"; + fi; + done + echo "END\t\t\t`date`\n" +done + +} + +# +# SECTION III +# Run tests +# + +LOGFILE=${NSPR_TEST_LOGFILE:-$NULL_DEVICE} +OBJDIR=`basename $PWD` +echo "\nNSPR Year 2000 Test Results - $OBJDIR\n" +echo "SYSTEM:\t\t\t${SYSTEM_INFO}" +echo "NSPR_TEST_LOGFILE:\t${LOGFILE}\n" + + +save_date + +# +# Run NSPR Y2k and standard tests +# + +set_y2k_test_parameters +runtests + +restore_date diff --git a/nsprpub/pr/tests/rwlocktest.c b/nsprpub/pr/tests/rwlocktest.c new file mode 100644 index 00000000000..b7c4f1e879d --- /dev/null +++ b/nsprpub/pr/tests/rwlocktest.c @@ -0,0 +1,241 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* + * + * RWLock tests + * + * Several threads are created to access and modify data arrays using + * PRRWLocks for synchronization. Two data arrays, array_A and array_B, are + * initialized with random data and a third array, array_C, is initialized + * with the sum of the first 2 arrays. + * + * Each one of the threads acquires a read lock to verify that the sum of + * the arrays A and B is equal to array C, and acquires a write lock to + * consistently update arrays A and B so that their is equal to array C. + * + */ + +#include "nspr.h" +#include "plgetopt.h" +#include "prrwlock.h" + +static int _debug_on; +static void rwtest(void *args); +static PRInt32 *array_A,*array_B,*array_C; +static void update_array(void); +static void check_array(void); + +typedef struct thread_args { + PRRWLock *rwlock; + PRInt32 loop_cnt; +} thread_args; + +PRFileDesc *output; +PRFileDesc *errhandle; + +#define DEFAULT_THREAD_CNT 4 +#define DEFAULT_LOOP_CNT 100 +#define TEST_ARRAY_SIZE 100 + +PRIntn main(PRIntn argc, char **argv) +{ + PRInt32 cnt; + PRStatus rc; + PRInt32 i; + + PRInt32 thread_cnt = DEFAULT_THREAD_CNT; + PRInt32 loop_cnt = DEFAULT_LOOP_CNT; + PRThread **threads; + thread_args *params; + PRRWLock *rwlock1; + + 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': /* loop count */ + loop_cnt = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_SetConcurrency(4); + + output = PR_GetSpecialFD(PR_StandardOutput); + errhandle = PR_GetSpecialFD(PR_StandardError); + + rwlock1 = PR_NewRWLock(0,"Lock 1"); + if (rwlock1 == NULL) { + PR_fprintf(errhandle, "PR_NewRWLock failed - error %d\n", + PR_GetError()); + return 1; + } + + threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt); + params = (thread_args *) PR_CALLOC(sizeof(thread_args) * thread_cnt); + + /* + * allocate and initialize data arrays + */ + array_A =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); + array_B =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); + array_C =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); + cnt = 0; + for (i=0; i < TEST_ARRAY_SIZE;i++) { + array_A[i] = cnt++; + array_B[i] = cnt++; + array_C[i] = array_A[i] + array_B[i]; + } + + if (_debug_on) + PR_fprintf(output,"%s: thread_cnt = %d loop_cnt = %d\n", argv[0], + thread_cnt, loop_cnt); + for(cnt = 0; cnt < thread_cnt; cnt++) { + PRThreadScope scope; + + params[cnt].rwlock = rwlock1; + params[cnt].loop_cnt = loop_cnt; + + /* + * create LOCAL and GLOBAL threads alternately + */ + if (cnt & 1) + scope = PR_LOCAL_THREAD; + else + scope = PR_GLOBAL_THREAD; + + threads[cnt] = PR_CreateThread(PR_USER_THREAD, + rwtest, ¶ms[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); + + } + + PR_DELETE(threads); + PR_DELETE(params); + + PR_DELETE(array_A); + PR_DELETE(array_B); + PR_DELETE(array_C); + + PR_DestroyRWLock(rwlock1); + + + printf("PASS\n"); + return 0; +} + +static void rwtest(void *args) +{ + PRInt32 index; + thread_args *arg = (thread_args *) args; + + + for (index = 0; index < arg->loop_cnt; index++) { + + /* + * verify sum, update arrays and verify sum again + */ + + PR_RWLock_Rlock(arg->rwlock); + check_array(); + PR_RWLock_Unlock(arg->rwlock); + + PR_RWLock_Wlock(arg->rwlock); + update_array(); + PR_RWLock_Unlock(arg->rwlock); + + PR_RWLock_Rlock(arg->rwlock); + check_array(); + PR_RWLock_Unlock(arg->rwlock); + } + if (_debug_on) + PR_fprintf(output, + "Thread[0x%x] lock = 0x%x exiting\n", + PR_GetCurrentThread(), arg->rwlock); + +} + +static void check_array(void) +{ +PRInt32 i; + + for (i=0; i < TEST_ARRAY_SIZE;i++) + if (array_C[i] != (array_A[i] + array_B[i])) { + PR_fprintf(output, "Error - data check failed\n"); + PR_ProcessExit(1); + } +} + +static void update_array(void) +{ +PRInt32 i; + + for (i=0; i < TEST_ARRAY_SIZE;i++) { + array_A[i] += i; + array_B[i] -= i; + } +} diff --git a/nsprpub/pr/tests/sel_spd.c b/nsprpub/pr/tests/sel_spd.c new file mode 100644 index 00000000000..c3b79652872 --- /dev/null +++ b/nsprpub/pr/tests/sel_spd.c @@ -0,0 +1,567 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Test the speed of select within NSPR + * + */ + +#include "nspr.h" +#include "prpriv.h" + +#include +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +int fprintf(FILE *stream, const char *fmt, ...) +{ +PR_LogPrint(fmt); +return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define PORT_BASE 19000 + +typedef struct timer_slot_t { + unsigned long d_connect; + unsigned long d_cl_data; + unsigned long d_sv_data; + unsigned long d_close; + unsigned long d_total; + 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 + * space and buffer allocation space. It is easy to get into a fragmented + * 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; +#else +static long _server_data = (128*1024); +static long _threads_max = 10, _threads = 10; +#endif + +static int verbose=0; +static PRMonitor *exit_cv; +static long _thread_exit_count; +static timer_slot_t *timer_data; +static PRThreadScope scope1, scope2; + +void tally_results(int); + +/* return the diff in microseconds */ +unsigned long _delta(PRIntervalTime *start, PRIntervalTime *stop) +{ + /* + * Will C do the right thing with unsigned arithemtic? + */ + return PR_IntervalToMicroseconds(*stop - *start); +} + +int _readn(PRFileDesc *sock, char *buf, int len) +{ + int rem; + int bytes; + + for (rem=len; rem; rem -= bytes) { + bytes = PR_Recv(sock, buf+len-rem, rem, 0, PR_INTERVAL_NO_TIMEOUT); + if (bytes <= 0) + return -1; + } + return len; +} + +void +_thread_exit(int id) +{ + PR_EnterMonitor(exit_cv); +#ifdef DEBUG + fprintf(stdout, "Thread %d EXIT\n", id); +#endif + + _thread_exit_count--; + if (_thread_exit_count == 0) { +#ifdef DEBUG + fprintf(stdout, "Thread %d EXIT triggered notify\n", id); +#endif + PR_Notify(exit_cv); + } + PR_ExitMonitor(exit_cv); +} + +void +_server_thread(void *arg_id) +{ + void _client_thread(void *); + PRThread *thread; + int *id = (int *)arg_id; + PRFileDesc *sock; + PRSocketOptionData sockopt; + PRNetAddr sa; + PRFileDesc * newsock; + char *data_buffer = NULL; + int data_buffer_size; + int index; + PRIntervalTime start, + connect_done, + read_done, + write_done, + close_done; + + +#ifdef DEBUG + fprintf(stdout, "server thread %d alive\n", *id); +#endif + + data_buffer_size = (_client_data>_server_data?_client_data:_server_data); + + if ( (data_buffer = (char *)PR_Malloc(data_buffer_size * sizeof(char))) == NULL ) { + fprintf(stderr, "Error creating buffer in server thread %d\n", *id); + goto done; + } + + + if ( (sock = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Error creating socket in server thread %d\n", *id); + goto done; + } + + sockopt.option = PR_SockOpt_Reuseaddr; + sockopt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(sock, &sockopt) == PR_FAILURE) { + fprintf(stderr, "Error setting socket option in server thread %d\n", *id); + goto done; + } + + memset(&sa, 0 , sizeof(sa)); + sa.inet.family = PR_AF_INET; + sa.inet.port = PR_htons(PORT_BASE + *id); + sa.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(sock, &sa) < 0) { + fprintf(stderr, "Error binding socket in server thread %d errno = %d\n", *id, errno); + goto done; + } + + if ( PR_Listen(sock, 32) < 0 ) { + fprintf(stderr, "Error listening to socket in server thread %d\n", *id); + goto done; + } + + /* Tell the client to start */ + if ( (thread = PR_CreateThread(PR_USER_THREAD, + _client_thread, + id, + PR_PRIORITY_NORMAL, + scope2, + PR_UNJOINABLE_THREAD, + 0)) == NULL) + fprintf(stderr, "Error creating client thread %d\n", *id); + + for (index = 0; index< _iterations; index++) { + +#ifdef DEBUG + fprintf(stdout, "server thread %d loop %d\n", *id, index); +#endif + + start = PR_IntervalNow(); + + if ( (newsock = PR_Accept(sock, &sa, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr, "Error accepting connection %d in server thread %d\n", + index, *id); + goto done; + } +#ifdef DEBUG + fprintf(stdout, "server thread %d got connection %d\n", *id, newsock); +#endif + + + connect_done = PR_IntervalNow(); + + if ( _readn(newsock, data_buffer, _client_data) < _client_data) { + fprintf(stderr, "Error reading client data for iteration %d in server thread %d\n", index, *id ); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "server thread %d read %d bytes\n", *id, _client_data); +#endif + read_done = PR_IntervalNow(); + + if ( PR_Send(newsock, data_buffer, _server_data, 0, + PR_INTERVAL_NO_TIMEOUT) < _server_data) { + fprintf(stderr, "Error sending client data for iteration %d in server thread %d\n", index, *id ); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "server thread %d write %d bytes\n", *id, _server_data); +#endif + + write_done = PR_IntervalNow(); + + PR_Close(newsock); + + close_done = PR_IntervalNow(); + + timer_data[2*(*id)].d_connect += _delta(&start, &connect_done); + timer_data[2*(*id)].d_cl_data += _delta(&connect_done, &read_done); + timer_data[2*(*id)].d_sv_data += _delta(&read_done, &write_done); + timer_data[2*(*id)].d_close += _delta(&write_done, &close_done); + timer_data[2*(*id)].d_total += _delta(&start, &close_done); + timer_data[2*(*id)].requests++; + + +#ifdef DEBUG + fprintf(stdout, "server: %d %d %d %d %d\n", + _delta(&start, &connect_done), _delta(&connect_done, &read_done), + _delta(&read_done, &write_done), _delta(&write_done, &close_done), + _delta(&start, &close_done)); +#endif + } + +done: + if (data_buffer != NULL) PR_Free (data_buffer); + if (sock) PR_Close(sock); + _thread_exit(*id); + return; +} + +void +_client_thread(void *arg_id) +{ + int *id = (int *)arg_id; + int index; + PRNetAddr sa; + PRFileDesc *sock_h; + char *data_buffer = NULL; + int data_buffer_size; + int bytes; + PRIntervalTime start, + connect_done, + read_done, + write_done, + close_done; + PRStatus rv; + +#ifdef DEBUG + fprintf(stdout, "client thread %d alive\n", *id); +#endif + + data_buffer_size = (_client_data>_server_data?_client_data:_server_data); + + if ( (data_buffer = (char *)PR_Malloc(data_buffer_size * sizeof(char))) == NULL) { + fprintf(stderr, "Error creating buffer in server thread %d\n", *id); + goto done; + } + + memset(&sa, 0 , sizeof(sa)); + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, PORT_BASE + *id, &sa); + PR_ASSERT(PR_SUCCESS == rv); + + for (index = 0; index< _iterations; index++) { + +#ifdef DEBUG + fprintf(stdout, "client thread %d loop %d\n", *id, index); +#endif + + start = PR_IntervalNow(); + if ( (sock_h = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Error creating socket %d in client thread %d\n", + index, *id); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "client thread %d socket created %d\n", *id, sock_h); +#endif + + if ( PR_Connect(sock_h, &sa, + PR_INTERVAL_NO_TIMEOUT) < 0) { + fprintf(stderr, "Error accepting connection %d in client thread %d\n", + index, *id); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "client thread %d socket connected %d\n", *id, sock_h); +#endif + + connect_done = PR_IntervalNow(); + if ( PR_Send(sock_h, data_buffer, _client_data, 0, + PR_INTERVAL_NO_TIMEOUT) < _client_data) { + fprintf(stderr, "Error sending client data for iteration %d in client thread %d\n", index, *id ); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "client thread %d socket wrote %d\n", *id, _client_data); +#endif + + write_done = PR_IntervalNow(); + if ( (bytes = _readn(sock_h, data_buffer, _server_data)) < _server_data) { + fprintf(stderr, "Error reading server data for iteration %d in client thread %d (read %d bytes)\n", index, *id, bytes ); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "client thread %d socket read %d\n", *id, _server_data); +#endif + + read_done = PR_IntervalNow(); + PR_Close(sock_h); + close_done = PR_IntervalNow(); + + timer_data[2*(*id)+1].d_connect += _delta(&start, &connect_done); + timer_data[2*(*id)+1].d_cl_data += _delta(&connect_done, &write_done); + timer_data[2*(*id)+1].d_sv_data += _delta(&write_done, &read_done); + timer_data[2*(*id)+1].d_close += _delta(&read_done, &close_done); + timer_data[2*(*id)+1].d_total += _delta(&start, &close_done); + timer_data[2*(*id)+1].requests++; + } +done: + if (data_buffer != NULL) PR_Free (data_buffer); + _thread_exit(*id); + + return; +} + +static +void do_work(void) +{ + int index; + + _thread_exit_count = _threads * 2; + for (index=0; index<_threads; index++) { + PRThread *thread; + int *id = (int *)PR_Malloc(sizeof(int)); + + *id = index; + + if ( (thread = PR_CreateThread(PR_USER_THREAD, + _server_thread, + id, + PR_PRIORITY_NORMAL, + scope1, + PR_UNJOINABLE_THREAD, + 0)) == NULL) + fprintf(stderr, "Error creating server thread %d\n", index); + } + + PR_EnterMonitor(exit_cv); + while (_thread_exit_count > 0) + PR_Wait(exit_cv, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(exit_cv); + + fprintf(stdout, "TEST COMPLETE!\n"); + + tally_results(verbose); + +} + +static void do_workUU(void) +{ + scope1 = PR_LOCAL_THREAD; + scope2 = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workUK(void) +{ + scope1 = PR_LOCAL_THREAD; + scope2 = PR_GLOBAL_THREAD; + do_work(); +} + +static void do_workKU(void) +{ + scope1 = PR_GLOBAL_THREAD; + scope2 = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workKK(void) +{ + scope1 = PR_GLOBAL_THREAD; + scope2 = PR_GLOBAL_THREAD; + do_work(); +} + + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + printf("%40s: %6.2f usec\n", msg, d / _iterations); +} + + +int main(int argc, char **argv) +{ +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + int opt; + PR_IMPORT_DATA(char *) optarg; +#endif + +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + while ( (opt = getopt(argc, argv, "c:s:i:t:v")) != EOF) { + switch(opt) { + case 'i': + _iterations = atoi(optarg); + break; + case 't': + _threads_max = _threads = atoi(optarg); + break; + case 'c': + _client_data = atoi(optarg); + break; + case 's': + _server_data = atoi(optarg); + break; + case 'v': + verbose = 1; + break; + default: + break; + } + } +#endif + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("sel_spd.log"); +#endif + + fprintf(stdout, "Running test for %d iterations with %d simultaneous threads.\n", + _iterations, _threads); + fprintf(stdout, "\tWill send %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + + if ( (exit_cv = PR_NewMonitor()) == NULL) + fprintf(stderr, "Error creating monitor for exit cv\n"); + if ( (timer_data = (timer_slot_t *)PR_Malloc(2*_threads * sizeof(timer_slot_t))) == NULL) + fprintf(stderr, "error allocating thread time results array\n"); + memset(timer_data, 0 , 2*_threads*sizeof(timer_slot_t)); + + Measure(do_workUU, "select loop user/user"); + Measure(do_workUK, "select loop user/kernel"); + Measure(do_workKU, "select loop kernel/user"); + Measure(do_workKK, "select loop kernel/kernel"); + + + return 0; +} + +void +tally_results(int verbose) +{ + int index; + unsigned long tot_connect = 0; + unsigned long tot_cl_data = 0; + unsigned long tot_sv_data = 0; + unsigned long tot_close = 0; + unsigned long tot_all = 0; + unsigned long tot_requests = 0; + + fprintf(stdout, "Server results:\n\n"); + for (index=0; index<_threads_max*2; index+=2) { + + if (verbose) + fprintf(stdout, "server thread %u\t%u\t%u\t%u\t%u\t%u\t%u\n", + index, timer_data[index].requests, timer_data[index].d_connect, + timer_data[index].d_cl_data, timer_data[index].d_sv_data, + timer_data[index].d_close, timer_data[index].d_total); + + tot_connect += timer_data[index].d_connect / _threads; + tot_cl_data += timer_data[index].d_cl_data / _threads; + tot_sv_data += timer_data[index].d_sv_data / _threads; + tot_close += timer_data[index].d_close / _threads; + tot_all += timer_data[index].d_total / _threads; + tot_requests += timer_data[index].requests / _threads; + } + fprintf(stdout, "----------\n"); + fprintf(stdout, "server per thread totals %u\t%u\t%u\t%u\t%u\n", + tot_requests, tot_connect, tot_cl_data, tot_sv_data, tot_close); + fprintf(stdout, "server per thread elapsed time %u\n", tot_all); + fprintf(stdout, "----------\n"); + + tot_connect = tot_cl_data = tot_sv_data = tot_close = tot_all = tot_requests = 0; + fprintf(stdout, "Client results:\n\n"); + for (index=1; index<_threads_max*2; index+=2) { + + if (verbose) + fprintf(stdout, "client thread %u\t%u\t%u\t%u\t%u\t%u\t%u\n", + index, timer_data[index].requests, timer_data[index].d_connect, + timer_data[index].d_cl_data, timer_data[index].d_sv_data, + timer_data[index].d_close, timer_data[index].d_total); + + tot_connect += timer_data[index].d_connect / _threads; + tot_cl_data += timer_data[index].d_cl_data / _threads; + tot_sv_data += timer_data[index].d_sv_data / _threads; + tot_close += timer_data[index].d_close / _threads; + tot_all += timer_data[index].d_total / _threads; + tot_requests += timer_data[index].requests / _threads; + } + fprintf(stdout, "----------\n"); + fprintf(stdout, "client per thread totals %u\t%u\t%u\t%u\t%u\n", + tot_requests, tot_connect, tot_cl_data, tot_sv_data, tot_close); + fprintf(stdout, "client per thread elapsed time %u\n", tot_all); +} + diff --git a/nsprpub/pr/tests/selct_er.c b/nsprpub/pr/tests/selct_er.c new file mode 100755 index 00000000000..e658813f6e7 --- /dev/null +++ b/nsprpub/pr/tests/selct_er.c @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1997 - Netscape Communications Corporation +** +** Name: prselect_err.c +** +** Description: tests PR_Select with sockets Error condition functions. +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +#ifdef XP_BEOS +#include +int main() +{ + printf( "This test is not ported to the BeOS\n" ); + return 0; +} +#else + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "primpl.h" +#include "pprio.h" +#include "prnetdb.h" + +#include +#include +#include + + +PRIntn failed_already=0; +PRIntn debug_mode; + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *badFD; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + PR_fd_set readFdSet; + char buf[128]; + PRInt32 retVal; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Select with sockets. Error\n"); + printf("reporting operations are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the fd set */ + PR_FD_ZERO(&readFdSet); + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + + /* Testing bad fd */ + if (debug_mode) printf("PR_Select should detect a bad file descriptor\n"); + if ((badFD = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a TCP socket\n"); + failed_already=1; + goto exit_now; + } + + PR_FD_SET(badFD, &readFdSet); + /* + * Make the fd invalid + */ +#if defined(XP_UNIX) + close(PR_FileDesc2NativeHandle(badFD)); +#elif defined(XP_OS2) + soclose(PR_FileDesc2NativeHandle(badFD)); +#elif defined(WIN32) || defined(WIN16) + closesocket(PR_FileDesc2NativeHandle(badFD)); +#elif defined(XP_MAC) + _PR_MD_CLOSE_SOCKET(PR_FileDesc2NativeHandle(badFD)); +#else +#error "Unknown architecture" +#endif + + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_INTERVAL_NO_TIMEOUT); + if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) { + fprintf(stderr, "Failed to detect the bad fd: " + "PR_Select returns %d\n", retVal); + if (retVal == -1) { + fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), + PR_GetOSError()); + failed_already=1; + } + goto exit_now; + } + if (debug_mode) printf("PR_Select detected a bad fd. Test passed.\n\n"); + PR_FD_CLR(badFD, &readFdSet); + + PR_Cleanup(); + goto exit_now; +exit_now: + if(failed_already) + return 1; + else + return 0; + +} + +#endif /* XP_BEOS */ diff --git a/nsprpub/pr/tests/selct_nm.c b/nsprpub/pr/tests/selct_nm.c new file mode 100644 index 00000000000..56a80a76fb9 --- /dev/null +++ b/nsprpub/pr/tests/selct_nm.c @@ -0,0 +1,320 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1997 - Netscape Communications Corporation +** +** Name: prselect_norm.c +** +** Description: tests PR_Select with sockets - Normal operations. +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prerror.h" +#include "prnetdb.h" + +#ifdef XP_MAC +#include "probslet.h" +#else +#include "obsolete/probslet.h" +#endif + +#include +#include +#include + +PRIntn failed_already=0; +PRIntn debug_mode; + +static void +clientThreadFunc(void *arg) +{ + PRUintn port = (PRUintn) arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[128]; + int i; + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons((PRUint16)port); + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.port); + + for (i = 0; i < 5; i++) { + sock = PR_NewTCPSocket(); + PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + PR_Write(sock, buf, sizeof(buf)); + PR_Close(sock); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds; + PRIntn nfds; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + PR_fd_set readFdSet; + char buf[128]; + PRThread *clientThread; + PRInt32 retVal; + PRIntn i, j; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Select with sockets. \n"); + printf(" Normal operation are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); +failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort1, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + failed_already=1; + goto exit_now; + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort2, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + failed_already=1; + goto exit_now; + } + + if (debug_mode) { + printf("Two client threads are created. Each of them will\n"); + printf("send data to one of the two ports the server is listening on.\n"); + printf("The data they send is the port number. Each of them send\n"); + printf("the data five times, so you should see ten lines below,\n"); + printf("interleaved in an arbitrary order.\n"); + } + /* set up the fd array */ + fds = fds0; + other_fds = fds1; + fds[0] = listenSock1; + fds[1] = listenSock2; + nfds = 2; + /* Set up the fd set */ + PR_FD_ZERO(&readFdSet); + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + /* 20 events total */ + i = 0; + while (i < 20) { + PRFileDesc **tmp; + int nextIndex; + int nEvents = 0; + + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(retVal != 0); /* no timeout */ + if (retVal == -1) { + fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + failed_already=1; + goto exit_now; + } + + nextIndex = 2; + /* the two listening sockets */ + for (j = 0; j < 2; j++) { + other_fds[j] = fds[j]; + if (PR_FD_ISSET(fds[j], &readFdSet)) { + PRFileDesc *sock; + + nEvents++; + sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + fprintf(stderr, "PR_Accept() failed\n"); + failed_already=1; + goto exit_now; + } + other_fds[nextIndex] = sock; + PR_FD_SET(sock, &readFdSet); + nextIndex++; + } + PR_FD_SET(fds[j], &readFdSet); + } + + for (j = 2; j < nfds; j++) { + if (PR_FD_ISSET(fds[j], &readFdSet)) { + PRInt32 nBytes; + + PR_FD_CLR(fds[j], &readFdSet); + nEvents++; + nBytes = PR_Read(fds[j], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read() failed\n"); + failed_already=1; + goto exit_now; + } + /* Just to be safe */ + buf[127] = '\0'; + PR_Close(fds[j]); + if (debug_mode) printf("The server received \"%s\" from a client\n", buf); + } else { + PR_FD_SET(fds[j], &readFdSet); + other_fds[nextIndex] = fds[j]; + nextIndex++; + } + } + + PR_ASSERT(retVal == nEvents); + /* swap */ + tmp = fds; + fds = other_fds; + other_fds = tmp; + nfds = nextIndex; + i += nEvents; + } + + if (debug_mode) printf("Test passed\n"); + + PR_Cleanup(); + goto exit_now; +exit_now: + if(failed_already) + return 1; + else + return 0; +} diff --git a/nsprpub/pr/tests/selct_to.c b/nsprpub/pr/tests/selct_to.c new file mode 100644 index 00000000000..b5600fa9fe6 --- /dev/null +++ b/nsprpub/pr/tests/selct_to.c @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** 1997 - Netscape Communications Corporation +** +** Name: prselect_to.c +** +** Description: tests PR_Select with sockets. Time out functions +** +** 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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" + +#ifdef XP_MAC +#include "probslet.h" +#else +#include "obsolete/probslet.h" +#endif + +#include "prerror.h" + +#include +#include +#include + +PRIntn failed_already=0; +PRIntn debug_mode; + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + PR_fd_set readFdSet; + char buf[128]; + PRInt32 retVal; + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Select with sockets. Timeout \n"); + printf("operations are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the fd set */ + PR_FD_ZERO(&readFdSet); + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + /* Testing timeout */ + if (debug_mode) printf("PR_Select should time out in 5 seconds\n"); + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_SecondsToInterval(5)); + if (retVal != 0) { + PR_snprintf(buf, sizeof(buf), + "PR_Select should time out and return 0, but it returns %ld\n", + retVal); + fprintf(stderr, "%s", buf); + if (retVal == -1) { + fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), + PR_GetOSError()); + failed_already=1; + } + goto exit_now; + } + if (debug_mode) printf("PR_Select timed out. Test passed.\n\n"); + + PR_Cleanup(); + +exit_now: + if(failed_already) + return 1; + else + return 0; +} diff --git a/nsprpub/pr/tests/select2.c b/nsprpub/pr/tests/select2.c new file mode 100644 index 00000000000..0651c450534 --- /dev/null +++ b/nsprpub/pr/tests/select2.c @@ -0,0 +1,354 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: select2.c +** +** Description: Measure PR_Select and Empty_Select performance. +** +** Modification History: +** 20-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. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" +#include "prttools.h" +#include "primpl.h" + +#include +#include +#include +#if defined(OS2) +#include +#endif + +#define PORT 8000 +#define DEFAULT_COUNT 10 +PRInt32 count; + + +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static void Test_Result (int result) +{ + switch (result) + { + case PASS: + printf ("PASS\n"); + break; + case FAIL: + printf ("FAIL\n"); + break; + default: + printf ("NOSTATUS\n"); + break; + } +} + +static void EmptyPRSelect(void) +{ + PRInt32 index = count; + PRInt32 rv; + + for (; index--;) + rv = PR_Select(0, NULL, NULL, NULL, PR_INTERVAL_NO_WAIT); +} + +static void EmptyNativeSelect(void) +{ + PRInt32 rv; + PRInt32 index = count; + struct timeval timeout; + + timeout.tv_sec = timeout.tv_usec = 0; + for (; index--;) + rv = select(0, NULL, NULL, NULL, &timeout); +} + +static void PRSelectTest(void) +{ + PRFileDesc *listenSocket; + PRNetAddr serverAddr; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + return; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address\n"); + PR_Close(listenSocket); + return; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + PR_Close(listenSocket); + return; + } + if (debug_mode) printf("Listening on port %d\n", PORT); + + { + PRFileDesc *newSock; + PRNetAddr rAddr; + PRInt32 loops = 0; + PR_fd_set rdset; + PRInt32 rv; + PRInt32 bytesRead; + char buf[11]; + + loops++; + + if (debug_mode) printf("Going into accept\n"); + + newSock = PR_Accept(listenSocket, + &rAddr, + PR_INTERVAL_NO_TIMEOUT); + + if (newSock) { + if (debug_mode) printf("Got connection!\n"); + } else { + if (debug_mode) printf("PR_Accept failed: error code %d\n", PR_GetError()); + else Test_Result (FAIL); + } + + PR_FD_ZERO(&rdset); + PR_FD_SET(newSock, &rdset); + + if (debug_mode) printf("Going into select \n"); + + rv = PR_Select(0, &rdset, 0, 0, PR_INTERVAL_NO_TIMEOUT); + + if (debug_mode) printf("return from select is %d\n", rv); + + if (PR_FD_ISSET(newSock, &rdset)) { + if (debug_mode) printf("I can't believe it- the socket is ready okay!\n"); + } else { + if (debug_mode) printf("Damn; the select test failed...\n"); + else Test_Result (FAIL); + } + + strcpy(buf, "XXXXXXXXXX"); + bytesRead = PR_Recv(newSock, buf, 10, 0, PR_INTERVAL_NO_TIMEOUT); + buf[10] = '\0'; + + if (debug_mode) printf("Recv completed with %d bytes, %s\n", bytesRead, buf); + + PR_Close(newSock); + } + +} + +#if defined(XP_UNIX) + +static void NativeSelectTest(void) +{ + PRFileDesc *listenSocket; + PRNetAddr serverAddr; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + return; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address\n"); + PR_Close(listenSocket); + return; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + PR_Close(listenSocket); + return; + } + if (debug_mode) printf("Listening on port %d\n", PORT); + + { + PRIntn osfd; + char buf[11]; + fd_set rdset; + PRNetAddr rAddr; + PRFileDesc *newSock; + struct timeval timeout; + PRInt32 bytesRead, rv, loops = 0; + + loops++; + + if (debug_mode) printf("Going into accept\n"); + + newSock = PR_Accept(listenSocket, &rAddr, PR_INTERVAL_NO_TIMEOUT); + + if (newSock) { + if (debug_mode) printf("Got connection!\n"); + } else { + if (debug_mode) printf("PR_Accept failed: error code %d\n", PR_GetError()); + else Test_Result (FAIL); + } + + osfd = PR_FileDesc2NativeHandle(newSock); + FD_ZERO(&rdset); + FD_SET(osfd, &rdset); + + if (debug_mode) printf("Going into select \n"); + + + timeout.tv_sec = 2; timeout.tv_usec = 0; + rv = select(osfd + 1, &rdset, NULL, NULL, &timeout); + + if (debug_mode) printf("return from select is %d\n", rv); + + if (FD_ISSET(osfd, &rdset)) { + if (debug_mode) + printf("I can't believe it- the socket is ready okay!\n"); + } else { + if (debug_mode) printf("Damn; the select test failed...\n"); + else Test_Result (FAIL); + } + + strcpy(buf, "XXXXXXXXXX"); + bytesRead = PR_Recv(newSock, buf, 10, 0, PR_INTERVAL_NO_TIMEOUT); + buf[10] = '\0'; + + if (debug_mode) printf("Recv completed with %d bytes, %s\n", bytesRead, buf); + + PR_Close(newSock); + } + +} /* NativeSelectTest */ + +#endif /* defined(XP_UNIX) */ + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + PRInt32 tot; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + tot = PR_IntervalToMilliseconds(stop-start); + + if (debug_mode) printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot); +} + +void main(int argc, char **argv) +{ + + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (argc > 2) { + count = atoi(argv[2]); + } else { + count = DEFAULT_COUNT; + } + +#if defined(XP_UNIX) + Measure(NativeSelectTest, "time to call 1 element select()"); +#endif + Measure(EmptyPRSelect, "time to call Empty PR_select()"); + Measure(EmptyNativeSelect, "time to call Empty select()"); + Measure(PRSelectTest, "time to call 1 element PR_select()"); + + if (!debug_mode) Test_Result (NOSTATUS); + PR_Cleanup(); + + +} diff --git a/nsprpub/pr/tests/selintr.c b/nsprpub/pr/tests/selintr.c new file mode 100644 index 00000000000..f47efca4318 --- /dev/null +++ b/nsprpub/pr/tests/selintr.c @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Test whether classic NSPR's select() wrapper properly blocks + * the periodic SIGALRM clocks. On some platforms (such as + * HP-UX and SINIX) an interrupted select() system call is + * restarted with the originally specified timeout, ignoring + * the time that has elapsed. If a select() call is interrupted + * repeatedly, it will never time out. (See Bugzilla bug #39674.) + */ + +#if !defined(XP_UNIX) + +/* + * This test is applicable to Unix only. + */ + +int main() +{ + return 0; +} + +#else /* XP_UNIX */ + +#include "nspr.h" + +#include +#include + +int main() +{ + struct timeval timeout; + int rv; + + PR_SetError(0, 0); /* force NSPR to initialize */ + PR_EnableClockInterrupts(); + + /* 2 seconds timeout */ + timeout.tv_sec = 2; + timeout.tv_usec = 0; + rv = select(1, NULL, NULL, NULL, &timeout); + printf("select returned %d\n", rv); + return 0; +} + +#endif /* XP_UNIX */ diff --git a/nsprpub/pr/tests/sem.c b/nsprpub/pr/tests/sem.c new file mode 100644 index 00000000000..09c9f3cde52 --- /dev/null +++ b/nsprpub/pr/tests/sem.c @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: sem.c +** +** Description: Tests Semaphonre functions. +** +** Modification History: +** 20-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "prpriv.h" + +#include +#include +#include + +PRIntn failed_already=0; +PRIntn debug_mode; + +/* + Since we don't have stdin, stdout everywhere, we will fake + it with our in-memory buffers called stdin and stdout. +*/ + +#define SBSIZE 1024 + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +static char stdinBuf[SBSIZE]; +static char stdoutBuf[SBSIZE]; + +static PRUintn stdinBufIdx = 0; +static PRUintn stdoutBufIdx = 0; +static PRStatus finalResult = PR_SUCCESS; + + +static size_t dread (PRUintn device, char *buf, size_t bufSize) +{ + PRUintn i; + + /* during first read call, initialize the stdinBuf buffer*/ + if (stdinBufIdx == 0) { + for (i=0; i 0); +} + +static void writer(void) +{ + PRUintn i = 0; + size_t nbytes; + + do { + (void) PR_WaitSem(fullBufs); + nbytes = buf[i].nbytes; + if (nbytes > 0) { + nbytes = dwrite(1, buf[i].data, nbytes); + PR_PostSem(emptyBufs); + i = (i + 1) % 2; + } + } while (nbytes > 0); +} + +int main(int argc, char **argv) +{ + PRThread *r; + + PR_STDIO_INIT(); + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + { + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + /* main test */ + +#ifdef XP_MAC + SetupMacPrintfLog("sem.log"); + debug_mode = 1; +#endif + + emptyBufs = PR_NewSem(2); /* two empty buffers */ + + fullBufs = PR_NewSem(0); /* zero full buffers */ + + /* create the reader thread */ + + r = PR_CreateThread(PR_USER_THREAD, + reader, 0, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + + /* Do the writer operation in this thread */ + writer(); + + PR_DestroySem(emptyBufs); + PR_DestroySem(fullBufs); + + if (finalResult == PR_SUCCESS) { + if (debug_mode) printf("sem Test Passed.\n"); + } + else{ + if (debug_mode) printf("sem Test Failed.\n"); + failed_already=1; + } + PR_Cleanup(); + if(failed_already) + return 1; + else + return 0; +} diff --git a/nsprpub/pr/tests/sema.c b/nsprpub/pr/tests/sema.c new file mode 100644 index 00000000000..3dff8a00c71 --- /dev/null +++ b/nsprpub/pr/tests/sema.c @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_NAME2 "/tmp/bar.sem" +#define SEM_MODE 0666 +#define ITERATIONS 1000 + +static PRBool debug_mode = PR_FALSE; +static PRIntn iterations = ITERATIONS; +static PRIntn counter; +static PRSem *sem1, *sem2; + +/* + * Thread 2 waits on semaphore 2 and posts to semaphore 1. + */ +void ThreadFunc(void *arg) +{ + PRIntn i; + + for (i = 0; i < iterations; i++) { + if (PR_WaitSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_WaitSemaphore failed\n"); + exit(1); + } + if (counter == 2*i+1) { + if (debug_mode) printf("thread 2: counter = %d\n", counter); + } else { + fprintf(stderr, "thread 2: counter should be %d but is %d\n", + 2*i+1, counter); + exit(1); + } + counter++; + if (PR_PostSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_PostSemaphore failed\n"); + exit(1); + } + } +} + +static void Help(void) +{ + fprintf(stderr, "sema test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-c loop count (%d)\n", ITERATIONS); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PRThread *thred; + PRIntn i; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop count */ + iterations = atoi(opt->value); + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) { + fprintf(stderr, "warning: removed semaphore %s left over " + "from previous run\n", SEM_NAME1); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_SUCCESS) { + fprintf(stderr, "warning: removed semaphore %s left over " + "from previous run\n", SEM_NAME2); + } + + sem1 = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 1); + if (NULL == sem1) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + sem2 = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 0); + if (NULL == sem2) { + fprintf(stderr, "PR_OpenSemaphore failed\n"); + exit(1); + } + thred = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == thred) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + + /* + * Thread 1 waits on semaphore 1 and posts to semaphore 2. + */ + for (i = 0; i < iterations; i++) { + if (PR_WaitSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_WaitSemaphore failed\n"); + exit(1); + } + if (counter == 2*i) { + if (debug_mode) printf("thread 1: counter = %d\n", counter); + } else { + fprintf(stderr, "thread 1: counter should be %d but is %d\n", + 2*i, counter); + exit(1); + } + counter++; + if (PR_PostSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_PostSemaphore failed\n"); + exit(1); + } + } + + if (PR_JoinThread(thred) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + + if (PR_CloseSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + if (PR_CloseSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + } + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/semaerr.c b/nsprpub/pr/tests/semaerr.c new file mode 100644 index 00000000000..8feb8d81b75 --- /dev/null +++ b/nsprpub/pr/tests/semaerr.c @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define NO_SUCH_SEM_NAME "/tmp/nosuchsem.sem" +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_MODE 0666 + +static PRBool debug_mode = PR_FALSE; + +static void Help(void) +{ + fprintf(stderr, "semaerr test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dh"); + PRSem *sem; + char *child_argv[32]; + char **child_arg; + PRProcess *proc; + PRInt32 exit_code; + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + /* + * Open a nonexistent semaphore without the PR_SEM_CREATE + * flag should fail with PR_FILE_NOT_FOUND_ERROR. + */ + (void) PR_DeleteSemaphore(NO_SUCH_SEM_NAME); + sem = PR_OpenSemaphore(NO_SUCH_SEM_NAME, 0, 0, 0); + if (NULL != sem) { + fprintf(stderr, "Opening nonexistent semaphore %s " + "without the PR_SEM_CREATE flag should fail " + "but succeeded\n", NO_SUCH_SEM_NAME); + exit(1); + } + if (PR_GetError() != PR_FILE_NOT_FOUND_ERROR) { + fprintf(stderr, "Expected error is %d but got (%d, %d)\n", + PR_FILE_NOT_FOUND_ERROR, PR_GetError(), PR_GetOSError()); + exit(1); + } + + /* + * Create a semaphore and let the another process + * try PR_SEM_CREATE and PR_SEM_CREATE|PR_SEM_EXCL. + */ + if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) { + fprintf(stderr, "warning: deleted semaphore %s from previous " + "run of the test\n", SEM_NAME1); + } + sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0); + if (sem == NULL) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + child_arg = child_argv; + *child_arg++ = "semaerr1"; + if (debug_mode) { + *child_arg++ = "-d"; + } + *child_arg = NULL; + proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); + if (proc == NULL) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + if (PR_WaitProcess(proc, &exit_code) == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exit_code != 0) { + fprintf(stderr, "process semaerr1 failed\n"); + exit(1); + } + if (PR_CloseSemaphore(sem) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + exit(1); + } + if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/semaerr1.c b/nsprpub/pr/tests/semaerr1.c new file mode 100644 index 00000000000..eeccdc43be1 --- /dev/null +++ b/nsprpub/pr/tests/semaerr1.c @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_NAME2 "/tmp/bar.sem" +#define SEM_MODE 0666 + +static PRBool debug_mode = PR_FALSE; + +static void Help(void) +{ + fprintf(stderr, "semaerr1 test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dh"); + PRSem *sem; + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + /* + * PR_SEM_CREATE|PR_SEM_EXCL should be able to + * create a nonexistent semaphore. + */ + (void) PR_DeleteSemaphore(SEM_NAME2); + sem = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0); + if (sem == NULL) { + fprintf(stderr, "PR_OpenSemaphore failed\n"); + exit(1); + } + if (PR_CloseSemaphore(sem) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + exit(1); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + exit(1); + } + + /* + * Opening an existing semaphore with PR_SEM_CREATE|PR_SEM_EXCL. + * should fail with PR_FILE_EXISTS_ERROR. + */ + sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0); + if (sem != NULL) { + fprintf(stderr, "PR_OpenSemaphore should fail but succeeded\n"); + exit(1); + } + if (PR_GetError() != PR_FILE_EXISTS_ERROR) { + fprintf(stderr, "Expect %d but got %d\n", PR_FILE_EXISTS_ERROR, + PR_GetError()); + exit(1); + } + + /* + * Try again, with just PR_SEM_CREATE. This should succeed. + */ + sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0); + if (sem == NULL) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + if (PR_CloseSemaphore(sem) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + exit(1); + } + + sem = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0); + if (sem == NULL) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + if (PR_CloseSemaphore(sem) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/semaping.c b/nsprpub/pr/tests/semaping.c new file mode 100644 index 00000000000..7b145fc5fde --- /dev/null +++ b/nsprpub/pr/tests/semaping.c @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define SHM_NAME "/tmp/counter" +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_NAME2 "/tmp/bar.sem" +#define SEM_MODE 0666 +#define SHM_MODE 0666 +#define ITERATIONS 1000 + +static PRBool debug_mode = PR_FALSE; +static PRIntn iterations = ITERATIONS; +static PRSem *sem1, *sem2; + +static void Help(void) +{ + fprintf(stderr, "semaping test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-c loop count (%d)\n", ITERATIONS); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PRProcess *proc; + PRIntn i; + char *child_argv[32]; + char **child_arg; + char iterations_buf[32]; + PRSharedMemory *shm; + PRIntn *counter_addr; + PRInt32 exit_code; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop count */ + iterations = atoi(opt->value); + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (PR_DeleteSharedMemory(SHM_NAME) == PR_SUCCESS) { + fprintf(stderr, "warning: removed shared memory %s left over " + "from previous run\n", SHM_NAME); + } + if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) { + fprintf(stderr, "warning: removed semaphore %s left over " + "from previous run\n", SEM_NAME1); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_SUCCESS) { + fprintf(stderr, "warning: removed semaphore %s left over " + "from previous run\n", SEM_NAME2); + } + + shm = PR_OpenSharedMemory(SHM_NAME, sizeof(*counter_addr), PR_SHM_CREATE, SHM_MODE); + if (NULL == shm) { + fprintf(stderr, "PR_OpenSharedMemory failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + counter_addr = PR_AttachSharedMemory(shm, 0); + if (NULL == counter_addr) { + fprintf(stderr, "PR_AttachSharedMemory failed\n"); + exit(1); + } + *counter_addr = 0; + sem1 = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 1); + if (NULL == sem1) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + sem2 = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 0); + if (NULL == sem2) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + + child_arg = &child_argv[0]; + *child_arg++ = "semapong"; + if (debug_mode != PR_FALSE) { + *child_arg++ = "-d"; + } + if (iterations != ITERATIONS) { + *child_arg++ = "-c"; + PR_snprintf(iterations_buf, sizeof(iterations_buf), "%d", iterations); + *child_arg++ = iterations_buf; + } + *child_arg = NULL; + proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); + if (NULL == proc) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + + /* + * Process 1 waits on semaphore 1 and posts to semaphore 2. + */ + for (i = 0; i < iterations; i++) { + if (PR_WaitSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_WaitSemaphore failed\n"); + exit(1); + } + if (*counter_addr == 2*i) { + if (debug_mode) printf("process 1: counter = %d\n", *counter_addr); + } else { + fprintf(stderr, "process 1: counter should be %d but is %d\n", + 2*i, *counter_addr); + exit(1); + } + (*counter_addr)++; + if (PR_PostSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_PostSemaphore failed\n"); + exit(1); + } + } + if (PR_DetachSharedMemory(shm, counter_addr) == PR_FAILURE) { + fprintf(stderr, "PR_DetachSharedMemory failed\n"); + exit(1); + } + if (PR_CloseSharedMemory(shm) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSharedMemory failed\n"); + exit(1); + } + if (PR_CloseSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + if (PR_CloseSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + + if (PR_WaitProcess(proc, &exit_code) == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exit_code != 0) { + fprintf(stderr, "process 2 failed with exit code %d\n", exit_code); + exit(1); + } + + if (PR_DeleteSharedMemory(SHM_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSharedMemory failed\n"); + } + if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + } + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/semapong.c b/nsprpub/pr/tests/semapong.c new file mode 100644 index 00000000000..d3733290bbb --- /dev/null +++ b/nsprpub/pr/tests/semapong.c @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define SHM_NAME "/tmp/counter" +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_NAME2 "/tmp/bar.sem" +#define ITERATIONS 1000 + +static PRBool debug_mode = PR_FALSE; +static PRIntn iterations = ITERATIONS; +static PRSem *sem1, *sem2; + +static void Help(void) +{ + fprintf(stderr, "semapong test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-c loop count (%d)\n", ITERATIONS); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PRIntn i; + PRSharedMemory *shm; + PRIntn *counter_addr; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop count */ + iterations = atoi(opt->value); + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + shm = PR_OpenSharedMemory(SHM_NAME, sizeof(*counter_addr), 0, 0666); + if (NULL == shm) { + fprintf(stderr, "PR_OpenSharedMemory failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + sem1 = PR_OpenSemaphore(SEM_NAME1, 0, 0, 0); + if (NULL == sem1) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + sem2 = PR_OpenSemaphore(SEM_NAME2, 0, 0, 0); + if (NULL == sem2) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + + counter_addr = PR_AttachSharedMemory(shm, 0); + if (NULL == counter_addr) { + fprintf(stderr, "PR_AttachSharedMemory failed\n"); + exit(1); + } + + /* + * Process 2 waits on semaphore 2 and posts to semaphore 1. + */ + for (i = 0; i < iterations; i++) { + if (PR_WaitSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_WaitSemaphore failed\n"); + exit(1); + } + if (*counter_addr == 2*i+1) { + if (debug_mode) printf("process 2: counter = %d\n", *counter_addr); + } else { + fprintf(stderr, "process 2: counter should be %d but is %d\n", + 2*i+1, *counter_addr); + exit(1); + } + (*counter_addr)++; + if (PR_PostSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_PostSemaphore failed\n"); + exit(1); + } + } + if (PR_DetachSharedMemory(shm, counter_addr) == PR_FAILURE) { + fprintf(stderr, "PR_DetachSharedMemory failed\n"); + exit(1); + } + if (PR_CloseSharedMemory(shm) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSharedMemory failed\n"); + exit(1); + } + if (PR_CloseSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + if (PR_CloseSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/sendzlf.c b/nsprpub/pr/tests/sendzlf.c new file mode 100644 index 00000000000..5416475b27a --- /dev/null +++ b/nsprpub/pr/tests/sendzlf.c @@ -0,0 +1,246 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Test: sendzlf.c + * + * Description: send a zero-length file with PR_SendFile and + * PR_TransmitFile. + */ + +#define ZERO_LEN_FILE_NAME "zerolen.tmp" +#define HEADER_STR "Header" +#define HEADER_LEN 6 /* length of HEADER_STR, not counting the null byte */ +#define TRAILER_STR "Trailer" +#define TRAILER_LEN 7 /* length of TRAILER_STR, not counting the null byte */ + +#include "nspr.h" + +#include +#include +#include + +static void ClientThread(void *arg) +{ + PRFileDesc *sock; + PRNetAddr addr; + PRUint16 port = (PRUint16) arg; + char buf[1024]; + char *bufPtr; + PRInt32 nbytes; + PRInt32 ntotal; + PRInt32 nexpected; + + sock = PR_NewTCPSocket(); + if (NULL == sock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrLoopback, port, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + fprintf(stderr, "PR_Connect failed\n"); + exit(1); + } + ntotal = 0; + bufPtr = buf; + while ((nbytes = PR_Read(sock, bufPtr, sizeof(buf)-ntotal)) > 0) { + ntotal += nbytes; + bufPtr += nbytes; + } + if (-1 == nbytes) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + nexpected = HEADER_LEN+TRAILER_LEN+TRAILER_LEN+HEADER_LEN+HEADER_LEN; + if (ntotal != nexpected) { + fprintf(stderr, "total bytes read should be %d but is %d\n", + nexpected, ntotal); + exit(1); + } + if (memcmp(buf, HEADER_STR TRAILER_STR TRAILER_STR HEADER_STR HEADER_STR, + nexpected) != 0) { + fprintf(stderr, "wrong data is received\n"); + exit(1); + } + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +static void ServerThread(void *arg) +{ + PRFileDesc *listenSock = (PRFileDesc *) arg; + PRFileDesc *acceptSock; + PRFileDesc *file; + PRSendFileData sfd; + char header[1024], trailer[1024]; + PRInt32 nbytes; + + /* Create a zero-length file */ + file = PR_Open(ZERO_LEN_FILE_NAME, + PR_CREATE_FILE|PR_TRUNCATE|PR_RDWR, 0666); + if (NULL == file) { + fprintf(stderr, "PR_Open failed\n"); + exit(1); + } + sfd.fd = file; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + memcpy(header, HEADER_STR, HEADER_LEN); + memcpy(trailer, TRAILER_STR, TRAILER_LEN); + sfd.header = header; + sfd.hlen = HEADER_LEN; + sfd.trailer = trailer; + sfd.tlen = TRAILER_LEN; + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + /* Send both header and trailer */ + nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (HEADER_LEN+TRAILER_LEN != nbytes) { + fprintf(stderr, "PR_SendFile should return %d but returned %d\n", + HEADER_LEN+TRAILER_LEN, nbytes); + exit(1); + } + /* Trailer only, no header */ + sfd.hlen = 0; + nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (TRAILER_LEN != nbytes) { + fprintf(stderr, "PR_SendFile should return %d but returned %d\n", + TRAILER_LEN, nbytes); + exit(1); + } + /* Header only, no trailer */ + sfd.hlen = HEADER_LEN; + sfd.tlen = 0; + nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (HEADER_LEN != nbytes) { + fprintf(stderr, "PR_SendFile should return %d but returned %d\n", + HEADER_LEN, nbytes); + exit(1); + } + /* Try PR_TransmitFile */ + nbytes = PR_TransmitFile(acceptSock, file, header, HEADER_LEN, + PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); + if (HEADER_LEN != nbytes) { + fprintf(stderr, "PR_TransmitFile should return %d but returned %d\n", + HEADER_LEN, nbytes); + exit(1); + } + if (PR_Close(acceptSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_Close(file) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_Delete(ZERO_LEN_FILE_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_Delete failed\n"); + exit(1); + } +} + +int main() +{ + PRFileDesc *listenSock; + PRThread *clientThread; + PRThread *serverThread; + PRNetAddr addr; + PRThreadScope scope = PR_GLOBAL_THREAD; + + listenSock = PR_NewTCPSocket(); + if (NULL == listenSock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + /* Find out what port number we are bound to. */ + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), + PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); + if (NULL == clientThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + serverThread = PR_CreateThread(PR_USER_THREAD, + ServerThread, listenSock, + PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); + if (NULL == serverThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(clientThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + if (PR_JoinThread(serverThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + if (PR_Close(listenSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/server_test.c b/nsprpub/pr/tests/server_test.c new file mode 100644 index 00000000000..8bb6d99b6c6 --- /dev/null +++ b/nsprpub/pr/tests/server_test.c @@ -0,0 +1,635 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** This server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-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. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +#define PASS 0 +#define FAIL 1 +static int debug_mode = 0; + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#undef DEBUGPRINTS +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + + +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static void Test_Result (int result) +{ + switch (result) + { + case PASS: + printf ("PASS\n"); + break; + case FAIL: + printf ("FAIL\n"); + break; + default: + break; + } +} + +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + } else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) { + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + } else { + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + } + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else Test_Result(FAIL); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else Test_Result(FAIL); + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else Test_Result(FAIL); + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + +static void do_workUU(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workUK(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + +static void do_workKU(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workKK(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +main(int argc, char **argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 10; + _clients = 1; + _client_data = 10; + _server_data = 10; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + Measure(do_workUU, "server loop user/user"); + #if 0 + Measure(do_workUK, "server loop user/kernel"); + Measure(do_workKU, "server loop kernel/user"); + Measure(do_workKK, "server loop kernel/kernel"); + #endif + + PR_Cleanup(); + + return 0; +} diff --git a/nsprpub/pr/tests/servr_kk.c b/nsprpub/pr/tests/servr_kk.c new file mode 100644 index 00000000000..9fbb9b00e6f --- /dev/null +++ b/nsprpub/pr/tests/servr_kk.c @@ -0,0 +1,614 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** This server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + } else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) { + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + } else { + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + } + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRSocketOptionData sockOpt; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else failed_already=1; + return NULL; + } + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) { + if (debug_mode) printf("\tServer error setting socket option: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else failed_already=1; + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + +static void do_workUU(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workUK(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + +static void do_workKU(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workKK(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +int main(int argc, char **argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 7; + _clients = 7; + _client_data = 100; + _server_data = 100; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + PR_SetThreadRecycleMode(64); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + + Measure(do_workKK, "server loop kernel/kernel"); + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/nsprpub/pr/tests/servr_ku.c b/nsprpub/pr/tests/servr_ku.c new file mode 100644 index 00000000000..ab2083d0f6e --- /dev/null +++ b/nsprpub/pr/tests/servr_ku.c @@ -0,0 +1,594 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** This server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + } else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) { + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + } else { + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + } + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRSocketOptionData sockOpt; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else failed_already=1; + return NULL; + } + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) { + if (debug_mode) printf("\tServer error setting socket option: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else failed_already=1; + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + + +static void do_workKU(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +main(int argc, char **argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 7; + _clients = 7; + _client_data = 100; + _server_data = 100; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + PR_SetThreadRecycleMode(64); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + Measure(do_workKU, "server loop kernel/user"); + + PR_Cleanup(); + if(failed_already) + return 1; + else + return 0; + +} diff --git a/nsprpub/pr/tests/servr_uk.c b/nsprpub/pr/tests/servr_uk.c new file mode 100644 index 00000000000..727b7b472ad --- /dev/null +++ b/nsprpub/pr/tests/servr_uk.c @@ -0,0 +1,596 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** This server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + + + +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + } else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) { + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + } else { + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + } + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRSocketOptionData sockOpt; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else + return NULL; + } + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) { + if (debug_mode) printf("\tServer error setting socket option: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else failed_already=1; + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + + +static void do_workUK(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +main(int argc, char **argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 7; + _clients = 7; + _client_data = 100; + _server_data = 100; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + PR_SetThreadRecycleMode(64); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + Measure(do_workUK, "server loop user/kernel"); + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; +} diff --git a/nsprpub/pr/tests/servr_uu.c b/nsprpub/pr/tests/servr_uu.c new file mode 100644 index 00000000000..020fadf669a --- /dev/null +++ b/nsprpub/pr/tests/servr_uu.c @@ -0,0 +1,594 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** This server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-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. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + } else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) { + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + } else { + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + } + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRSocketOptionData sockOpt; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else failed_already=1; + return NULL; + } + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) { + if (debug_mode) printf("\tServer error setting socket option: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else failed_already=1; + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + +static void do_workUU(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +main(int argc, char **argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 7; + _clients = 7; + _client_data = 100; + _server_data = 100; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + PR_SetThreadRecycleMode(64); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + Measure(do_workUU, "server loop user/user"); + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/nsprpub/pr/tests/short_thread.c b/nsprpub/pr/tests/short_thread.c new file mode 100644 index 00000000000..42a52d7ce84 --- /dev/null +++ b/nsprpub/pr/tests/short_thread.c @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include "nspr.h" +#include "plgetopt.h" + +/* + * Create a thread that exits right away; useful for testing race conditions in thread + * creation + */ + +int _debug_on = 0; +#define DPRINTF(arg) if (_debug_on) printf arg + +static void housecleaning(void *cur_time); + +int main (int argc, char **argv) +{ + static PRIntervalTime thread_start_time; + static PRThread *housekeeping_tid = NULL; + 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 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (( housekeeping_tid = + PR_CreateThread (PR_USER_THREAD, housecleaning, (void*)&thread_start_time, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0)) + == NULL ) { + fprintf(stderr, + "simple_test: Error - PR_CreateThread failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + exit( 1 ); + } + PR_Cleanup(); + return(0); +} + +static void +housecleaning (void *cur_time) +{ + DPRINTF(("Child Thread exiting\n")); +} diff --git a/nsprpub/pr/tests/sigpipe.c b/nsprpub/pr/tests/sigpipe.c new file mode 100644 index 00000000000..ecb9689c818 --- /dev/null +++ b/nsprpub/pr/tests/sigpipe.c @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + ************************************************************************* + * + * Test: sigpipe.c + * + * Test the SIGPIPE handler in NSPR. This test applies to Unix only. + * + ************************************************************************* + */ + +#if !defined(XP_UNIX) && !defined(XP_OS2) + +int main(void) +{ + /* This test applies to Unix and OS/2 (emx build). */ + return 0; +} + +#else /* XP_UNIX && OS/2 */ + +#include "nspr.h" + +#ifdef XP_OS2 +#define INCL_DOSQUEUES +#define INCL_DOSERRORS +#include +#endif + +#include +#ifdef XP_OS2_VACPP +#define EPIPE EBADF /* IBM's write() doesn't return EPIPE */ +#include +#else +#include +#endif +#include + +static void Test(void *arg) +{ +#ifdef XP_OS2 + HFILE pipefd[2]; +#else + int pipefd[2]; +#endif + int rv; + char c = '\0'; + +#ifdef XP_OS2 + if (DosCreatePipe(&pipefd[0], &pipefd[1], 4096) != 0) { +#else + if (pipe(pipefd) == -1) { +#endif + fprintf(stderr, "cannot create pipe: %d\n", errno); + exit(1); + } + close(pipefd[0]); + + rv = write(pipefd[1], &c, 1); + if (rv != -1) { + fprintf(stderr, "write to broken pipe should have failed with EPIPE but returned %d\n", rv); + exit(1); + } + if (errno != EPIPE) { + fprintf(stderr, "write to broken pipe failed but with wrong errno: %d\n", errno); + exit(1); + } + close(pipefd[1]); + printf("write to broken pipe failed with EPIPE, as expected\n"); +} + +int main(void) +{ + PRThread *thread; + + /* This initializes NSPR. */ + PR_SetError(0, 0); + + thread = PR_CreateThread(PR_USER_THREAD, Test, NULL, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (thread == NULL) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(thread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + Test(NULL); + + printf("PASSED\n"); + return 0; +} + +#endif /* XP_UNIX */ diff --git a/nsprpub/pr/tests/sleep.c b/nsprpub/pr/tests/sleep.c new file mode 100644 index 00000000000..518473677d0 --- /dev/null +++ b/nsprpub/pr/tests/sleep.c @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" + +#if defined(XP_UNIX) || defined(XP_OS2) + +#include + +#ifndef XP_OS2 +#include +#endif +#include + +#if defined(HAVE_SVID_GETTOD) +#define GTOD(_a) gettimeofday(_a) +#else +#define GTOD(_a) gettimeofday((_a), NULL) +#endif + +#if defined (XP_OS2_VACPP) +#define INCL_DOSPROCESS +#include +#endif + +static PRIntn rv = 0; + +static void Other(void *unused) +{ + PRIntn didit = 0; + while (PR_SUCCESS == PR_Sleep(PR_MillisecondsToInterval(250))) + { + fprintf(stderr, "."); + didit += 1; + } + if (didit < 5) rv = 1; +} + +PRIntn main () +{ + PRUint32 elapsed; + PRThread *thread; + struct timeval timein, timeout; + PRInt32 onePercent = 3000000UL / 100UL; + + fprintf (stderr, "First sleep will sleep 3 seconds.\n"); + fprintf (stderr, " sleep 1 begin\n"); + (void)GTOD(&timein); + sleep (3); + (void)GTOD(&timeout); + fprintf (stderr, " sleep 1 end\n"); + elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec); + elapsed += (timeout.tv_usec - timein.tv_usec); + fprintf(stderr, "elapsed %u usecs\n", elapsed); + if (labs(elapsed - 3000000UL) > onePercent) rv = 1; + + PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 100); + PR_STDIO_INIT(); + + fprintf (stderr, "Second sleep should do the same (does it?).\n"); + fprintf (stderr, " sleep 2 begin\n"); + (void)GTOD(&timein); + sleep (3); + (void)GTOD(&timeout); + fprintf (stderr, " sleep 2 end\n"); + elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec); + elapsed += (timeout.tv_usec - timein.tv_usec); + fprintf(stderr, "elapsed %u usecs\n", elapsed); + if (labs(elapsed - 3000000UL) > onePercent) rv = 1; + + fprintf (stderr, "What happens to other threads?\n"); + fprintf (stderr, "You should see dots every quarter second.\n"); + fprintf (stderr, "If you don't, you're probably running on classic NSPR.\n"); + thread = PR_CreateThread( + PR_USER_THREAD, Other, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + fprintf (stderr, " sleep 2 begin\n"); + (void)GTOD(&timein); + sleep (3); + (void)GTOD(&timeout); + fprintf (stderr, " sleep 2 end\n"); + PR_Interrupt(thread); + PR_JoinThread(thread); + elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec); + elapsed += (timeout.tv_usec - timein.tv_usec); + fprintf(stderr, "elapsed %u usecs\n", elapsed); + if (labs(elapsed - 3000000UL) > onePercent) rv = 1; + fprintf(stderr, "%s\n", (0 == rv) ? "PASSED" : "FAILED"); + return rv; +} + +#else /* defined(XP_UNIX) */ + +PRIntn main() +{ + return 2; +} + +#endif /* defined(XP_UNIX) */ + diff --git a/nsprpub/pr/tests/socket.c b/nsprpub/pr/tests/socket.c new file mode 100644 index 00000000000..8e4a899b39c --- /dev/null +++ b/nsprpub/pr/tests/socket.c @@ -0,0 +1,2354 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: socket.c +** +** Description: Test socket functionality. +** +** Modification History: +*/ +#include "primpl.h" + +#include "plgetopt.h" + +#include +#include +#include +#ifdef XP_UNIX +#include +#endif +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#endif + +#ifdef WIN32 +#include +#endif + +static int _debug_on = 0; +static int test_cancelio = 0; + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +int fprintf(FILE *stream, const char *fmt, ...) +{ + PR_LogPrint(fmt); + return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +#ifdef XP_PC +#define mode_t int +#endif + +#define DPRINTF(arg) if (_debug_on) printf arg + +#ifdef XP_PC +char *TEST_DIR = "prdir"; +char *SMALL_FILE_NAME = "prsmallf"; +char *LARGE_FILE_NAME = "prlargef"; +#else +char *TEST_DIR = "/tmp/prsocket_test_dir"; +char *SMALL_FILE_NAME = "/tmp/prsocket_test_dir/small_file"; +char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file"; +#endif +#define SMALL_FILE_SIZE (3 * 1024) /* 3 KB */ +#define SMALL_FILE_OFFSET_1 (512) +#define SMALL_FILE_LEN_1 (1 * 1024) /* 1 KB */ +#define SMALL_FILE_OFFSET_2 (75) +#define SMALL_FILE_LEN_2 (758) +#define SMALL_FILE_OFFSET_3 (1024) +#define SMALL_FILE_LEN_3 (SMALL_FILE_SIZE - SMALL_FILE_OFFSET_3) +#define SMALL_FILE_HEADER_SIZE (64) /* 64 bytes */ +#define SMALL_FILE_TRAILER_SIZE (128) /* 128 bytes */ + +#define LARGE_FILE_SIZE (3 * 1024 * 1024) /* 3 MB */ +#define LARGE_FILE_OFFSET_1 (0) +#define LARGE_FILE_LEN_1 (2 * 1024 * 1024) /* 2 MB */ +#define LARGE_FILE_OFFSET_2 (64) +#define LARGE_FILE_LEN_2 (1 * 1024 * 1024 + 75) +#define LARGE_FILE_OFFSET_3 (2 * 1024 * 1024 - 128) +#define LARGE_FILE_LEN_3 (LARGE_FILE_SIZE - LARGE_FILE_OFFSET_3) +#define LARGE_FILE_OFFSET_4 PR_GetPageSize() +#define LARGE_FILE_LEN_4 769 +#define LARGE_FILE_HEADER_SIZE (512) +#define LARGE_FILE_TRAILER_SIZE (64) + +#define BUF_DATA_SIZE (2 * 1024) +#define TCP_MESG_SIZE 1024 +/* + * set UDP datagram size small enough that datagrams sent to a port on the + * local host will not be lost + */ +#define UDP_DGRAM_SIZE 128 +#define NUM_TCP_CLIENTS 5 /* for a listen queue depth of 5 */ +#define NUM_UDP_CLIENTS 10 + +#ifndef XP_MAC +#define NUM_TRANSMITFILE_CLIENTS 4 +#else +/* Mac can't handle more than 2* (3Mb) allocations for large file size buffers */ +#define NUM_TRANSMITFILE_CLIENTS 2 +#endif + +#define NUM_TCP_CONNECTIONS_PER_CLIENT 5 +#define NUM_TCP_MESGS_PER_CONNECTION 10 +#define NUM_UDP_DATAGRAMS_PER_CLIENT 5 +#define TCP_SERVER_PORT 10000 +#define UDP_SERVER_PORT TCP_SERVER_PORT +#define SERVER_MAX_BIND_COUNT 100 + +static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS; +static PRInt32 num_udp_clients = NUM_UDP_CLIENTS; +static PRInt32 num_transmitfile_clients = NUM_TRANSMITFILE_CLIENTS; +static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT; +static PRInt32 tcp_mesg_size = TCP_MESG_SIZE; +static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION; +static PRInt32 num_udp_datagrams_per_client = NUM_UDP_DATAGRAMS_PER_CLIENT; +static PRInt32 udp_datagram_size = UDP_DGRAM_SIZE; + +static PRInt32 thread_count; +PRUint16 server_domain = PR_AF_INET, client_domain = PR_AF_INET; + +/* an I/O layer that uses the emulated senfile method */ +static PRDescIdentity emuSendFileIdentity; +static PRIOMethods emuSendFileMethods; + +int failed_already=0; +typedef struct buffer { + char data[BUF_DATA_SIZE]; +} buffer; + +PRNetAddr tcp_server_addr, udp_server_addr; + +typedef struct Serve_Client_Param { + PRFileDesc *sockfd; /* socket to read from/write to */ + PRInt32 datalen; /* bytes of data transfered in each read/write */ +} Serve_Client_Param; + +typedef struct Server_Param { + PRSemaphore *addr_sem; /* sem to post on, after setting up the address */ + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *exit_counter; /* counter to decrement, before exit */ + PRInt32 datalen; /* bytes of data transfered in each read/write */ +} Server_Param; + + +typedef struct Client_Param { + PRNetAddr server_addr; + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *exit_counter; /* counter to decrement, before exit */ + PRInt32 datalen; + PRInt32 udp_connect; /* if set clients connect udp sockets */ +} Client_Param; + +/* the sendfile method in emuSendFileMethods */ +static PRInt32 PR_CALLBACK +emu_SendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + return PR_EmulateSendFile(sd, sfd, flags, timeout); +} + +/* the transmitfile method in emuSendFileMethods */ +static PRInt32 PR_CALLBACK +emu_TransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers, + PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRSendFileData sfd; + + sfd.fd = fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = headers; + sfd.hlen = hlen; + sfd.trailer = NULL; + sfd.tlen = 0; + return emu_SendFile(sd, &sfd, flags, timeout); +} + +/* + * readn + * read data from sockfd into buf + */ +static PRInt32 +readn(PRFileDesc *sockfd, char *buf, int len) +{ + int rem; + int bytes; + int offset = 0; + int err; + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + + if (test_cancelio) + timeout = PR_SecondsToInterval(2); + + for (rem=len; rem; offset += bytes, rem -= bytes) { + DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n", + PR_GetCurrentThread(), rem)); +retry: + bytes = PR_Recv(sockfd, buf + offset, rem, 0, + timeout); + DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n", + PR_GetCurrentThread(), bytes)); + if (bytes < 0) { +#ifdef WINNT + printf("PR_Recv: error = %d oserr = %d\n",(err = PR_GetError()), + PR_GetOSError()); + if ((test_cancelio) && (err == PR_IO_TIMEOUT_ERROR)) { + if (PR_NT_CancelIo(sockfd) != PR_SUCCESS) + printf("PR_NT_CancelIO: error = %d\n",PR_GetError()); + timeout = PR_INTERVAL_NO_TIMEOUT; + goto retry; + } +#endif + return -1; + } + } + return len; +} + +/* + * writen + * write data from buf to sockfd + */ +static PRInt32 +writen(PRFileDesc *sockfd, char *buf, int len) +{ + int rem; + int bytes; + int offset = 0; + + for (rem=len; rem; offset += bytes, rem -= bytes) { + DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n", + PR_GetCurrentThread(), rem)); + bytes = PR_Send(sockfd, buf + offset, rem, 0, + PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n", + PR_GetCurrentThread(), bytes)); + if (bytes <= 0) + return -1; + } + return len; +} + +/* + * Serve_Client + * Thread, started by the server, for serving a client connection. + * Reads data from socket and writes it back, unmodified, and + * closes the socket + */ +static void PR_CALLBACK +Serve_Client(void *arg) +{ + Serve_Client_Param *scp = (Serve_Client_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf; + PRInt32 bytes, j; + + sockfd = scp->sockfd; + bytes = scp->datalen; + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + goto exit; + } + + + for (j = 0; j < num_tcp_mesgs_per_connection; j++) { + /* + * Read data from client and send it back to the client unmodified + */ + if (readn(sockfd, in_buf->data, bytes) < bytes) { + fprintf(stderr,"prsocket_test: ERROR - Serve_Client:readn\n"); + failed_already=1; + goto exit; + } + /* + * shutdown reads, after the last read + */ + if (j == num_tcp_mesgs_per_connection - 1) + if (PR_Shutdown(sockfd, PR_SHUTDOWN_RCV) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n"); + } + DPRINTF(("Serve_Client [0x%lx]: inbuf[0] = 0x%lx\n",PR_GetCurrentThread(), + (*((int *) in_buf->data)))); + if (writen(sockfd, in_buf->data, bytes) < bytes) { + fprintf(stderr,"prsocket_test: ERROR - Serve_Client:writen\n"); + failed_already=1; + goto exit; + } + } + /* + * shutdown reads and writes + */ + if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n"); + failed_already=1; + } + +exit: + PR_Close(sockfd); + if (in_buf) { + PR_DELETE(in_buf); + } +} + +PRThread* create_new_thread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, PRInt32 index) +{ +PRInt32 native_thread = 0; + + PR_ASSERT(state == PR_UNJOINABLE_THREAD); +#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32) + switch(index % 4) { + case 0: + scope = (PR_LOCAL_THREAD); + break; + case 1: + scope = (PR_GLOBAL_THREAD); + break; + case 2: + scope = (PR_GLOBAL_BOUND_THREAD); + break; + case 3: + native_thread = 1; + break; + default: + PR_ASSERT(!"Invalid scope"); + break; + } + if (native_thread) { +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + pthread_t tid; + if (!pthread_create(&tid, NULL, (void * (*)(void *)) start, arg)) + return((PRThread *) tid); + else + return (NULL); +#else + HANDLE thandle; + unsigned tid; + + thandle = (HANDLE) _beginthreadex( + NULL, + stackSize, + (unsigned (__stdcall *)(void *))start, + arg, + 0, + &tid); + return((PRThread *) thandle); +#endif + } else { + return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); + } +#else + return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); +#endif +} + +/* + * TCP Server + * Server Thread + * Bind an address to a socket and listen for incoming connections + * Start a Serve_Client thread for each incoming connection. + */ +static void PR_CALLBACK +TCP_Server(void *arg) +{ + PRThread *t; + Server_Param *sp = (Server_Param *) arg; + Serve_Client_Param *scp; + PRFileDesc *sockfd, *newsockfd; + PRNetAddr netaddr; + PRInt32 i; + /* + * Create a tcp socket + */ + if ((sockfd = PR_OpenTCPSocket(server_domain)) == NULL) { + fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n"); + goto exit; + } + memset(&netaddr, 0 , sizeof(netaddr)); + + if (PR_SetNetAddr(PR_IpAddrAny, server_domain, TCP_SERVER_PORT, + &netaddr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + goto exit; + } + /* + * 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,"prsocket_test: ERROR - PR_Bind failed\n"); + perror("PR_Bind"); + failed_already=1; + goto exit; + } + + if (PR_Listen(sockfd, 32) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n"); + failed_already=1; + goto exit; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n"); + failed_already=1; + goto exit; + } + + DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain, + PR_ntohs(PR_NetAddrInetPort(&netaddr)), + &tcp_server_addr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + goto exit; + } + if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET)) + PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK), + &tcp_server_addr.ipv6.ip); + + /* + * Wake up parent thread because server address is bound and made + * available in the global variable 'tcp_server_addr' + */ + PR_PostSem(sp->addr_sem); + + for (i = 0; i < (num_tcp_clients * num_tcp_connections_per_client); i++) { + /* test both null and non-null 'addr' argument to PR_Accept */ + PRNetAddr *addrp = (i%2 ? &netaddr: NULL); + + DPRINTF(("TCP_Server: Accepting connection\n")); + if ((newsockfd = PR_Accept(sockfd, addrp, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr,"prsocket_test: ERROR - PR_Accept failed\n"); + goto exit; + } + DPRINTF(("TCP_Server: Accepted connection\n")); + scp = PR_NEW(Serve_Client_Param); + if (scp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + goto exit; + } + + /* + * Start a Serve_Client thread for each incoming connection + */ + scp->sockfd = newsockfd; + scp->datalen = sp->datalen; + + t = create_new_thread(PR_USER_THREAD, + Serve_Client, (void *)scp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, i); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + goto exit; + } + DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", t)); + } + +exit: + if (sockfd) { + PR_Close(sockfd); + } + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(sp->exit_mon); + --(*sp->exit_counter); + PR_Notify(sp->exit_mon); + PR_ExitMonitor(sp->exit_mon); + DPRINTF(("TCP_Server [0x%lx] exiting\n", PR_GetCurrentThread())); +} + +/* + * UDP Server + * Server Thread + * Bind an address to a socket, read data from clients and send data + * back to clients + */ +static void PR_CALLBACK +UDP_Server(void *arg) +{ + Server_Param *sp = (Server_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf; + PRNetAddr netaddr; + PRInt32 bytes, i, rv = 0; + + + bytes = sp->datalen; + /* + * Create a udp socket + */ + if ((sockfd = PR_OpenUDPSocket(server_domain)) == NULL) { + fprintf(stderr,"prsocket_test: PR_NewUDPSocket failed\n"); + failed_already=1; + return; + } + memset(&netaddr, 0 , sizeof(netaddr)); + if (PR_SetNetAddr(PR_IpAddrAny, server_domain, UDP_SERVER_PORT, + &netaddr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + failed_already=1; + return; + } + /* + * 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,"prsocket_test: ERROR - PR_Bind failed\n"); + perror("PR_Bind"); + failed_already=1; + return; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n"); + failed_already=1; + return; + } + + DPRINTF(("PR_Bind: UDP Server netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + /* + * We can't use the IP address returned by PR_GetSockName in + * netaddr.inet.ip because netaddr.inet.ip is returned + * as 0 (= PR_INADDR_ANY). + */ + + if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain, + PR_ntohs(PR_NetAddrInetPort(&netaddr)), + &udp_server_addr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + failed_already=1; + return; + } + if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET)) + PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK), + &udp_server_addr.ipv6.ip); + + /* + * Wake up parent thread because server address is bound and made + * available in the global variable 'udp_server_addr' + */ + PR_PostSem(sp->addr_sem); + + bytes = sp->datalen; + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + /* + * Receive datagrams from clients and send them back, unmodified, to the + * clients + */ + memset(&netaddr, 0 , sizeof(netaddr)); + for (i = 0; i < (num_udp_clients * num_udp_datagrams_per_client); i++) { + DPRINTF(("UDP_Server: calling PR_RecvFrom client - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n", + netaddr.inet.ip, netaddr.inet.port, bytes, in_buf->data, + in_buf->data[0])); + + rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr, + PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("UDP_Server: PR_RecvFrom client - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n", + netaddr.inet.ip, netaddr.inet.port, rv, in_buf->data, + in_buf->data[0])); + if (rv != bytes) { + return; + } + rv = PR_SendTo(sockfd, in_buf->data, bytes, 0, &netaddr, + PR_INTERVAL_NO_TIMEOUT); + if (rv != bytes) { + return; + } + } + + PR_DELETE(in_buf); + PR_Close(sockfd); + + /* + * Decrement exit_counter and notify parent thread + */ + PR_EnterMonitor(sp->exit_mon); + --(*sp->exit_counter); + PR_Notify(sp->exit_mon); + PR_ExitMonitor(sp->exit_mon); + DPRINTF(("UDP_Server [0x%x] exiting\n", PR_GetCurrentThread())); +} + +/* + * TCP_Client + * Client Thread + * Connect to the server at the address specified in the argument. + * Fill in a buffer, write data to server, read it back and check + * for data corruption. + * Close the socket for server connection + */ +static void PR_CALLBACK +TCP_Client(void *arg) +{ + Client_Param *cp = (Client_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf, *out_buf; + union PRNetAddr netaddr; + PRInt32 bytes, i, j; + + + bytes = cp->datalen; + out_buf = PR_NEW(buffer); + if (out_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + netaddr = cp->server_addr; + + for (i = 0; i < num_tcp_connections_per_client; i++) { + if ((sockfd = PR_OpenTCPSocket(client_domain)) == NULL) { + fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n"); + failed_already=1; + return; + } + if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){ + fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + return; + } + for (j = 0; j < num_tcp_mesgs_per_connection; j++) { + /* + * fill in random data + */ + memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes); + /* + * write to server + */ +#ifdef WINNT + if (test_cancelio && (j == 0)) + PR_Sleep(PR_SecondsToInterval(12)); +#endif + if (writen(sockfd, out_buf->data, bytes) < bytes) { + fprintf(stderr,"prsocket_test: ERROR - TCP_Client:writen\n"); + failed_already=1; + return; + } + DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n", + PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data)))); + if (readn(sockfd, in_buf->data, bytes) < bytes) { + fprintf(stderr,"prsocket_test: ERROR - TCP_Client:readn\n"); + failed_already=1; + return; + } + /* + * verify the data read + */ + if (memcmp(in_buf->data, out_buf->data, bytes) != 0) { + fprintf(stderr,"prsocket_test: ERROR - data corruption\n"); + failed_already=1; + return; + } + } + /* + * shutdown reads and writes + */ + if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n"); + failed_already=1; + } + PR_Close(sockfd); + } + + PR_DELETE(out_buf); + PR_DELETE(in_buf); + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(cp->exit_mon); + --(*cp->exit_counter); + PR_Notify(cp->exit_mon); + PR_ExitMonitor(cp->exit_mon); + DPRINTF(("TCP_Client [0x%x] exiting\n", PR_GetCurrentThread())); +} + +/* + * UDP_Client + * Client Thread + * Create a socket and bind an address + * Communicate with the server at the address specified in the argument. + * Fill in a buffer, write data to server, read it back and check + * for data corruption. + * Close the socket + */ +static void PR_CALLBACK +UDP_Client(void *arg) +{ + Client_Param *cp = (Client_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf, *out_buf; + union PRNetAddr netaddr; + PRInt32 bytes, i, rv; + + + bytes = cp->datalen; + out_buf = PR_NEW(buffer); + if (out_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + if ((sockfd = PR_OpenUDPSocket(client_domain)) == NULL) { + fprintf(stderr,"prsocket_test: PR_OpenUDPSocket failed\n"); + failed_already=1; + return; + } + + /* + * bind an address for the client, let the system chose the port + * number + */ + memset(&netaddr, 0 , sizeof(netaddr)); + if (PR_SetNetAddr(PR_IpAddrAny, client_domain, 0, + &netaddr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + failed_already=1; + return; + } + if (PR_Bind(sockfd, &netaddr) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n"); + perror("PR_Bind"); + return; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n"); + failed_already=1; + return; + } + + DPRINTF(("PR_Bind: UDP Client netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + + netaddr = cp->server_addr; + + if (cp->udp_connect) { + if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){ + fprintf(stderr,"prsocket_test: PR_Connect failed\n"); + failed_already=1; + return; + } + } + + for (i = 0; i < num_udp_datagrams_per_client; i++) { + /* + * fill in random data + */ + DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx bytes = 0x%lx\n", + PR_GetCurrentThread(), out_buf->data, bytes)); + memset(out_buf->data, ((PRInt32) (&netaddr)) + i, bytes); + /* + * write to server + */ + if (cp->udp_connect) + rv = PR_Send(sockfd, out_buf->data, bytes, 0, + PR_INTERVAL_NO_TIMEOUT); + else + rv = PR_SendTo(sockfd, out_buf->data, bytes, 0, &netaddr, + PR_INTERVAL_NO_TIMEOUT); + if (rv != bytes) { + return; + } + DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n", + PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data)))); + if (cp->udp_connect) + rv = PR_Recv(sockfd, in_buf->data, bytes, 0, + PR_INTERVAL_NO_TIMEOUT); + else + rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr, + PR_INTERVAL_NO_TIMEOUT); + if (rv != bytes) { + return; + } + DPRINTF(("UDP_Client [0x%lx]: in_buf = 0x%lx in_buf[0] = 0x%lx\n", + PR_GetCurrentThread(), in_buf, (*((int *) in_buf->data)))); + /* + * verify the data read + */ + if (memcmp(in_buf->data, out_buf->data, bytes) != 0) { + fprintf(stderr,"prsocket_test: ERROR - UDP data corruption\n"); + failed_already=1; + return; + } + } + PR_Close(sockfd); + + PR_DELETE(in_buf); + PR_DELETE(out_buf); + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(cp->exit_mon); + --(*cp->exit_counter); + PR_Notify(cp->exit_mon); + PR_ExitMonitor(cp->exit_mon); + PR_DELETE(cp); + DPRINTF(("UDP_Client [0x%x] exiting\n", PR_GetCurrentThread())); +} + +/* + * TCP_Socket_Client_Server_Test - concurrent server test + * + * One server and several clients are started + * Each client connects to the server and sends a chunk of data + * For each connection, server starts another thread to read the data + * from the client and send it back to the client, unmodified. + * Each client checks that data received from server is same as the + * data it sent to the server. + * + */ + +static PRInt32 +TCP_Socket_Client_Server_Test(void) +{ + int i; + PRThread *t; + PRSemaphore *server_sem; + Server_Param *sparamp; + Client_Param *cparamp; + PRMonitor *mon2; + PRInt32 datalen; + + + datalen = tcp_mesg_size; + thread_count = 0; + /* + * start the server thread + */ + sparamp = PR_NEW(Server_Param); + if (sparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + return -1; + } + server_sem = PR_NewSem(0); + if (server_sem == NULL) { + fprintf(stderr,"prsocket_test: PR_NewSem failed\n"); + failed_already=1; + return -1; + } + mon2 = PR_NewMonitor(); + if (mon2 == NULL) { + fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n"); + failed_already=1; + return -1; + } + PR_EnterMonitor(mon2); + + sparamp->addr_sem = server_sem; + sparamp->exit_mon = mon2; + sparamp->exit_counter = &thread_count; + sparamp->datalen = datalen; + t = PR_CreateThread(PR_USER_THREAD, + TCP_Server, (void *)sparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + return -1; + } + DPRINTF(("Created TCP server = 0x%lx\n", t)); + thread_count++; + + /* + * wait till the server address is setup + */ + PR_WaitSem(server_sem); + + /* + * Now start a bunch of client threads + */ + + cparamp = PR_NEW(Client_Param); + if (cparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + return -1; + } + cparamp->server_addr = tcp_server_addr; + cparamp->exit_mon = mon2; + cparamp->exit_counter = &thread_count; + cparamp->datalen = datalen; + for (i = 0; i < num_tcp_clients; i++) { + t = create_new_thread(PR_USER_THREAD, + TCP_Client, (void *) cparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, i); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + return -1; + } + DPRINTF(("Created TCP client = 0x%lx\n", t)); + thread_count++; + } + /* Wait for server and client threads to exit */ + while (thread_count) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("TCP Server - thread_count = %d\n", thread_count)); + } + PR_ExitMonitor(mon2); + printf("%30s","TCP_Socket_Client_Server_Test:"); + printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l, + num_tcp_clients, num_tcp_connections_per_client); + printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":", + num_tcp_mesgs_per_connection, tcp_mesg_size); + + return 0; +} + +/* + * UDP_Socket_Client_Server_Test - iterative server test + * + * One server and several clients are started + * Each client connects to the server and sends a chunk of data + * For each connection, server starts another thread to read the data + * from the client and send it back to the client, unmodified. + * Each client checks that data received from server is same as the + * data it sent to the server. + * + */ + +static PRInt32 +UDP_Socket_Client_Server_Test(void) +{ + int i; + PRThread *t; + PRSemaphore *server_sem; + Server_Param *sparamp; + Client_Param *cparamp; + PRMonitor *mon2; + PRInt32 datalen; + PRInt32 udp_connect = 1; + + + datalen = udp_datagram_size; + thread_count = 0; + /* + * start the server thread + */ + sparamp = PR_NEW(Server_Param); + if (sparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + return -1; + } + server_sem = PR_NewSem(0); + if (server_sem == NULL) { + fprintf(stderr,"prsocket_test: PR_NewSem failed\n"); + failed_already=1; + return -1; + } + mon2 = PR_NewMonitor(); + if (mon2 == NULL) { + fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n"); + failed_already=1; + return -1; + } + PR_EnterMonitor(mon2); + + sparamp->addr_sem = server_sem; + sparamp->exit_mon = mon2; + sparamp->exit_counter = &thread_count; + sparamp->datalen = datalen; + DPRINTF(("Creating UDP server")); + t = PR_CreateThread(PR_USER_THREAD, + UDP_Server, (void *)sparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + return -1; + } + thread_count++; + + /* + * wait till the server address is setup + */ + PR_WaitSem(server_sem); + + /* + * Now start a bunch of client threads + */ + + for (i = 0; i < num_udp_clients; i++) { + cparamp = PR_NEW(Client_Param); + if (cparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + return -1; + } + cparamp->server_addr = udp_server_addr; + cparamp->exit_mon = mon2; + cparamp->exit_counter = &thread_count; + cparamp->datalen = datalen; + /* + * Cause every other client thread to connect udp sockets + */ +#ifndef XP_MAC + cparamp->udp_connect = udp_connect; +#else + /* No support for UDP connects on Mac */ + cparamp->udp_connect = 0; +#endif + if (udp_connect) + udp_connect = 0; + else + udp_connect = 1; + DPRINTF(("Creating UDP client %d\n", i)); + t = PR_CreateThread(PR_USER_THREAD, + UDP_Client, (void *) cparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + return -1; + } + thread_count++; + } + /* Wait for server and client threads to exit */ + while (thread_count) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("UDP Server - thread_count = %d\n", thread_count)); + } + PR_ExitMonitor(mon2); + printf("%30s","UDP_Socket_Client_Server_Test: "); + printf("%2ld Server %2ld Clients\n",1l, num_udp_clients); + printf("%30s %2ld datagrams_per_client %4ld bytes_per_datagram\n",":", + num_udp_datagrams_per_client, udp_datagram_size); + + return 0; +} + +static PRFileDesc *small_file_fd, *large_file_fd; +static void *small_file_addr, *small_file_header, *large_file_addr; +static void *small_file_trailer, *large_file_header, *large_file_trailer; +/* + * TransmitFile_Client + * Client Thread + */ +static void +TransmitFile_Client(void *arg) +{ + PRFileDesc *sockfd; + union PRNetAddr netaddr; + char *small_buf, *large_buf; + Client_Param *cp = (Client_Param *) arg; + PRInt32 rlen; + + small_buf = (char*)PR_Malloc(SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE + + SMALL_FILE_TRAILER_SIZE); + if (small_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer\n"); + failed_already=1; + return; + } + large_buf = (char*)PR_Malloc(LARGE_FILE_SIZE + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE); + if (large_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer\n"); + failed_already=1; + return; + } + netaddr.inet.family = cp->server_addr.inet.family; + netaddr.inet.port = cp->server_addr.inet.port; + netaddr.inet.ip = cp->server_addr.inet.ip; + + if ((sockfd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n"); + failed_already=1; + return; + } + + if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){ + fprintf(stderr,"prsocket_test: PR_Connect failed\n"); + failed_already=1; + return; + } + /* + * read the small file and verify the data + */ + if (readn(sockfd, small_buf, SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE) + != (SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)) { + fprintf(stderr, + "prsocket_test: TransmitFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "prsocket_test: TransmitFile_Client ERROR - small file header data corruption\n"); + failed_already=1; + return; + } + if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE, + SMALL_FILE_SIZE) != 0) { + fprintf(stderr, + "prsocket_test: TransmitFile_Client ERROR - small file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * read the large file and verify the data + */ + if (readn(sockfd, large_buf, LARGE_FILE_SIZE) != LARGE_FILE_SIZE) { + fprintf(stderr, + "prsocket_test: TransmitFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_addr, large_buf, LARGE_FILE_SIZE) != 0) { + fprintf(stderr, + "prsocket_test: TransmitFile_Client ERROR - large file data corruption\n"); + failed_already=1; + } +#endif + + + /* + * receive data from PR_SendFile + */ + /* + * case 1: small file with header and trailer + */ + rlen = SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE + + SMALL_FILE_TRAILER_SIZE; + if (readn(sockfd, small_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 1. ERROR - small file header corruption\n"); + failed_already=1; + return; + } + if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE, + SMALL_FILE_SIZE) != 0) { + fprintf(stderr, + "SendFile 1. ERROR - small file data corruption\n"); + failed_already=1; + return; + } + if (memcmp(small_file_trailer, + small_buf + SMALL_FILE_HEADER_SIZE + SMALL_FILE_SIZE, + SMALL_FILE_TRAILER_SIZE) != 0) { + fprintf(stderr, + "SendFile 1. ERROR - small file trailer corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 2: partial large file at zero offset, file with header and trailer + */ + rlen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE; + if (readn(sockfd, large_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 2. ERROR - large file header corruption\n"); + failed_already=1; + return; + } + if (memcmp(large_file_addr, large_buf + LARGE_FILE_HEADER_SIZE, + LARGE_FILE_LEN_1) != 0) { + fprintf(stderr, + "SendFile 2. ERROR - large file data corruption\n"); + failed_already=1; + return; + } + if (memcmp(large_file_trailer, + large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_1, + LARGE_FILE_TRAILER_SIZE) != 0) { + fprintf(stderr, + "SendFile 2. ERROR - large file trailer corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 3: partial small file at non-zero offset, with header + */ + rlen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE; + if (readn(sockfd, small_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 3. ERROR - small file header corruption\n"); + failed_already=1; + return; + } + if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_1, + small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_1) != 0) { + fprintf(stderr, + "SendFile 3. ERROR - small file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 4: partial small file at non-zero offset, with trailer + */ + rlen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE; + if (readn(sockfd, small_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_2, small_buf, + SMALL_FILE_LEN_2) != 0) { + fprintf(stderr, + "SendFile 4. ERROR - small file data corruption\n"); + failed_already=1; + return; + } + if (memcmp(small_file_trailer, small_buf + SMALL_FILE_LEN_2, + SMALL_FILE_TRAILER_SIZE) != 0) { + fprintf(stderr, + "SendFile 4. ERROR - small file trailer corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 5: partial large file at non-zero offset, file with header + */ + rlen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE; + if (readn(sockfd, large_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 5. ERROR - large file header corruption\n"); + failed_already=1; + return; + } + if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_2, + large_buf + LARGE_FILE_HEADER_SIZE, + LARGE_FILE_LEN_2) != 0) { + fprintf(stderr, + "SendFile 5. ERROR - large file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 6: partial small file at non-zero offset, with header + */ + rlen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE; + if (readn(sockfd, small_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 6. ERROR - small file header corruption\n"); + return; + } + if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_3, + small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_3) != 0) { +#if 0 + char *i, *j; + int k; + + i = (char *) small_file_addr + SMALL_FILE_OFFSET_3; + j = small_buf + SMALL_FILE_HEADER_SIZE; + k = SMALL_FILE_LEN_3; + while (k-- > 0) { + if (*i++ != *j++) + printf("i = %d j = %d\n", + (int) (i - ((char *) small_file_addr + SMALL_FILE_OFFSET_3)), + (int) (j - (small_buf + SMALL_FILE_HEADER_SIZE))); + } +#endif + fprintf(stderr, + "SendFile 6. ERROR - small file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 7: partial large file at non-zero offset, with header + */ + rlen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE; + if (readn(sockfd, large_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 7. ERROR - large file header corruption\n"); + failed_already=1; + return; + } + if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_3, + large_buf + LARGE_FILE_HEADER_SIZE, + LARGE_FILE_LEN_3) != 0) { + fprintf(stderr, + "SendFile 7. ERROR - large file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 8: partial large file at non-zero, page-aligned offset, with + * header and trailer + */ + rlen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE; + if (readn(sockfd, large_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 2. ERROR - large file header corruption\n"); + failed_already=1; + return; + } + if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_4, + large_buf + LARGE_FILE_HEADER_SIZE, + LARGE_FILE_LEN_4) != 0) { + fprintf(stderr, + "SendFile 2. ERROR - large file data corruption\n"); + failed_already=1; + return; + } + if (memcmp(large_file_trailer, + large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_4, + LARGE_FILE_TRAILER_SIZE) != 0) { + fprintf(stderr, + "SendFile 2. ERROR - large file trailer corruption\n"); + failed_already=1; + return; + } +#endif + PR_DELETE(small_buf); + PR_DELETE(large_buf); + PR_Close(sockfd); + + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(cp->exit_mon); + --(*cp->exit_counter); + PR_Notify(cp->exit_mon); + PR_ExitMonitor(cp->exit_mon); + DPRINTF(("TransmitFile_Client [0x%lx] exiting\n", PR_GetCurrentThread())); +} + +/* + * Serve_TransmitFile_Client + * Thread, started by the server, for serving a client connection. + * Trasmits a small file, with a header, and a large file, without + * a header + */ +static void +Serve_TransmitFile_Client(void *arg) +{ + Serve_Client_Param *scp = (Serve_Client_Param *) arg; + PRFileDesc *sockfd; + PRInt32 bytes; + PRFileDesc *local_small_file_fd=NULL; + PRFileDesc *local_large_file_fd=NULL; + PRSendFileData sfd; + PRInt32 slen; + + sockfd = scp->sockfd; + local_small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDONLY,0); + + if (local_small_file_fd == NULL) { + fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n", + SMALL_FILE_NAME); + failed_already=1; + goto done; + } + local_large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDONLY,0); + + if (local_large_file_fd == NULL) { + fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n", + LARGE_FILE_NAME); + failed_already=1; + goto done; + } + bytes = PR_TransmitFile(sockfd, local_small_file_fd, small_file_header, + SMALL_FILE_HEADER_SIZE, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (bytes != (SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE)) { + fprintf(stderr, + "prsocet_test: PR_TransmitFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + bytes = PR_TransmitFile(sockfd, local_large_file_fd, NULL, 0, + PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); + if (bytes != LARGE_FILE_SIZE) { + fprintf(stderr, + "prsocket_test: PR_TransmitFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + + /* + * PR_SendFile test cases + */ + + /* + * case 1: small file with header and trailer + */ + sfd.fd = local_small_file_fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = small_file_header; + sfd.hlen = SMALL_FILE_HEADER_SIZE; + sfd.trailer = small_file_trailer; + sfd.tlen = SMALL_FILE_TRAILER_SIZE; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE + + SMALL_FILE_TRAILER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 1. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + + /* + * case 2: partial large file at zero offset, file with header and trailer + */ + sfd.fd = local_large_file_fd; + sfd.file_offset = 0; + sfd.file_nbytes = LARGE_FILE_LEN_1; + sfd.header = large_file_header; + sfd.hlen = LARGE_FILE_HEADER_SIZE; + sfd.trailer = large_file_trailer; + sfd.tlen = LARGE_FILE_TRAILER_SIZE; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 3: partial small file at non-zero offset, with header + */ + sfd.fd = local_small_file_fd; + sfd.file_offset = SMALL_FILE_OFFSET_1; + sfd.file_nbytes = SMALL_FILE_LEN_1; + sfd.header = small_file_header; + sfd.hlen = SMALL_FILE_HEADER_SIZE; + sfd.trailer = NULL; + sfd.tlen = 0; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 3. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 4: partial small file at non-zero offset, with trailer + */ + sfd.fd = local_small_file_fd; + sfd.file_offset = SMALL_FILE_OFFSET_2; + sfd.file_nbytes = SMALL_FILE_LEN_2; + sfd.header = NULL; + sfd.hlen = 0; + sfd.trailer = small_file_trailer; + sfd.tlen = SMALL_FILE_TRAILER_SIZE; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 4. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 5: partial large file at non-zero offset, file with header + */ + sfd.fd = local_large_file_fd; + sfd.file_offset = LARGE_FILE_OFFSET_2; + sfd.file_nbytes = LARGE_FILE_LEN_2; + sfd.header = large_file_header; + sfd.hlen = LARGE_FILE_HEADER_SIZE; + sfd.trailer = NULL; + sfd.tlen = 0; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 5. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 6: partial small file from non-zero offset till end of file, with header + */ + sfd.fd = local_small_file_fd; + sfd.file_offset = SMALL_FILE_OFFSET_3; + sfd.file_nbytes = 0; /* data from offset to end-of-file */ + sfd.header = small_file_header; + sfd.hlen = SMALL_FILE_HEADER_SIZE; + sfd.trailer = NULL; + sfd.tlen = 0; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 6. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 7: partial large file at non-zero offset till end-of-file, with header + */ + sfd.fd = local_large_file_fd; + sfd.file_offset = LARGE_FILE_OFFSET_3; + sfd.file_nbytes = 0; /* data until end-of-file */ + sfd.header = large_file_header; + sfd.hlen = LARGE_FILE_HEADER_SIZE; + sfd.trailer = NULL; + sfd.tlen = 0; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 7. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 8: partial large file at non-zero page-aligned offset, + * with header and trailer + */ + sfd.fd = local_large_file_fd; + sfd.file_offset = LARGE_FILE_OFFSET_4; + sfd.file_nbytes = LARGE_FILE_LEN_4; + sfd.header = large_file_header; + sfd.hlen = LARGE_FILE_HEADER_SIZE; + sfd.trailer = large_file_trailer; + sfd.tlen = LARGE_FILE_TRAILER_SIZE; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_CLOSE_SOCKET, + PR_INTERVAL_NO_TIMEOUT); + slen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } +done: + if (local_small_file_fd != NULL) + PR_Close(local_small_file_fd); + if (local_large_file_fd != NULL) + PR_Close(local_large_file_fd); +} + +/* + * TransmitFile Server + * Server Thread + * Bind an address to a socket and listen for incoming connections + * Create worker threads to service clients + */ +static void +TransmitFile_Server(void *arg) +{ + PRThread **t = NULL; /* an array of PRThread pointers */ + Server_Param *sp = (Server_Param *) arg; + Serve_Client_Param *scp; + PRFileDesc *sockfd = NULL, *newsockfd; + PRNetAddr netaddr; + PRInt32 i; + + t = (PRThread**)PR_MALLOC(num_transmitfile_clients * sizeof(PRThread *)); + if (t == NULL) { + fprintf(stderr, "prsocket_test: run out of memory\n"); + failed_already=1; + goto exit; + } + /* + * Create a tcp socket + */ + if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) { + fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n"); + failed_already=1; + goto 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,"prsocket_test: ERROR - PR_Bind failed\n"); + failed_already=1; + perror("PR_Bind"); + goto exit; + } + + if (PR_Listen(sockfd, 32) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n"); + failed_already=1; + goto exit; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr, + "prsocket_test: ERROR - PR_GetSockName failed\n"); + failed_already=1; + goto exit; + } + + DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + tcp_server_addr.inet.family = netaddr.inet.family; + tcp_server_addr.inet.port = netaddr.inet.port; + tcp_server_addr.inet.ip = netaddr.inet.ip; + + /* + * Wake up parent thread because server address is bound and made + * available in the global variable 'tcp_server_addr' + */ + PR_PostSem(sp->addr_sem); + + for (i = 0; i < num_transmitfile_clients ; i++) { + /* test both null and non-null 'addr' argument to PR_Accept */ + PRNetAddr *addrp = (i%2 ? &netaddr: NULL); + + if ((newsockfd = PR_Accept(sockfd, addrp, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr, + "prsocket_test: ERROR - PR_Accept failed\n"); + failed_already=1; + goto exit; + } + /* test both regular and emulated PR_SendFile */ + if (i%2) { + PRFileDesc *layer = PR_CreateIOLayerStub( + emuSendFileIdentity, &emuSendFileMethods); + if (layer == NULL) { + fprintf(stderr, + "prsocket_test: ERROR - PR_CreateIOLayerStub failed\n"); + failed_already=1; + goto exit; + } + if (PR_PushIOLayer(newsockfd, PR_TOP_IO_LAYER, layer) + == PR_FAILURE) { + fprintf(stderr, + "prsocket_test: ERROR - PR_PushIOLayer failed\n"); + failed_already=1; + goto exit; + } + } + scp = PR_NEW(Serve_Client_Param); + if (scp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + goto exit; + } + + /* + * Start a Serve_Client thread for each incoming connection + */ + scp->sockfd = newsockfd; + scp->datalen = sp->datalen; + + t[i] = PR_CreateThread(PR_USER_THREAD, + Serve_TransmitFile_Client, (void *)scp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + if (t[i] == NULL) { + fprintf(stderr, + "prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + goto exit; + } + DPRINTF(("TransmitFile_Server: Created Serve_TransmitFile_Client = 0x%lx\n", t)); + } + + /* + * Wait for all the worker threads to end, so that we know + * they are no longer using the small and large file fd's. + */ + + for (i = 0; i < num_transmitfile_clients; i++) { + PR_JoinThread(t[i]); + } + +exit: + if (t) { + PR_DELETE(t); + } + if (sockfd) { + PR_Close(sockfd); + } + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(sp->exit_mon); + --(*sp->exit_counter); + PR_Notify(sp->exit_mon); + PR_ExitMonitor(sp->exit_mon); + DPRINTF(("TransmitFile_Server [0x%lx] exiting\n", PR_GetCurrentThread())); +} + +/* + * Socket_Misc_Test - test miscellaneous functions + * + */ +static PRInt32 +Socket_Misc_Test(void) +{ + PRIntn i, rv = 0, bytes, count, len; + PRThread *t; + PRSemaphore *server_sem; + Server_Param *sparamp; + Client_Param *cparamp; + PRMonitor *mon2; + PRInt32 datalen; + + /* + * We deliberately pick a buffer size that is not a nice multiple + * of 1024. + */ +#define TRANSMITFILE_BUF_SIZE (4 * 1024 - 11) + + typedef struct { + char data[TRANSMITFILE_BUF_SIZE]; + } file_buf; + file_buf *buf = NULL; + + /* + * create file(s) to be transmitted + */ + if ((PR_MkDir(TEST_DIR, 0777)) < 0) { + printf("prsocket_test failed to create dir %s\n",TEST_DIR); + failed_already=1; + return -1; + } + + small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777); + + if (small_file_fd == NULL) { + fprintf(stderr,"prsocket_test failed to create/open file %s\n", + SMALL_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } + buf = PR_NEW(file_buf); + if (buf == NULL) { + fprintf(stderr,"prsocket_test failed to allocate buffer\n"); + failed_already=1; + rv = -1; + goto done; + } + /* + * fill in random data + */ + for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) { + buf->data[i] = i; + } + count = 0; + do { + len = (SMALL_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ? + TRANSMITFILE_BUF_SIZE : (SMALL_FILE_SIZE - count); + bytes = PR_Write(small_file_fd, buf->data, len); + if (bytes <= 0) { + fprintf(stderr, + "prsocket_test failed to write to file %s\n", + SMALL_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } + count += bytes; + } while (count < SMALL_FILE_SIZE); +#ifdef XP_UNIX + /* + * map the small file; used in checking for data corruption + */ + small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ, + MAP_SHARED, small_file_fd->secret->md.osfd, 0); + if (small_file_addr == (void *) -1) { + fprintf(stderr,"prsocket_test failed to mmap file %s\n", + SMALL_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } +#endif + /* + * header for small file + */ + small_file_header = PR_MALLOC(SMALL_FILE_HEADER_SIZE); + if (small_file_header == NULL) { + fprintf(stderr,"prsocket_test failed to malloc header file\n"); + failed_already=1; + rv = -1; + goto done; + } + memset(small_file_header, (int) PR_IntervalNow(), + SMALL_FILE_HEADER_SIZE); + /* + * trailer for small file + */ + small_file_trailer = PR_MALLOC(SMALL_FILE_TRAILER_SIZE); + if (small_file_trailer == NULL) { + fprintf(stderr,"prsocket_test failed to malloc header trailer\n"); + failed_already=1; + rv = -1; + goto done; + } + memset(small_file_trailer, (int) PR_IntervalNow(), + SMALL_FILE_TRAILER_SIZE); + /* + * setup large file + */ + large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777); + + if (large_file_fd == NULL) { + fprintf(stderr,"prsocket_test failed to create/open file %s\n", + LARGE_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } + /* + * fill in random data + */ + for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) { + buf->data[i] = i; + } + count = 0; + do { + len = (LARGE_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ? + TRANSMITFILE_BUF_SIZE : (LARGE_FILE_SIZE - count); + bytes = PR_Write(large_file_fd, buf->data, len); + if (bytes <= 0) { + fprintf(stderr, + "prsocket_test failed to write to file %s: (%ld, %ld)\n", + LARGE_FILE_NAME, + PR_GetError(), PR_GetOSError()); + failed_already=1; + rv = -1; + goto done; + } + count += bytes; + } while (count < LARGE_FILE_SIZE); +#ifdef XP_UNIX + /* + * map the large file; used in checking for data corruption + */ + large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ, + MAP_SHARED, large_file_fd->secret->md.osfd, 0); + if (large_file_addr == (void *) -1) { + fprintf(stderr,"prsocket_test failed to mmap file %s\n", + LARGE_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } +#endif + /* + * header for large file + */ + large_file_header = PR_MALLOC(LARGE_FILE_HEADER_SIZE); + if (large_file_header == NULL) { + fprintf(stderr,"prsocket_test failed to malloc header file\n"); + failed_already=1; + rv = -1; + goto done; + } + memset(large_file_header, (int) PR_IntervalNow(), + LARGE_FILE_HEADER_SIZE); + /* + * trailer for large file + */ + large_file_trailer = PR_MALLOC(LARGE_FILE_TRAILER_SIZE); + if (large_file_trailer == NULL) { + fprintf(stderr,"prsocket_test failed to malloc header trailer\n"); + failed_already=1; + rv = -1; + goto done; + } + memset(large_file_trailer, (int) PR_IntervalNow(), + LARGE_FILE_TRAILER_SIZE); + + datalen = tcp_mesg_size; + thread_count = 0; + /* + * start the server thread + */ + sparamp = PR_NEW(Server_Param); + if (sparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + rv = -1; + goto done; + } + server_sem = PR_NewSem(0); + if (server_sem == NULL) { + fprintf(stderr,"prsocket_test: PR_NewSem failed\n"); + failed_already=1; + rv = -1; + goto done; + } + mon2 = PR_NewMonitor(); + if (mon2 == NULL) { + fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n"); + failed_already=1; + rv = -1; + goto done; + } + PR_EnterMonitor(mon2); + + sparamp->addr_sem = server_sem; + sparamp->exit_mon = mon2; + sparamp->exit_counter = &thread_count; + sparamp->datalen = datalen; + t = PR_CreateThread(PR_USER_THREAD, + TransmitFile_Server, (void *)sparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + rv = -1; + goto done; + } + DPRINTF(("Created TCP server = 0x%x\n", t)); + thread_count++; + + /* + * wait till the server address is setup + */ + PR_WaitSem(server_sem); + + /* + * Now start a bunch of client threads + */ + + cparamp = PR_NEW(Client_Param); + if (cparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + rv = -1; + goto done; + } + cparamp->server_addr = tcp_server_addr; + cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + cparamp->exit_mon = mon2; + cparamp->exit_counter = &thread_count; + cparamp->datalen = datalen; + for (i = 0; i < num_transmitfile_clients; i++) { + t = create_new_thread(PR_USER_THREAD, + TransmitFile_Client, (void *) cparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, i); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + rv = -1; + failed_already=1; + goto done; + } + DPRINTF(("Created TransmitFile client = 0x%lx\n", t)); + thread_count++; + } + /* Wait for server and client threads to exit */ + while (thread_count) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("Socket_Misc_Test - thread_count = %d\n", thread_count)); + } + PR_ExitMonitor(mon2); +done: + if (buf) { + PR_DELETE(buf); + } +#ifdef XP_UNIX + 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); + if ((PR_Delete(SMALL_FILE_NAME)) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: failed to unlink file %s\n", + SMALL_FILE_NAME); + failed_already=1; + } + if ((PR_Delete(LARGE_FILE_NAME)) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: failed to unlink file %s\n", + LARGE_FILE_NAME); + failed_already=1; + } + if ((PR_RmDir(TEST_DIR)) == PR_FAILURE) { + fprintf(stderr,"prsocket_test failed to rmdir %s: (%ld, %ld)\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + failed_already=1; + } + + printf("%-29s%s","Socket_Misc_Test",":"); + printf("%2d Server %2d Clients\n",1, num_transmitfile_clients); + printf("%30s Sizes of Transmitted Files - %4d KB, %2d MB \n",":", + SMALL_FILE_SIZE/1024, LARGE_FILE_SIZE/(1024 * 1024)); + + + return rv; +} +/************************************************************************/ + +/* + * Test Socket NSPR APIs + */ + +int +main(int argc, char **argv) +{ + /* + * -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 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("socket.log"); +#endif + PR_SetConcurrency(4); + + emuSendFileIdentity = PR_GetUniqueIdentity("Emulated SendFile"); + emuSendFileMethods = *PR_GetDefaultIOMethods(); + emuSendFileMethods.transmitfile = emu_TransmitFile; + emuSendFileMethods.sendfile = emu_SendFile; + + /* + * run client-server test with TCP, Ipv4-Ipv4 + */ + printf("TCP Client/Server Test - IPv4/Ipv4\n"); + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); + /* + * client-server test, Ipv6-Ipv4 + */ + client_domain = PR_AF_INET6; + printf("TCP Client/Server Test - IPv6/Ipv4\n"); + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); + /* + * client-server test, Ipv4-Ipv6 + */ + client_domain = PR_AF_INET; + server_domain = PR_AF_INET6; + printf("TCP Client/Server Test - IPv4/Ipv6\n"); + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); + /* + * client-server test, Ipv6-Ipv6 + */ + client_domain = PR_AF_INET6; + server_domain = PR_AF_INET6; + printf("TCP Client/Server Test - IPv6/Ipv6\n"); + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); + test_cancelio = 0; + /* + * run client-server test with UDP, IPv4/IPv4 + */ + printf("UDP Client/Server Test - IPv4/Ipv4\n"); + client_domain = PR_AF_INET; + server_domain = PR_AF_INET; + if (UDP_Socket_Client_Server_Test() < 0) { + printf("UDP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("UDP_Socket_Client_Server_Test Passed\n"); + /* + * run client-server test with UDP, IPv6/IPv4 + */ + printf("UDP Client/Server Test - IPv6/Ipv4\n"); + client_domain = PR_AF_INET6; + server_domain = PR_AF_INET; + if (UDP_Socket_Client_Server_Test() < 0) { + printf("UDP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("UDP_Socket_Client_Server_Test Passed\n"); + /* + * run client-server test with UDP,IPv4-IPv6 + */ + printf("UDP Client/Server Test - IPv4/Ipv6\n"); + client_domain = PR_AF_INET; + server_domain = PR_AF_INET6; + if (UDP_Socket_Client_Server_Test() < 0) { + printf("UDP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("UDP_Socket_Client_Server_Test Passed\n"); + /* + * run client-server test with UDP,IPv6-IPv6 + */ + printf("UDP Client/Server Test - IPv6/Ipv6\n"); + client_domain = PR_AF_INET6; + server_domain = PR_AF_INET6; + if (UDP_Socket_Client_Server_Test() < 0) { + printf("UDP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("UDP_Socket_Client_Server_Test Passed\n"); + /* + * Misc socket tests - including transmitfile, etc. + */ + +#if !defined(WIN16) + /* +** The 'transmit file' test does not run because +** transmit file is not implemented in NSPR yet. +** +*/ + if (Socket_Misc_Test() < 0) { + printf("Socket_Misc_Test failed\n"); + failed_already=1; + goto done; + } else + printf("Socket_Misc_Test passed\n"); + + /* + * run client-server test with TCP again to test + * recycling used sockets from PR_TransmitFile(). + */ + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); +#endif + +done: + PR_Cleanup(); + if (failed_already) return 1; + else return 0; +} diff --git a/nsprpub/pr/tests/sockopt.c b/nsprpub/pr/tests/sockopt.c new file mode 100644 index 00000000000..905e23875d0 --- /dev/null +++ b/nsprpub/pr/tests/sockopt.c @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "prio.h" +#include "prinit.h" +#include "prprf.h" +#ifdef XP_MAC +#include "probslet.h" +#else +#include "obsolete/probslet.h" +#endif + +#include "plerror.h" + +static PRFileDesc *err = NULL; +static PRBool failed = PR_FALSE; + +#ifndef XP_MAC +static void Failed(const char *msg1, const char *msg2) +{ + if (NULL != msg1) PR_fprintf(err, "%s ", msg1); + PL_FPrintError(err, msg2); + failed = PR_TRUE; +} /* Failed */ + +#else +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +static void Failed(const char *msg1, const char *msg2) +{ + if (NULL != msg1) printf("%s ", msg1); + printf (msg2); + failed |= PR_TRUE; +} /* Failed */ + +#endif + +static PRSockOption Incr(PRSockOption *option) +{ + PRIntn val = ((PRIntn)*option) + 1; + *option = (PRSockOption)val; + return (PRSockOption)val; +} /* Incr */ + +PRIntn main(PRIntn argc, char *argv) +{ + PRStatus rv; + PRFileDesc *udp = PR_NewUDPSocket(); + PRFileDesc *tcp = PR_NewTCPSocket(); + const char *tag[] = + { + "PR_SockOpt_Nonblocking", /* nonblocking io */ + "PR_SockOpt_Linger", /* linger on close if data present */ + "PR_SockOpt_Reuseaddr", /* allow local address reuse */ + "PR_SockOpt_Keepalive", /* keep connections alive */ + "PR_SockOpt_RecvBufferSize", /* send buffer size */ + "PR_SockOpt_SendBufferSize", /* receive buffer size */ + + "PR_SockOpt_IpTimeToLive", /* time to live */ + "PR_SockOpt_IpTypeOfService", /* type of service and precedence */ + + "PR_SockOpt_AddMember", /* add an IP group membership */ + "PR_SockOpt_DropMember", /* drop an IP group membership */ + "PR_SockOpt_McastInterface", /* multicast interface address */ + "PR_SockOpt_McastTimeToLive", /* multicast timetolive */ + "PR_SockOpt_McastLoopback", /* multicast loopback */ + + "PR_SockOpt_NoDelay", /* don't delay send to coalesce packets */ + "PR_SockOpt_MaxSegment", /* maximum segment size */ + "PR_SockOpt_Broadcast", /* Enable broadcast */ + "PR_SockOpt_Last" + }; + + err = PR_GetSpecialFD(PR_StandardError); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("sockopt.log"); +#endif + + if (NULL == udp) Failed("PR_NewUDPSocket()", NULL); + else if (NULL == tcp) Failed("PR_NewTCPSocket()", NULL); + else + { + PRSockOption option; + PRUint32 segment = 1024; + PRNetAddr addr; + + rv = PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr); + if (PR_FAILURE == rv) Failed("PR_InitializeNetAddr()", NULL); + rv = PR_Bind(udp, &addr); + if (PR_FAILURE == rv) Failed("PR_Bind()", NULL); + for(option = PR_SockOpt_Linger; option < PR_SockOpt_Last; Incr(&option)) + { + PRSocketOptionData data; + PRFileDesc *fd = tcp; + data.option = option; + switch (option) + { + case PR_SockOpt_Nonblocking: + data.value.non_blocking = PR_TRUE; + break; + case PR_SockOpt_Linger: + data.value.linger.polarity = PR_TRUE; + data.value.linger.linger = PR_SecondsToInterval(2); + break; + case PR_SockOpt_Reuseaddr: + data.value.reuse_addr = PR_TRUE; + break; + case PR_SockOpt_Keepalive: + data.value.keep_alive = PR_TRUE; + break; + case PR_SockOpt_RecvBufferSize: + data.value.recv_buffer_size = segment; + break; + case PR_SockOpt_SendBufferSize: + data.value.send_buffer_size = segment; + break; + case PR_SockOpt_IpTimeToLive: + data.value.ip_ttl = 64; + break; + case PR_SockOpt_IpTypeOfService: + data.value.tos = 0; + break; + case PR_SockOpt_McastTimeToLive: + fd = udp; + data.value.mcast_ttl = 4; + break; + case PR_SockOpt_McastLoopback: + fd = udp; + data.value.mcast_loopback = PR_TRUE; + break; + case PR_SockOpt_NoDelay: + data.value.no_delay = PR_TRUE; + break; +#ifndef WIN32 + case PR_SockOpt_MaxSegment: + data.value.max_segment = segment; + break; +#endif + case PR_SockOpt_Broadcast: + fd = udp; + data.value.broadcast = PR_TRUE; + break; + default: continue; + } + + /* + * TCP_MAXSEG can only be read, not set + */ + if (option != PR_SockOpt_MaxSegment) { +#ifdef WIN32 + if (option != PR_SockOpt_McastLoopback) +#endif + { + rv = PR_SetSocketOption(fd, &data); + if (PR_FAILURE == rv) + Failed("PR_SetSocketOption()", tag[option]); + } + } + + rv = PR_GetSocketOption(fd, &data); + if (PR_FAILURE == rv) Failed("PR_GetSocketOption()", tag[option]); + } + PR_Close(udp); + PR_Close(tcp); + } +#ifndef XP_MAC + PR_fprintf(err, "%s\n", (failed) ? "FAILED" : "PASSED"); +#else + printf("%s\n", (failed) ? "FAILED" : "PASSED"); +#endif + return (failed) ? 1 : 0; +} /* main */ + +/* sockopt.c */ + diff --git a/nsprpub/pr/tests/sockping.c b/nsprpub/pr/tests/sockping.c new file mode 100644 index 00000000000..093651389c8 --- /dev/null +++ b/nsprpub/pr/tests/sockping.c @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: sockping.c + * + * Description: + * This test runs in conjunction with the sockpong test. + * This test creates a socket pair and passes one socket + * to the sockpong test. Then this test writes "ping" to + * to the sockpong test and the sockpong test writes "pong" + * back. To run this pair of tests, just invoke sockping. + * + * Tested areas: process creation, socket pairs, file + * descriptor inheritance. + */ + +#include "prerror.h" +#include "prio.h" +#include "prproces.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +static char *child_argv[] = { "sockpong", NULL }; + +int main() +{ + PRFileDesc *sock[2]; + PRStatus status; + PRProcess *process; + PRProcessAttr *attr; + char buf[1024]; + PRInt32 nBytes; + PRInt32 exitCode; + int idx; + + status = PR_NewTCPSocketPair(sock); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_NewTCPSocketPair failed\n"); + exit(1); + } + + status = PR_SetFDInheritable(sock[0], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + status = PR_SetFDInheritable(sock[1], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + + attr = PR_NewProcessAttr(); + if (attr == NULL) { + fprintf(stderr, "PR_NewProcessAttr failed\n"); + exit(1); + } + + status = PR_ProcessAttrSetInheritableFD(attr, sock[1], "SOCKET"); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n"); + exit(1); + } + + process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr); + if (process == NULL) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + PR_DestroyProcessAttr(attr); + status = PR_Close(sock[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + strcpy(buf, "ping"); + printf("ping process: sending \"%s\"\n", buf); + nBytes = PR_Write(sock[0], buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(sock[0], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("ping process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "pong") != 0) { + fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n", + buf); + exit(1); + } + } + + status = PR_Close(sock[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_WaitProcess(process, &exitCode); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exitCode == 0) { + printf("PASS\n"); + return 0; + } else { + printf("FAIL\n"); + return 1; + } +} diff --git a/nsprpub/pr/tests/sockpong.c b/nsprpub/pr/tests/sockpong.c new file mode 100644 index 00000000000..e54e34233ce --- /dev/null +++ b/nsprpub/pr/tests/sockpong.c @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: sockpong.c + * + * Description: + * This test runs in conjunction with the sockping test. + * The sockping test creates a socket pair and passes one + * socket to this test. Then the sockping test writes + * "ping" to this test and this test writes "pong" back. + * To run this pair of tests, just invoke sockping. + * + * Tested areas: process creation, socket pairs, file + * descriptor inheritance. + */ + +#include "prerror.h" +#include "prio.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +int main() +{ + PRFileDesc *sock; + PRStatus status; + char buf[1024]; + PRInt32 nBytes; + int idx; + + sock = PR_GetInheritedFD("SOCKET"); + if (sock == NULL) { + fprintf(stderr, "PR_GetInheritedFD failed\n"); + exit(1); + } + status = PR_SetFDInheritable(sock, PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(sock, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("pong process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "ping") != 0) { + fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n", + buf); + exit(1); + } + + strcpy(buf, "pong"); + printf("pong process: sending \"%s\"\n", buf); + nBytes = PR_Write(sock, buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed\n"); + exit(1); + } + } + + status = PR_Close(sock); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + return 0; +} diff --git a/nsprpub/pr/tests/sprintf.c b/nsprpub/pr/tests/sprintf.c new file mode 100644 index 00000000000..7fe2ac1949c --- /dev/null +++ b/nsprpub/pr/tests/sprintf.c @@ -0,0 +1,454 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: sprintf.c + * Description: + * This is a test program for the PR_snprintf() functions defined + * in prprf.c. This test program is based on ns/nspr/tests/sprintf.c, + * revision 1.10. + * Modification History: + * 20-May-1997 AGarcia replaced printf statment to return PASS\n. This is to be used by the + * regress tool parsing routine. + ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to + * recognize the return code from tha main program. + */ + +#include "prinit.h" +#include "prprf.h" +#include "prlog.h" +#include "prlong.h" +#include +#include +#include + +#define countof(a) (sizeof(a)/sizeof(a[0])) + +static char sbuf[20000]; + + +/* +** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf. +** Make sure the results are identical +*/ +static void test_i(char *pattern, int i) +{ + char *s; + char buf[200]; + int n; + + /* try all three routines */ + s = PR_smprintf(pattern, i); + PR_ASSERT(s != 0); + n = PR_snprintf(buf, sizeof(buf), pattern, i); + PR_ASSERT(n <= sizeof(buf)); + sprintf(sbuf, pattern, i); + + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0) || + (strncmp(s, sbuf, sizeof(sbuf)) != 0)) { + fprintf(stderr, + "pattern='%s' i=%d\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, i, s, buf, sbuf); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +} + +static void TestI(void) +{ + static int nums[] = { + 0, 1, -1, 10, -10, + 32767, -32768, + }; + static char *signs[] = { + "", + "0", "-", "+", " ", + "0-", "0+", "0 ", "-0", "-+", "- ", + "+0", "+-", "+ ", " 0", " -", " +", + "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +", + "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +", + "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -", + " 0-", " 0+", " -0", " -+", " +0", " +-", + "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-", + "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0", + "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0", + " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0", + }; + static char *precs[] = { + "", "3", "5", "43", + "7.3", "7.5", "7.11", "7.43", + }; + static char *formats[] = { + "d", "o", "x", "u", + "hd", "ho", "hx", "hu" + }; + int f, s, n, p; + char fmt[20]; + + for (f = 0; f < countof(formats); f++) { + for (s = 0; s < countof(signs); s++) { + for (p = 0; p < countof(precs); p++) { + fmt[0] = '%'; + fmt[1] = 0; + if (signs[s]) strcat(fmt, signs[s]); + if (precs[p]) strcat(fmt, precs[p]); + if (formats[f]) strcat(fmt, formats[f]); + for (n = 0; n < countof(nums); n++) { + test_i(fmt, nums[n]); + } + } + } + } +} + +/************************************************************************/ + +/* +** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf. +** Make sure the results are identical +*/ +static void test_l(char *pattern, char *spattern, PRInt32 l) +{ + char *s; + char buf[200]; + int n; + + /* try all three routines */ + s = PR_smprintf(pattern, l); + PR_ASSERT(s != 0); + n = PR_snprintf(buf, sizeof(buf), pattern, l); + PR_ASSERT(n <= sizeof(buf)); + sprintf(sbuf, spattern, l); + + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0) || + (strncmp(s, sbuf, sizeof(sbuf)) != 0)) { + fprintf(stderr, + "pattern='%s' l=%ld\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, l, s, buf, sbuf); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +} + +static void TestL(void) +{ + static PRInt32 nums[] = { + 0, + 1, + -1, + 10, + -10, + 32767, + -32768, + PR_INT32(0x7fffffff), /* 2147483647L */ + -1 - PR_INT32(0x7fffffff) /* -2147483648L */ + }; + static char *signs[] = { + "", + "0", "-", "+", " ", + "0-", "0+", "0 ", "-0", "-+", "- ", + "+0", "+-", "+ ", " 0", " -", " +", + "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +", + "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +", + "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -", + " 0-", " 0+", " -0", " -+", " +0", " +-", + "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-", + "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0", + "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0", + " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0", + }; + static char *precs[] = { + "", "3", "5", "43", + ".3", ".43", + "7.3", "7.5", "7.11", "7.43", + }; + static char *formats[] = { "ld", "lo", "lx", "lu" }; + +#if PR_BYTES_PER_INT == 4 + static char *sformats[] = { "d", "o", "x", "u" }; +#elif PR_BYTES_PER_LONG == 4 + static char *sformats[] = { "ld", "lo", "lx", "lu" }; +#else +#error Neither int nor long is 4 bytes on this platform +#endif + + int f, s, n, p; + char fmt[40], sfmt[40]; + + for (f = 0; f < countof(formats); f++) { + for (s = 0; s < countof(signs); s++) { + for (p = 0; p < countof(precs); p++) { + fmt[0] = '%'; + fmt[1] = 0; + if (signs[s]) strcat(fmt, signs[s]); + if (precs[p]) strcat(fmt, precs[p]); + strcpy(sfmt, fmt); + if (formats[f]) strcat(fmt, formats[f]); + if (sformats[f]) strcat(sfmt, sformats[f]); + for (n = 0; n < countof(nums); n++) { + test_l(fmt, sfmt, nums[n]); + } + } + } + } +} + +/************************************************************************/ + +/* +** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf. +** Make sure the results are identical +*/ +static void test_ll(char *pattern, char *spattern, PRInt64 l) +{ + char *s; + char buf[200]; + int n; + + /* try all three routines */ + s = PR_smprintf(pattern, l); + PR_ASSERT(s != 0); + n = PR_snprintf(buf, sizeof(buf), pattern, l); + PR_ASSERT(n <= sizeof(buf)); +#if defined(HAVE_LONG_LONG) + sprintf(sbuf, spattern, l); + + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0) || + (strncmp(s, sbuf, sizeof(sbuf)) != 0)) { +#if PR_BYTES_PER_LONG == 8 +#define FORMAT_SPEC "%ld" +#elif defined(WIN16) +#define FORMAT_SPEC "%Ld" +#elif defined(WIN32) +#define FORMAT_SPEC "%I64d" +#else +#define FORMAT_SPEC "%lld" +#endif + fprintf(stderr, + "pattern='%s' ll=" FORMAT_SPEC "\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, l, s, buf, sbuf); + printf("FAIL\n"); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +#else + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0)) { + fprintf(stderr, + "pattern='%s'\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, s, buf, sbuf); + printf("FAIL\n"); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +#endif +} + +static void TestLL(void) +{ + static PRInt64 nums[] = { + LL_INIT(0, 0), + LL_INIT(0, 1), + LL_INIT(0xffffffff, 0xffffffff), /* -1 */ + LL_INIT(0, 10), + LL_INIT(0xffffffff, 0xfffffff6), /* -10 */ + LL_INIT(0, 32767), + LL_INIT(0xffffffff, 0xffff8000), /* -32768 */ + LL_INIT(0, 0x7fffffff), /* 2147483647 */ + LL_INIT(0xffffffff, 0x80000000), /* -2147483648 */ + LL_INIT(0x7fffffff, 0xffffffff), /* 9223372036854775807 */ + LL_INIT(0x80000000, 0) /* -9223372036854775808 */ + }; + + static char *signs[] = { + "", + "0", "-", "+", " ", + "0-", "0+", "0 ", "-0", "-+", "- ", + "+0", "+-", "+ ", " 0", " -", " +", + "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +", + "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +", + "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -", + " 0-", " 0+", " -0", " -+", " +0", " +-", + "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-", + "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0", + "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0", + " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0", + }; + static char *precs[] = { + "", "3", "5", "43", + ".3", ".43", + "7.3", "7.5", "7.11", "7.43", + }; + static char *formats[] = { "lld", "llo", "llx", "llu" }; + +#if PR_BYTES_PER_LONG == 8 + static char *sformats[] = { "ld", "lo", "lx", "lu" }; +#elif defined(WIN16) + /* Watcom uses the format string "%Ld" instead of "%lld". */ + static char *sformats[] = { "Ld", "Lo", "Lx", "Lu" }; +#elif defined(WIN32) + static char *sformats[] = { "I64d", "I64o", "I64x", "I64u" }; +#else + static char *sformats[] = { "lld", "llo", "llx", "llu" }; +#endif + + int f, s, n, p; + char fmt[40], sfmt[40]; + + for (f = 0; f < countof(formats); f++) { + for (s = 0; s < countof(signs); s++) { + for (p = 0; p < countof(precs); p++) { + fmt[0] = '%'; + fmt[1] = 0; + if (signs[s]) strcat(fmt, signs[s]); + if (precs[p]) strcat(fmt, precs[p]); + strcpy(sfmt, fmt); + if (formats[f]) strcat(fmt, formats[f]); + if (sformats[f]) strcat(sfmt, sformats[f]); + for (n = 0; n < countof(nums); n++) { + test_ll(fmt, sfmt, nums[n]); + } + } + } + } +} + +/************************************************************************/ + +/* +** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf. +** Make sure the results are identical +*/ +static void test_s(char *pattern, char *ss) +{ + char *s; + unsigned char before[8]; + char buf[200]; + unsigned char after[8]; + int n; + + memset(before, 0xBB, 8); + memset(after, 0xAA, 8); + + /* try all three routines */ + s = PR_smprintf(pattern, ss); + PR_ASSERT(s != 0); + n = PR_snprintf(buf, sizeof(buf), pattern, ss); + PR_ASSERT(n <= sizeof(buf)); + sprintf(sbuf, pattern, ss); + + for (n = 0; n < 8; n++) { + PR_ASSERT(before[n] == 0xBB); + PR_ASSERT(after[n] == 0xAA); + } + + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0) || + (strncmp(s, sbuf, sizeof(sbuf)) != 0)) { + fprintf(stderr, + "pattern='%s' ss=%.20s\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, ss, s, buf, sbuf); + printf("FAIL\n"); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +} + +static void TestS(void) +{ + static char *strs[] = { + "", + "a", + "abc", + "abcde", + "abcdefABCDEF", + "abcdefghijklmnopqrstuvwxyz0123456789!@#$" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$" + "abcdefghijklmnopqrstuvwxyz0123456789!@#$", + }; + /* '0' is not relevant to printing strings */ + static char *signs[] = { + "", + "-", "+", " ", + "-+", "- ", "+-", "+ ", " -", " +", + "-+ ", "- +", "+- ", "+ -", " -+", " +-", + }; + static char *precs[] = { + "", "3", "5", "43", + ".3", ".43", + "7.3", "7.5", "7.11", "7.43", + }; + static char *formats[] = { "s" }; + int f, s, n, p; + char fmt[40]; + + for (f = 0; f < countof(formats); f++) { + for (s = 0; s < countof(signs); s++) { + for (p = 0; p < countof(precs); p++) { + fmt[0] = '%'; + fmt[1] = 0; + if (signs[s]) strcat(fmt+strlen(fmt), signs[s]); + if (precs[p]) strcat(fmt+strlen(fmt), precs[p]); + if (formats[f]) strcat(fmt+strlen(fmt), formats[f]); + for (n = 0; n < countof(strs); n++) { + test_s(fmt, strs[n]); + } + } + } + } +} + +/************************************************************************/ + +int main(int argc, char **argv) +{ + PR_STDIO_INIT(); + TestI(); + TestL(); + TestLL(); + TestS(); + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/sproc_ch.c b/nsprpub/pr/tests/sproc_ch.c new file mode 100644 index 00000000000..98dee0836d4 --- /dev/null +++ b/nsprpub/pr/tests/sproc_ch.c @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Test sproc_ch.c + * + * The purpose of this test and the sproc_p.c test is to test the shutdown + * of all the IRIX sprocs in a program when one of them dies due to an error. + * + * There are three sprocs in this test: the parent, the child, and the + * grandchild. The parent and child sprocs never stop on their own. + * The grandchild sproc gets a segmentation fault and dies. You should + * You should use "ps" to see if the parent and child sprocs are killed + * after the grandchild dies. + */ + +#include "prinit.h" +#include + +#if !defined(IRIX) + +int main() +{ + printf("This test applies to IRIX only.\n"); + return 0; +} + +#else /* IRIX */ + +#include "prthread.h" +#include +#include + +void SegFault(void *unused) +{ + int *p = 0; + + printf("The grandchild sproc has pid %d.\n", getpid()); + printf("The grandchild sproc will get a segmentation fault and die.\n"); + printf("The parent and child sprocs should be killed after the " + "grandchild sproc dies.\n"); + printf("Use 'ps' to make sure this is so.\n"); + fflush(stdout); + /* Force a segmentation fault */ + *p = 0; +} + +void NeverStops(void *unused) +{ + int i = 0; + + printf("The child sproc has pid %d.\n", getpid()); + printf("The child sproc won't stop on its own.\n"); + fflush(stdout); + + /* create the grandchild sproc */ + PR_CreateThread(PR_USER_THREAD, SegFault, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + while (1) { + i++; + } +} + +int main() +{ + int i= 0; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + printf("The parent sproc has pid %d.\n", getpid()); + printf("The parent sproc won't stop on its own.\n"); + fflush(stdout); + + /* create the child sproc */ + PR_CreateThread(PR_USER_THREAD, NeverStops, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + while (1) { + i++; + } + return 0; +} + +#endif /* IRIX */ diff --git a/nsprpub/pr/tests/sproc_p.c b/nsprpub/pr/tests/sproc_p.c new file mode 100644 index 00000000000..e8ded66b11e --- /dev/null +++ b/nsprpub/pr/tests/sproc_p.c @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Test sproc_p.c + * + * The purpose of this test and the sproc_ch.c test is to test the shutdown + * of all the IRIX sprocs in a program when one of them dies due to an error. + * + * In this test, the parent sproc gets a segmentation fault and dies. + * The child sproc never stops on its own. You should use "ps" to see if + * the child sproc is killed after the parent dies. + */ + +#include "prinit.h" +#include + +#if !defined(IRIX) + +int main() +{ + printf("This test applies to IRIX only.\n"); + return 0; +} + +#else /* IRIX */ + +#include "prthread.h" +#include +#include + +void NeverStops(void *unused) +{ + int i = 0; + + printf("The child sproc has pid %d.\n", getpid()); + printf("The child sproc won't stop on its own.\n"); + fflush(stdout); + + /* I never stop */ + while (1) { + i++; + } +} + +int main() +{ + int *p = 0; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + printf("The parent sproc has pid %d.\n", getpid()); + printf("The parent sproc will first create a child sproc.\n"); + printf("Then the parent sproc will get a segmentation fault and die.\n"); + printf("The child sproc should be killed after the parent sproc dies.\n"); + printf("Use 'ps' to make sure this is so.\n"); + fflush(stdout); + + PR_CreateThread(PR_USER_THREAD, NeverStops, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + /* Force a segmentation fault */ + *p = 0; + return 0; +} + +#endif /* IRIX */ diff --git a/nsprpub/pr/tests/stack.c b/nsprpub/pr/tests/stack.c new file mode 100644 index 00000000000..c47cb71f921 --- /dev/null +++ b/nsprpub/pr/tests/stack.c @@ -0,0 +1,310 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* + * + * 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 100 +#define DEFAULT_LOOP_CNT 10000 + +/* + * 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; + PRInt32 loops; +} 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; + PRInt32 loops = DEFAULT_LOOP_CNT; + PRThread **threads; + stack_data *thread_args; + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:l:"); + + 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; + case 'l': /* loop count */ + loops = 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].loops = loops; + 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, loops; + DataRecord *Items, *Item; + PRStack *list1, *list2; + PRStackElem *node; + stack_data *arg = (stack_data *) thread_arg; + + val = arg->initial_data_value; + cnt = arg->data_cnt; + loops = arg->loops; + 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++; + } + + /* + * pop data records from list1 and add them back to list1 + * generates contention for the stack accesses + */ + while (loops-- > 0) { + 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(list1, node); + } + } + /* + * 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/nsprpub/pr/tests/stat.c b/nsprpub/pr/tests/stat.c new file mode 100644 index 00000000000..73803d05750 --- /dev/null +++ b/nsprpub/pr/tests/stat.c @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Program to test different ways to get file info; right now it + * only works for solaris and OS/2. + * + */ +#include "nspr.h" +#include "prpriv.h" +#include "prinrval.h" + +#include +#include +#include + +#ifdef XP_OS2 +#include +#include +#include +#endif + +#define DEFAULT_COUNT 100000 +PRInt32 count; + +#ifndef XP_PC +char *filename = "/etc/passwd"; +#else +char *filename = "..\\stat.c"; +#endif + +static void statPRStat(void) +{ + PRFileInfo finfo; + PRInt32 index = count; + + for (;index--;) { + PR_GetFileInfo(filename, &finfo); + } +} + +static void statStat(void) +{ + struct stat finfo; + PRInt32 index = count; + + for (;index--;) { + stat(filename, &finfo); + } +} + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + PRInt32 tot; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + tot = PR_IntervalToMilliseconds(stop-start); + + printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot); +} + +void main(int argc, char **argv) +{ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (argc > 1) { + count = atoi(argv[1]); + } else { + count = DEFAULT_COUNT; + } + + Measure(statPRStat, "time to call PR_GetFileInfo()"); + Measure(statStat, "time to call stat()"); + + PR_Cleanup(); +} diff --git a/nsprpub/pr/tests/stdio.c b/nsprpub/pr/tests/stdio.c new file mode 100644 index 00000000000..d0d84e4ec1f --- /dev/null +++ b/nsprpub/pr/tests/stdio.c @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: stdio.c + * Description: testing the "special" fds + * Modification History: + * 20-May-1997 AGarcia - Replace Test succeeded status with PASS. This is used by the + * regress tool parsing code. + ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. + */ + + +#include "prlog.h" +#include "prinit.h" +#include "prio.h" + +#include +#include + +static PRIntn PR_CALLBACK stdio(PRIntn argc, char **argv) +{ + PRInt32 rv; + + PRFileDesc *out = PR_GetSpecialFD(PR_StandardOutput); + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + + rv = PR_Write( + out, "This to standard out\n", + strlen("This to standard out\n")); + PR_ASSERT((PRInt32)strlen("This to standard out\n") == rv); + rv = PR_Write( + err, "This to standard err\n", + strlen("This to standard err\n")); + PR_ASSERT((PRInt32)strlen("This to standard err\n") == rv); + + return 0; + +} /* stdio */ + +int main(int argc, char **argv) +{ + PR_STDIO_INIT(); + return PR_Initialize(stdio, argc, argv, 0); +} /* main */ + + +/* stdio.c */ diff --git a/nsprpub/pr/tests/str2addr.c b/nsprpub/pr/tests/str2addr.c new file mode 100644 index 00000000000..b1d4cf4acc8 --- /dev/null +++ b/nsprpub/pr/tests/str2addr.c @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: str2addr.c + * Description: a test for PR_StringToNetAddr + */ + +#include "nspr.h" + +#include +#include + +/* Address string to convert */ +#define DEFAULT_IPV4_ADDR_STR "207.200.73.41" + +/* Expected conversion result, in network byte order */ +static unsigned char default_ipv4_addr[] = {207, 200, 73, 41}; + +int main(int argc, char **argv) +{ + PRNetAddr addr; + const char *addrStr; + unsigned char *bytes; + int idx; + + addrStr = DEFAULT_IPV4_ADDR_STR; + if (PR_StringToNetAddr(addrStr, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_StringToNetAddr failed\n"); + exit(1); + } + if (addr.inet.family != PR_AF_INET) { + fprintf(stderr, "addr.inet.family should be %d but is %d\n", + PR_AF_INET, addr.inet.family); + exit(1); + } + bytes = (unsigned char *) &addr.inet.ip; + for (idx = 0; idx < 4; idx++) { + if (bytes[idx] != default_ipv4_addr[idx]) { + fprintf(stderr, "byte %d of IPv4 addr should be %d but is %d\n", + idx, default_ipv4_addr[idx], bytes[idx]); + exit(1); + } + } + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/strod.c b/nsprpub/pr/tests/strod.c new file mode 100644 index 00000000000..242617a7175 --- /dev/null +++ b/nsprpub/pr/tests/strod.c @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prinit.h" +#include "prio.h" +#include "prprf.h" +#include "prdtoa.h" +#include "plgetopt.h" + +#include + +static void Help(void) +{ + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PR_fprintf(err, "Usage: /.strod [-n n] [-l n] [-h]\n"); + PR_fprintf(err, "\t-n n Number to translate (default: 1234567890123456789)\n"); + PR_fprintf(err, "\t-l n Times to loop the test (default: 1)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRIntn loops = 1; + PRFloat64 answer; + const char *number = "1234567890123456789"; + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PLOptState *opt = PL_CreateOptState(argc, argv, "hc:l:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'n': /* number to translate */ + number = opt->value; + break; + case 'l': /* number of times to run the tests */ + loops = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_fprintf(err, "Settings\n"); + PR_fprintf(err, "\tNumber to translate %s\n", number); + PR_fprintf(err, "\tLoops to run test: %d\n", loops); + + while (loops--) + { + answer = PR_strtod(number, NULL); + PR_fprintf(err, "Translation = %20.0f\n", answer); + } + return 0; +} + + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/nsprpub/pr/tests/suspend.c b/nsprpub/pr/tests/suspend.c new file mode 100644 index 00000000000..44ba6f8712e --- /dev/null +++ b/nsprpub/pr/tests/suspend.c @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifdef XP_BEOS +#include +int main() +{ + printf( "This test is not ported to the BeOS\n" ); + return 0; +} +#else + +#include "nspr.h" +#include "prpriv.h" +#include "prinrval.h" + +#if defined(XP_MAC) +#include "gcint.h" +#endif + +#include +#include +#include + +#ifdef XP_MAC +#include "gcint.h" +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRMonitor *mon; +PRInt32 count; +PRInt32 alive; + +#define SLEEP_TIME 4 /* secs */ + +void PR_CALLBACK +Level_2_Thread(void *arg) +{ + PR_Sleep(PR_MillisecondsToInterval(4 * 1000)); + printf("Level_2_Thread[0x%lx] exiting\n",PR_GetCurrentThread()); + return; +} + +void PR_CALLBACK +Level_1_Thread(void *arg) +{ + PRUint32 tmp = (PRUint32)arg; + PRThreadScope scope = (PRThreadScope) tmp; + PRThread *thr; + + thr = PR_CreateThreadGCAble(PR_USER_THREAD, + Level_2_Thread, + NULL, + PR_PRIORITY_HIGH, + scope, + PR_JOINABLE_THREAD, + 0); + + if (!thr) { + printf("Could not create thread!\n"); + } else { + printf("Level_1_Thread[0x%lx] created %15s thread 0x%lx\n", + PR_GetCurrentThread(), + (scope == PR_GLOBAL_THREAD) ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD", + thr); + PR_JoinThread(thr); + } + PR_EnterMonitor(mon); + alive--; + PR_Notify(mon); + PR_ExitMonitor(mon); + printf("Thread[0x%lx] exiting\n",PR_GetCurrentThread()); +} + +static PRStatus PR_CALLBACK print_thread(PRThread *thread, int i, void *arg) +{ + PRInt32 words; + PRWord *registers; + + printf( + "\nprint_thread[0x%lx]: %-20s - i = %ld\n",thread, + (PR_GLOBAL_THREAD == PR_GetThreadScope(thread)) ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD", i); + registers = PR_GetGCRegisters(thread, 0, (int *)&words); + printf("Regsters R0 = 0x%x R1 = 0x%x R2 = 0x%x R3 = 0x%x\n", + registers[0],registers[1],registers[2],registers[3]); + printf("Stack Pointer = 0x%lx\n", PR_GetSP(thread)); + return PR_SUCCESS; +} + +static void Level_0_Thread(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *thr; + PRThread *me = PR_GetCurrentThread(); + int n; + PRInt32 words; + PRWord *registers; + + alive = 0; + mon = PR_NewMonitor(); + + alive = count; + for (n=0; n 1) { + count = atoi(argv[1]); + } else { + count = 5; + } + + printf("\n\n%20s%30s\n\n"," ","Suspend_Resume Test"); + CreateThreadsUU(); + CreateThreadsUK(); + CreateThreadsKU(); + CreateThreadsKK(); + PR_SetConcurrency(2); + + printf("\n%20s%30s\n\n"," ","Added 2nd CPU\n"); + + CreateThreadsUK(); + CreateThreadsKK(); + CreateThreadsUU(); + CreateThreadsKU(); + PR_Cleanup(); +} + +#endif /* XP_BEOS */ diff --git a/nsprpub/pr/tests/switch.c b/nsprpub/pr/tests/switch.c new file mode 100644 index 00000000000..2e42b793142 --- /dev/null +++ b/nsprpub/pr/tests/switch.c @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: switch.c +** Description: trying to time context switches +*/ + +#include "prinit.h" +#include "prcvar.h" +#include "prmem.h" +#include "prinrval.h" +#include "prlock.h" +#include "prlog.h" +#include "prthread.h" +#include "prprf.h" + +#include "plerror.h" +#include "plgetopt.h" + +#if defined(XP_MAC) +#include "pprio.h" +#define printf PR_LogPrint +#else +#include "private/pprio.h" +#endif + +#include + +#define INNER_LOOPS 100 +#define DEFAULT_LOOPS 100 +#define DEFAULT_THREADS 10 + +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE; + +typedef struct Shared +{ + PRLock *ml; + PRCondVar *cv; + PRBool twiddle; + PRThread *thread; + struct Shared *next; +} Shared; + +static void Help(void) +{ + debug_out = PR_STDOUT; + + PR_fprintf( + 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\tglobal threads only (default: FALSE)\n"); + PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); +} /* Help */ + +static void PR_CALLBACK Notified(void *arg) +{ + Shared *shared = (Shared*)arg; + PRStatus status = PR_SUCCESS; + while (PR_SUCCESS == status) + { + PR_Lock(shared->ml); + while (shared->twiddle && (PR_SUCCESS == status)) + status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT); + if (verbosity) PR_fprintf(debug_out, "+"); + shared->twiddle = PR_TRUE; + shared->next->twiddle = PR_FALSE; + PR_NotifyCondVar(shared->next->cv); + PR_Unlock(shared->ml); + } +} /* Notified */ + +static Shared home; +PRIntn PR_CALLBACK Switch(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRStatus status; + PRBool help = PR_FALSE; + PRUintn concurrency = 1; + Shared *shared, *link; + PRIntervalTime timein, timeout; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PRUintn thread_count, inner_count, loop_count, average; + PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G"); + 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 */ + loop_limit = atoi(opt->value); + break; + case 't': /* thread limit */ + thread_limit = 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 'h': /* help message */ + Help(); + help = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (help) return -1; + + if (PR_TRUE == debug_mode) + { + debug_out = PR_STDOUT; + PR_fprintf(debug_out, "Test parameters\n"); + PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit); + PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit); + PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); + PR_fprintf( + debug_out, "\tThread type: %s\n", + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); + } + + PR_SetConcurrency(concurrency); + + link = &home; + home.ml = PR_NewLock(); + home.cv = PR_NewCondVar(home.ml); + home.twiddle = PR_FALSE; + home.next = NULL; + + timeout = 0; + + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + shared = PR_NEWZAP(Shared); + + shared->ml = home.ml; + shared->cv = PR_NewCondVar(home.ml); + shared->twiddle = PR_TRUE; + shared->next = link; + link = shared; + + shared->thread = PR_CreateThread( + PR_USER_THREAD, Notified, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 0); + PR_ASSERT(shared->thread != NULL); + if (NULL == shared->thread) + failed = PR_TRUE; + } + + for (loop_count = 1; loop_count <= loop_limit; ++loop_count) + { + timein = PR_IntervalNow(); + for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) + { + PR_Lock(home.ml); + home.twiddle = PR_TRUE; + shared->twiddle = PR_FALSE; + PR_NotifyCondVar(shared->cv); + while (home.twiddle) + { + status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT); + if (PR_FAILURE == status) + failed = PR_TRUE; + } + PR_Unlock(home.ml); + } + timeout += (PR_IntervalNow() - timein); + } + + if (debug_mode) + { + average = PR_IntervalToMicroseconds(timeout) + / (INNER_LOOPS * loop_limit * thread_count); + PR_fprintf( + debug_out, "Average switch times %d usecs for %d threads\n", + average, thread_limit); + } + + link = shared; + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + if (&home == link) break; + status = PR_Interrupt(link->thread); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to interrupt"); + } + link = link->next; + } + + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + link = shared->next; + status = PR_JoinThread(shared->thread); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to join"); + } + PR_DestroyCondVar(shared->cv); + PR_DELETE(shared); + if (&home == link) break; + shared = link; + } + PR_DestroyCondVar(home.cv); + PR_DestroyLock(home.ml); + + PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); + return ((failed) ? 1 : 0); +} /* Switch */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn result; + PR_STDIO_INIT(); + result = PR_Initialize(Switch, argc, argv, 0); + return result; +} /* main */ + +/* switch.c */ diff --git a/nsprpub/pr/tests/system.c b/nsprpub/pr/tests/system.c new file mode 100644 index 00000000000..1feb066b8dd --- /dev/null +++ b/nsprpub/pr/tests/system.c @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prmem.h" +#include "prprf.h" +#include "prsystem.h" + +#include "plerror.h" + +static char *tag[] = +{ + "PR_SI_HOSTNAME", + "PR_SI_SYSNAME", + "PR_SI_RELEASE", + "PR_SI_ARCHITECTURE" +}; + +static PRSysInfo Incr(PRSysInfo *cmd) +{ + PRIntn tmp = (PRIntn)*cmd + 1; + *cmd = (PRSysInfo)tmp; + return (PRSysInfo)tmp; +} /* Incr */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PRSysInfo cmd; + PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); + + char *info = (char*)PR_Calloc(SYS_INFO_BUFFER_LENGTH, 1); + for (cmd = PR_SI_HOSTNAME; cmd <= PR_SI_ARCHITECTURE; Incr(&cmd)) + { + rv = PR_GetSystemInfo(cmd, info, SYS_INFO_BUFFER_LENGTH); + if (PR_SUCCESS == rv) PR_fprintf(output, "%s: %s\n", tag[cmd], info); + else PL_FPrintError(output, tag[cmd]); + } + PR_DELETE(info); + + PR_fprintf(output, "Host page size is %d\n", PR_GetPageSize()); + PR_fprintf(output, "Page shift is %d\n", PR_GetPageShift()); + PR_fprintf(output, "Memory map alignment is %ld\n", PR_GetMemMapAlignment()); + PR_fprintf(output, "Number of processors is: %d\n", PR_GetNumberOfProcessors()); + PR_fprintf(output, "Physical memory size is: %llu\n", PR_GetPhysicalMemorySize()); + + return 0; +} /* main */ + +/* system.c */ diff --git a/nsprpub/pr/tests/testbit.c b/nsprpub/pr/tests/testbit.c new file mode 100644 index 00000000000..1ad0b8f4ce2 --- /dev/null +++ b/nsprpub/pr/tests/testbit.c @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: lazyinit.c +** Description: Test the functions and macros declared in prbit.h +** +*/ + +#include "nspr.h" + +#define ErrorReport(x) { printf((x)); failed = 1; } + +prbitmap_t myMap[512/32] = { 0 }; + +PRInt32 rc; +PRInt32 i; +PRIntn failed = 0; + +PRIntn main(PRIntn argc, char **argv ) +{ + /* + ** Test bitmap things. + */ + if ( PR_TEST_BIT( myMap, 0 )) + ErrorReport("Test 0.0: Failed\n"); + + if ( PR_TEST_BIT( myMap, 31 )) + ErrorReport("Test 0.1: Failed\n"); + + if ( PR_TEST_BIT( myMap, 128 )) + ErrorReport("Test 0.2: Failed\n"); + + if ( PR_TEST_BIT( myMap, 129 )) + ErrorReport("Test 0.3: Failed\n"); + + + PR_SET_BIT( myMap, 0 ); + if ( !PR_TEST_BIT( myMap, 0 )) + ErrorReport("Test 1.0: Failed\n"); + + PR_CLEAR_BIT( myMap, 0 ); + if ( PR_TEST_BIT( myMap, 0 )) + ErrorReport("Test 1.0.1: Failed\n"); + + PR_SET_BIT( myMap, 31 ); + if ( !PR_TEST_BIT( myMap, 31 )) + ErrorReport("Test 1.1: Failed\n"); + + PR_CLEAR_BIT( myMap, 31 ); + if ( PR_TEST_BIT( myMap, 31 )) + ErrorReport("Test 1.1.1: Failed\n"); + + PR_SET_BIT( myMap, 128 ); + if ( !PR_TEST_BIT( myMap, 128 )) + ErrorReport("Test 1.2: Failed\n"); + + PR_CLEAR_BIT( myMap, 128 ); + if ( PR_TEST_BIT( myMap, 128 )) + ErrorReport("Test 1.2.1: Failed\n"); + + PR_SET_BIT( myMap, 129 ); + if ( !PR_TEST_BIT( myMap, 129 )) + ErrorReport("Test 1.3: Failed\n"); + + PR_CLEAR_BIT( myMap, 129 ); + if ( PR_TEST_BIT( myMap, 129 )) + ErrorReport("Test 1.3.1: Failed\n"); + + + /* + ** Test Ceiling and Floor functions and macros + */ + if ((rc = PR_CeilingLog2(32)) != 5 ) + ErrorReport("Test 10.0: Failed\n"); + + if ((rc = PR_FloorLog2(32)) != 5 ) + ErrorReport("Test 10.1: Failed\n"); + + + /* + ** Evaluate results and exit + */ + if (failed) + { + printf("FAILED\n"); + return(1); + } + else + { + printf("PASSED\n"); + return(0); + } +} /* end main() */ +/* end testbit.c */ diff --git a/nsprpub/pr/tests/testfile.c b/nsprpub/pr/tests/testfile.c new file mode 100644 index 00000000000..47259e269e5 --- /dev/null +++ b/nsprpub/pr/tests/testfile.c @@ -0,0 +1,1011 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "prpriv.h" + +#include +#include +#include +#ifdef WIN32 +#include +#include +#endif +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#endif + +#if defined(XP_OS2) +#define INCL_DOSFILEMGR +#include +#ifdef XP_OS2_EMX +#include +#include +#endif /* XP_OS2_EMX */ +#endif /* XP_OS2 */ + +static int _debug_on = 0; + +#ifdef XP_MAC +#include "prlog.h" +#include "primpl.h" +#define printf PR_LogPrint +#define setbuf(x,y) +extern void SetupMacPrintfLog(char *logFile); +#endif + +#ifdef XP_WIN +#define mode_t int +#endif + +#define DPRINTF(arg) if (_debug_on) printf arg + +PRLock *lock; +PRMonitor *mon; +PRInt32 count; +int thread_count; + +#ifdef WIN16 +#define BUF_DATA_SIZE 256 * 120 +#else +#define BUF_DATA_SIZE 256 * 1024 +#endif + +#define NUM_RDWR_THREADS 10 +#define NUM_DIRTEST_THREADS 4 +#define CHUNK_SIZE 512 + +typedef struct buffer { + char data[BUF_DATA_SIZE]; +} buffer; + +typedef struct File_Rdwr_Param { + char *pathname; + char *buf; + int offset; + int len; +} File_Rdwr_Param; + +#ifdef XP_PC +#ifdef XP_OS2 +char *TEST_DIR = "prdir"; +#else +char *TEST_DIR = "C:\\temp\\prdir"; +#endif +char *FILE_NAME = "pr_testfile"; +char *HIDDEN_FILE_NAME = "hidden_pr_testfile"; +#else +char *TEST_DIR = "/tmp/testfile_dir"; +char *FILE_NAME = "pr_testfile"; +char *HIDDEN_FILE_NAME = ".hidden_pr_testfile"; +#endif +buffer *in_buf, *out_buf; +char pathname[256], renamename[256]; +#define TMPDIR_LEN 64 +char testdir[TMPDIR_LEN]; +static PRInt32 PR_CALLBACK DirTest(void *argunused); +PRInt32 dirtest_failed = 0; + +PRThread* create_new_thread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, PRInt32 index) +{ +PRInt32 native_thread = 0; + + PR_ASSERT(state == PR_UNJOINABLE_THREAD); + +#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32) || defined(XP_OS2) + + switch(index % 4) { + case 0: + scope = (PR_LOCAL_THREAD); + break; + case 1: + scope = (PR_GLOBAL_THREAD); + break; + case 2: + scope = (PR_GLOBAL_BOUND_THREAD); + break; + case 3: + native_thread = 1; + break; + default: + PR_ASSERT(!"Invalid scope"); + break; + } + if (native_thread) { +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + pthread_t tid; + if (!pthread_create(&tid, NULL, start, arg)) + return((PRThread *) tid); + else + return (NULL); +#elif defined(XP_OS2) + TID tid; + + tid = (TID)_beginthread((void(* _Optlink)(void*))start, + NULL, 32768, arg); + if (tid == -1) { + printf("_beginthread failed. errno %d\n", errno); + return (NULL); + } + else + return((PRThread *) tid); +#else + HANDLE thandle; + unsigned tid; + + thandle = (HANDLE) _beginthreadex( + NULL, + stackSize, + (unsigned (__stdcall *)(void *))start, + arg, + 0, + &tid); + return((PRThread *) thandle); +#endif + } else { + return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); + } +#else + return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); +#endif +} + +static void PR_CALLBACK File_Write(void *arg) +{ +PRFileDesc *fd_file; +File_Rdwr_Param *fp = (File_Rdwr_Param *) arg; +char *name, *buf; +int offset, len; + + setbuf(stdout, NULL); + name = fp->pathname; + buf = fp->buf; + offset = fp->offset; + len = fp->len; + + fd_file = PR_Open(name, PR_RDWR | PR_CREATE_FILE, 0777); + if (fd_file == NULL) { + printf("testfile failed to create/open file %s\n",name); + return; + } + if (PR_Seek(fd_file, offset, PR_SEEK_SET) < 0) { + printf("testfile failed to seek in file %s\n",name); + return; + } + if ((PR_Write(fd_file, buf, len)) < 0) { + printf("testfile failed to write to file %s\n",name); + return; + } + DPRINTF(("Write out_buf[0] = 0x%x\n",(*((int *) buf)))); + PR_Close(fd_file); + PR_DELETE(fp); + + PR_EnterMonitor(mon); + --thread_count; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +static void PR_CALLBACK File_Read(void *arg) +{ +PRFileDesc *fd_file; +File_Rdwr_Param *fp = (File_Rdwr_Param *) arg; +char *name, *buf; +int offset, len; + + setbuf(stdout, NULL); + name = fp->pathname; + buf = fp->buf; + offset = fp->offset; + len = fp->len; + + fd_file = PR_Open(name, PR_RDONLY, 0); + if (fd_file == NULL) { + printf("testfile failed to open file %s\n",name); + return; + } + if (PR_Seek(fd_file, offset, PR_SEEK_SET) < 0) { + printf("testfile failed to seek in file %s\n",name); + return; + } + if ((PR_Read(fd_file, buf, len)) < 0) { + printf("testfile failed to read to file %s\n",name); + return; + } + DPRINTF(("Read in_buf[0] = 0x%x\n",(*((int *) buf)))); + PR_Close(fd_file); + PR_DELETE(fp); + + PR_EnterMonitor(mon); + --thread_count; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + + +static PRInt32 Misc_File_Tests(char *pathname) +{ +PRFileDesc *fd_file; +int len, rv = 0; +PRFileInfo file_info, file_info1; +char tmpname[1024]; + + setbuf(stdout, NULL); + /* + * Test PR_Available, PR_Seek, PR_GetFileInfo, PR_Rename, PR_Access + */ + + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777); + + if (fd_file == NULL) { + printf("testfile failed to create/open file %s\n",pathname); + return -1; + } + if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) { + printf("testfile PR_GetFileInfo failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (PR_Access(pathname, PR_ACCESS_EXISTS) != 0) { + printf("testfile PR_Access failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (PR_Access(pathname, PR_ACCESS_WRITE_OK) != 0) { + printf("testfile PR_Access failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (PR_Access(pathname, PR_ACCESS_READ_OK) != 0) { + printf("testfile PR_Access failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + + + if (PR_GetFileInfo(pathname, &file_info) < 0) { + printf("testfile PR_GetFileInfo failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (file_info.type != PR_FILE_FILE) { + printf( + "testfile: Error - PR_GetFileInfo returned incorrect type for file %s\n", + pathname); + rv = -1; + goto cleanup; + } + if (file_info.size != 0) { + printf( + "testfile PR_GetFileInfo returned incorrect size (%d should be 0) for file %s\n", + file_info.size, pathname); + rv = -1; + goto cleanup; + } + file_info1 = file_info; + + len = PR_Available(fd_file); + if (len < 0) { + printf("testfile PR_Available failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } else if (len != 0) { + printf( + "testfile PR_Available failed: expected/returned = %d/%d bytes\n", + 0, len); + rv = -1; + goto cleanup; + } + if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) { + printf("testfile PR_GetFileInfo failed on file %s\n",pathname); + goto cleanup; + } + if (LL_NE(file_info.creationTime , file_info1.creationTime)) { + printf( + "testfile PR_GetFileInfo returned incorrect status-change time: %s\n", + pathname); + printf("ft = %lld, ft1 = %lld\n",file_info.creationTime, + file_info1.creationTime); + rv = -1; + goto cleanup; + } + len = PR_Write(fd_file, out_buf->data, CHUNK_SIZE); + if (len < 0) { + printf("testfile failed to write to file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) { + printf("testfile PR_GetFileInfo failed on file %s\n",pathname); + goto cleanup; + } + if (file_info.size != CHUNK_SIZE) { + printf( + "testfile PR_GetFileInfo returned incorrect size (%d should be %d) for file %s\n", + file_info.size, CHUNK_SIZE, pathname); + rv = -1; + goto cleanup; + } + if (LL_CMP(file_info.modifyTime, < , file_info1.modifyTime)) { + printf( + "testfile PR_GetFileInfo returned incorrect modify time: %s\n", + pathname); + printf("ft = %lld, ft1 = %lld\n",file_info.modifyTime, + file_info1.modifyTime); + rv = -1; + goto cleanup; + } + + len = PR_Available(fd_file); + if (len < 0) { + printf("testfile PR_Available failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } else if (len != 0) { + printf( + "testfile PR_Available failed: expected/returned = %d/%d bytes\n", + 0, len); + rv = -1; + goto cleanup; + } + + PR_Seek(fd_file, 0, PR_SEEK_SET); + len = PR_Available(fd_file); + if (len < 0) { + printf("testfile PR_Available failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } else if (len != CHUNK_SIZE) { + printf( + "testfile PR_Available failed: expected/returned = %d/%d bytes\n", + CHUNK_SIZE, len); + rv = -1; + goto cleanup; + } + PR_Close(fd_file); + + strcpy(tmpname,pathname); + strcat(tmpname,".RENAMED"); + if (PR_FAILURE == PR_Rename(pathname, tmpname)) { + printf("testfile failed to rename file %s\n",pathname); + rv = -1; + goto cleanup; + } + + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777); + len = PR_Write(fd_file, out_buf->data, CHUNK_SIZE); + PR_Close(fd_file); + if (PR_SUCCESS == PR_Rename(pathname, tmpname)) { + printf("testfile renamed to existing file %s\n",pathname); + } + + if ((PR_Delete(tmpname)) < 0) { + printf("testfile failed to unlink file %s\n",tmpname); + rv = -1; + } + +cleanup: + if ((PR_Delete(pathname)) < 0) { + printf("testfile failed to unlink file %s\n",pathname); + rv = -1; + } + return rv; +} + + +static PRInt32 PR_CALLBACK FileTest(void) +{ +PRDir *fd_dir; +int i, offset, len, rv = 0; +PRThread *t; +PRThreadScope scope = PR_GLOBAL_THREAD; +File_Rdwr_Param *fparamp; + + /* + * Create Test dir + */ + if ((PR_MkDir(TEST_DIR, 0777)) < 0) { + printf("testfile failed to create dir %s\n",TEST_DIR); + return -1; + } + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf("testfile failed to open dir %s\n",TEST_DIR); + rv = -1; + goto cleanup; + } + + PR_CloseDir(fd_dir); + + strcat(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, FILE_NAME); + + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + printf( + "testfile failed to alloc buffer struct\n"); + rv = -1; + goto cleanup; + } + out_buf = PR_NEW(buffer); + if (out_buf == NULL) { + printf( + "testfile failed to alloc buffer struct\n"); + rv = -1; + goto cleanup; + } + + /* + * Start a bunch of writer threads + */ + offset = 0; + len = CHUNK_SIZE; + PR_EnterMonitor(mon); + for (i = 0; i < NUM_RDWR_THREADS; i++) { + fparamp = PR_NEW(File_Rdwr_Param); + if (fparamp == NULL) { + printf( + "testfile failed to alloc File_Rdwr_Param struct\n"); + rv = -1; + goto cleanup; + } + fparamp->pathname = pathname; + fparamp->buf = out_buf->data + offset; + fparamp->offset = offset; + fparamp->len = len; + memset(fparamp->buf, i, len); + + t = create_new_thread(PR_USER_THREAD, + File_Write, (void *)fparamp, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0, i); + offset += len; + } + thread_count = i; + /* Wait for writer threads to exit */ + while (thread_count) { + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon); + + + /* + * Start a bunch of reader threads + */ + offset = 0; + len = CHUNK_SIZE; + PR_EnterMonitor(mon); + for (i = 0; i < NUM_RDWR_THREADS; i++) { + fparamp = PR_NEW(File_Rdwr_Param); + if (fparamp == NULL) { + printf( + "testfile failed to alloc File_Rdwr_Param struct\n"); + rv = -1; + goto cleanup; + } + fparamp->pathname = pathname; + fparamp->buf = in_buf->data + offset; + fparamp->offset = offset; + fparamp->len = len; + + t = create_new_thread(PR_USER_THREAD, + File_Read, (void *)fparamp, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0, i); + offset += len; + if ((offset + len) > BUF_DATA_SIZE) + break; + } + thread_count = i; + + /* Wait for reader threads to exit */ + while (thread_count) { + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon); + + if (memcmp(in_buf->data, out_buf->data, offset) != 0) { + printf("File Test failed: file data corrupted\n"); + rv = -1; + goto cleanup; + } + + if ((PR_Delete(pathname)) < 0) { + printf("testfile failed to unlink file %s\n",pathname); + rv = -1; + goto cleanup; + } + + /* + * Test PR_Available, PR_Seek, PR_GetFileInfo, PR_Rename, PR_Access + */ + if (Misc_File_Tests(pathname) < 0) { + rv = -1; + } + +cleanup: + if ((PR_RmDir(TEST_DIR)) < 0) { + printf("testfile failed to rmdir %s\n", TEST_DIR); + rv = -1; + } + return rv; +} + +struct dirtest_arg { + PRMonitor *mon; + PRInt32 done; +}; + +static PRInt32 RunDirTest(void) +{ +int i; +PRThread *t; +PRMonitor *mon; +struct dirtest_arg thrarg; + + mon = PR_NewMonitor(); + if (!mon) { + printf("RunDirTest: Error - failed to create monitor\n"); + dirtest_failed = 1; + return -1; + } + thrarg.mon = mon; + + for (i = 0; i < NUM_DIRTEST_THREADS; i++) { + + thrarg.done= 0; + t = create_new_thread(PR_USER_THREAD, + DirTest, &thrarg, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, i); + if (!t) { + printf("RunDirTest: Error - failed to create thread\n"); + dirtest_failed = 1; + return -1; + } + PR_EnterMonitor(mon); + while (!thrarg.done) + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(mon); + + } + PR_DestroyMonitor(mon); + return 0; +} + +static PRInt32 PR_CALLBACK DirTest(void *arg) +{ +struct dirtest_arg *tinfo = (struct dirtest_arg *) arg; +PRFileDesc *fd_file; +PRDir *fd_dir; +int i; +int path_len; +PRDirEntry *dirEntry; +PRFileInfo info; +PRInt32 num_files = 0; +#if defined(XP_PC) && defined(WIN32) +HANDLE hfile; +#endif + +#define FILES_IN_DIR 20 + + /* + * Create Test dir + */ + DPRINTF(("Creating test dir %s\n",TEST_DIR)); + if ((PR_MkDir(TEST_DIR, 0777)) < 0) { + printf( + "testfile failed to create dir %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf( + "testfile failed to open dirctory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, FILE_NAME); + path_len = strlen(pathname); + + for (i = 0; i < FILES_IN_DIR; i++) { + + sprintf(pathname + path_len,"%d%s",i,""); + + DPRINTF(("Creating test file %s\n",pathname)); + + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777); + + if (fd_file == NULL) { + printf( + "testfile failed to create/open file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + PR_Close(fd_file); + } +#if defined(XP_UNIX) || defined(XP_MAC) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2) || defined(XP_BEOS) + /* + * Create a hidden file - a platform-dependent operation + */ + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, HIDDEN_FILE_NAME); +#if defined(XP_UNIX) || defined(XP_MAC) || defined(XP_BEOS) + DPRINTF(("Creating hidden test file %s\n",pathname)); + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777); + + if (fd_file == NULL) { + printf( + "testfile failed to create/open hidden file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + +#if defined(XP_MAC) + { +#include + + OSErr err; + FCBPBRec fcbpb; + CInfoPBRec pb; + Str255 pascalMacPath; + + fcbpb.ioNamePtr = pascalMacPath; + fcbpb.ioVRefNum = 0; + fcbpb.ioRefNum = fd_file->secret->md.osfd; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) { + PR_Close(fd_file); + return -1; + } + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = fcbpb.ioFCBVRefNum; + pb.hFileInfo.ioDirID = fcbpb.ioFCBParID; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) { + PR_Close(fd_file); + return -1; + } + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = fcbpb.ioFCBVRefNum; + pb.hFileInfo.ioDirID = fcbpb.ioFCBParID; + pb.hFileInfo.ioFDirIndex = 0; + + pb.hFileInfo.ioFlFndrInfo.fdFlags |= fInvisible; + + err = PBSetCatInfoSync(&pb); + if (err != noErr) { + PR_Close(fd_file); + return -1; + } + + } +#endif + + PR_Close(fd_file); + + +#elif defined(XP_PC) && defined(WIN32) + DPRINTF(("Creating hidden test file %s\n",pathname)); + hfile = CreateFile(pathname, GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_HIDDEN, + NULL); + if (hfile == INVALID_HANDLE_VALUE) { + printf("testfile failed to create/open hidden file %s [0, %d]\n", + pathname, GetLastError()); + return -1; + } + CloseHandle(hfile); + +#elif defined(OS2) + DPRINTF(("Creating hidden test file %s\n",pathname)); + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, (int)FILE_HIDDEN); + + if (fd_file == NULL) { + printf("testfile failed to create/open hidden file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + PR_Close(fd_file); +#endif /* XP _UNIX || XP_MAC*/ + +#endif /* XP_UNIX || XP_MAC ||(XP_PC && WIN32) */ + + + if (PR_FAILURE == PR_CloseDir(fd_dir)) + { + printf( + "testfile failed to close dirctory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf( + "testfile failed to reopen dirctory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + /* + * List all files, including hidden files + */ + DPRINTF(("Listing all files in directory %s\n",TEST_DIR)); +#if defined(XP_UNIX) || defined(XP_MAC) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2) || defined(XP_BEOS) + num_files = FILES_IN_DIR + 1; +#else + num_files = FILES_IN_DIR; +#endif + while ((dirEntry = PR_ReadDir(fd_dir, PR_SKIP_BOTH)) != NULL) { + num_files--; + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, dirEntry->name); + DPRINTF(("\t%s\n",dirEntry->name)); + + if ((PR_GetFileInfo(pathname, &info)) < 0) { + printf( + "testfile failed to GetFileInfo file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + + if (info.type != PR_FILE_FILE) { + printf( + "testfile incorrect fileinfo for file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + } + if (num_files != 0) + { + printf( + "testfile failed to find all files in directory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + PR_CloseDir(fd_dir); + +#if defined(XP_UNIX) || defined(XP_MAC) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2) || defined(XP_BEOS) + + /* + * List all files, except hidden files + */ + + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf( + "testfile failed to reopen dirctory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + DPRINTF(("Listing non-hidden files in directory %s\n",TEST_DIR)); + while ((dirEntry = PR_ReadDir(fd_dir, PR_SKIP_HIDDEN)) != NULL) { + DPRINTF(("\t%s\n",dirEntry->name)); + if (!strcmp(HIDDEN_FILE_NAME, dirEntry->name)) { + printf("testfile found hidden file %s\n", pathname); + return -1; + } + + } + /* + * Delete hidden file + */ + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, HIDDEN_FILE_NAME); + if (PR_FAILURE == PR_Delete(pathname)) { + printf( + "testfile failed to delete hidden file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + + PR_CloseDir(fd_dir); +#endif /* XP_UNIX || XP_MAC || (XP_PC && WIN32) */ + + strcpy(renamename, TEST_DIR); + strcat(renamename, ".RENAMED"); + if (PR_FAILURE == PR_Rename(TEST_DIR, renamename)) { + printf( + "testfile failed to rename directory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + if (PR_FAILURE == PR_MkDir(TEST_DIR, 0777)) { + printf( + "testfile failed to recreate dir %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + if (PR_SUCCESS == PR_Rename(renamename, TEST_DIR)) { + printf( + "testfile renamed directory to existing name %s\n", + renamename); + return -1; + } + + if (PR_FAILURE == PR_RmDir(TEST_DIR)) { + printf( + "testfile failed to rmdir %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + if (PR_FAILURE == PR_Rename(renamename, TEST_DIR)) { + printf( + "testfile failed to rename directory %s [%d, %d]\n", + renamename, PR_GetError(), PR_GetOSError()); + return -1; + } + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf( + "testfile failed to reopen directory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, FILE_NAME); + path_len = strlen(pathname); + + for (i = 0; i < FILES_IN_DIR; i++) { + + sprintf(pathname + path_len,"%d%s",i,""); + + if (PR_FAILURE == PR_Delete(pathname)) { + printf( + "testfile failed to delete file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + } + + PR_CloseDir(fd_dir); + + if (PR_FAILURE == PR_RmDir(TEST_DIR)) { + printf( + "testfile failed to rmdir %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + PR_EnterMonitor(tinfo->mon); + tinfo->done = 1; + PR_Notify(tinfo->mon); + PR_ExitMonitor(tinfo->mon); + + return 0; +} +/************************************************************************/ + +/* + * Test file and directory NSPR APIs + */ + +int main(int argc, char **argv) +{ +#ifdef WIN32 + PRUint32 len; +#endif +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + int opt; + extern char *optarg; + extern int optind; +#endif +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + while ((opt = getopt(argc, argv, "d")) != EOF) { + switch(opt) { + case 'd': + _debug_on = 1; + break; + default: + break; + } + } +#endif + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("testfile.log"); +#endif + + mon = PR_NewMonitor(); + if (mon == NULL) { + printf("testfile: PR_NewMonitor failed\n"); + exit(2); + } +#ifdef WIN32 + len = GetTempPath(TMPDIR_LEN, testdir); + if ((len > 0) && (len < (TMPDIR_LEN - 6))) { + /* + * enough space for prdir + */ + strcpy((testdir + len),"prdir"); + TEST_DIR = testdir; + printf("TEST_DIR = %s\n",TEST_DIR); + } + +#endif + + if (FileTest() < 0) { + printf("File Test failed\n"); + exit(2); + } + printf("File Test passed\n"); + if ((RunDirTest() < 0) || dirtest_failed) { + printf("Dir Test failed\n"); + exit(2); + } + printf("Dir Test passed\n"); + + PR_DestroyMonitor(mon); + PR_Cleanup(); + return 0; +} diff --git a/nsprpub/pr/tests/threads.c b/nsprpub/pr/tests/threads.c new file mode 100644 index 00000000000..e1d188d4c36 --- /dev/null +++ b/nsprpub/pr/tests/threads.c @@ -0,0 +1,249 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" +#include "prinrval.h" +#include "plgetopt.h" +#include "pprthred.h" +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRMonitor *mon; +PRInt32 count, iterations, alive; + +PRBool debug_mode = PR_FALSE, passed = PR_TRUE; + +void +PR_CALLBACK +ReallyDumbThread(void *arg) +{ + return; +} + +void +PR_CALLBACK +DumbThread(void *arg) +{ + PRInt32 tmp = (PRInt32)arg; + PRThreadScope scope = (PRThreadScope)tmp; + PRThread *thr; + + thr = PR_CreateThread(PR_USER_THREAD, + ReallyDumbThread, + NULL, + PR_PRIORITY_NORMAL, + scope, + PR_JOINABLE_THREAD, + 0); + + if (!thr) { + if (debug_mode) { + printf("Could not create really dumb thread (%d, %d)!\n", + PR_GetError(), PR_GetOSError()); + } + passed = PR_FALSE; + } else { + PR_JoinThread(thr); + } + PR_EnterMonitor(mon); + alive--; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +static void CreateThreads(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *thr; + int n; + + alive = 0; + mon = PR_NewMonitor(); + + alive = count; + for (n=0; noption) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop counter */ + count = atoi(opt->value); + break; + case 'i': /* loop counter */ + iterations = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + +#ifdef XP_MAC + SetupMacPrintfLog("threads.log"); + count = 10; + iterations = 10; + debug_mode = PR_TRUE; +#else + if (0 == count) count = 50; + if (0 == iterations) iterations = 10; + +#endif + + if (debug_mode) + { + printf("\ +** Tests lots of thread creations. \n\ +** Create %ld native threads %ld times. \n\ +** Create %ld user threads %ld times \n", iterations,count,iterations,count); + } + + for (index=0; index +#include +#include +#ifdef XP_UNIX +#include +#endif +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#endif + +#ifdef WIN32 +#include +#endif + +static int _debug_on = 0; +static int server_port = -1; +static char *program_name = NULL; + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +int fprintf(FILE *stream, const char *fmt, ...) +{ + PR_LogPrint(fmt); + return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +#ifdef XP_PC +#define mode_t int +#endif + +#define DPRINTF(arg) if (_debug_on) printf arg + +#define BUF_DATA_SIZE (2 * 1024) +#define TCP_MESG_SIZE 1024 +#define NUM_TCP_CLIENTS 10 /* for a listen queue depth of 5 */ + +#define NUM_TCP_CONNECTIONS_PER_CLIENT 10 +#define NUM_TCP_MESGS_PER_CONNECTION 10 +#define TCP_SERVER_PORT 10000 + +static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS; +static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT; +static PRInt32 tcp_mesg_size = TCP_MESG_SIZE; +static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION; + +int failed_already=0; + +typedef struct buffer { + char data[BUF_DATA_SIZE]; +} buffer; + +PRNetAddr tcp_server_addr, udp_server_addr; + +typedef struct Client_Param { + PRNetAddr server_addr; + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *exit_counter; /* counter to decrement, before exit */ + PRInt32 datalen; +} Client_Param; + +/* + * readn + * read data from sockfd into buf + */ +static PRInt32 +readn(PRFileDesc *sockfd, char *buf, int len) +{ + int rem; + int bytes; + int offset = 0; + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + + for (rem=len; rem; offset += bytes, rem -= bytes) { + DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n", + PR_GetCurrentThread(), rem)); + bytes = PR_Recv(sockfd, buf + offset, rem, 0, + timeout); + DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n", + PR_GetCurrentThread(), bytes)); + if (bytes < 0) { + return -1; + } + } + return len; +} + +/* + * writen + * write data from buf to sockfd + */ +static PRInt32 +writen(PRFileDesc *sockfd, char *buf, int len) +{ + int rem; + int bytes; + int offset = 0; + + for (rem=len; rem; offset += bytes, rem -= bytes) { + DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n", + PR_GetCurrentThread(), rem)); + bytes = PR_Send(sockfd, buf + offset, rem, 0, + PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n", + PR_GetCurrentThread(), bytes)); + if (bytes <= 0) + return -1; + } + return len; +} + +/* + * TCP_Client + * Client job + * Connect to the server at the address specified in the argument. + * Fill in a buffer, write data to server, read it back and check + * for data corruption. + * Close the socket for server connection + */ +static void PR_CALLBACK +TCP_Client(void *arg) +{ + Client_Param *cp = (Client_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf, *out_buf; + union PRNetAddr netaddr; + PRInt32 bytes, i, j; + + + DPRINTF(("TCP client started\n")); + bytes = cp->datalen; + out_buf = PR_NEW(buffer); + if (out_buf == NULL) { + fprintf(stderr,"%s: failed to alloc buffer struct\n", program_name); + failed_already=1; + return; + } + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"%s: failed to alloc buffer struct\n", program_name); + failed_already=1; + return; + } + netaddr.inet.family = cp->server_addr.inet.family; + netaddr.inet.port = cp->server_addr.inet.port; + netaddr.inet.ip = cp->server_addr.inet.ip; + + for (i = 0; i < num_tcp_connections_per_client; i++) { + if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) { + fprintf(stderr,"%s: PR_OpenTCPSocket failed\n", program_name); + failed_already=1; + return; + } + + DPRINTF(("TCP client connecting to server:%d\n", server_port)); + if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){ + fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + return; + } + for (j = 0; j < num_tcp_mesgs_per_connection; j++) { + /* + * fill in random data + */ + memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes); + /* + * write to server + */ + if (writen(sockfd, out_buf->data, bytes) < bytes) { + fprintf(stderr,"%s: ERROR - TCP_Client:writen\n", program_name); + failed_already=1; + return; + } + /* + DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n", + PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data)))); + */ + if (readn(sockfd, in_buf->data, bytes) < bytes) { + fprintf(stderr,"%s: ERROR - TCP_Client:readn\n", program_name); + failed_already=1; + return; + } + /* + * verify the data read + */ + if (memcmp(in_buf->data, out_buf->data, bytes) != 0) { + fprintf(stderr,"%s: ERROR - data corruption\n", program_name); + failed_already=1; + return; + } + } + /* + * shutdown reads and writes + */ + if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { + fprintf(stderr,"%s: ERROR - PR_Shutdown\n", program_name); + failed_already=1; + } + PR_Close(sockfd); + } + + PR_DELETE(out_buf); + PR_DELETE(in_buf); + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(cp->exit_mon); + --(*cp->exit_counter); + PR_Notify(cp->exit_mon); + PR_ExitMonitor(cp->exit_mon); + DPRINTF(("TCP_Client exiting\n")); +} + +/* + * TCP_Socket_Client_Server_Test - concurrent server test + * + * Each client connects to the server and sends a chunk of data + * For each connection, server reads the data + * from the client and sends it back to the client, unmodified. + * Each client checks that data received from server is same as the + * data it sent to the server. + * + */ + +static PRInt32 +TCP_Socket_Client_Server_Test(void) +{ + int i; + Client_Param *cparamp; + PRMonitor *mon2; + PRInt32 datalen; + PRInt32 connections = 0; + PRThread *thr; + + datalen = tcp_mesg_size; + connections = 0; + + mon2 = PR_NewMonitor(); + if (mon2 == NULL) { + fprintf(stderr,"%s: PR_NewMonitor failed\n", program_name); + failed_already=1; + return -1; + } + + /* + * Start client jobs + */ + cparamp = PR_NEW(Client_Param); + if (cparamp == NULL) { + fprintf(stderr,"%s: PR_NEW failed\n", program_name); + failed_already=1; + return -1; + } + cparamp->server_addr.inet.family = PR_AF_INET; + cparamp->server_addr.inet.port = PR_htons(server_port); + cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + cparamp->exit_mon = mon2; + cparamp->exit_counter = &connections; + cparamp->datalen = datalen; + for (i = 0; i < num_tcp_clients; i++) { + thr = PR_CreateThread(PR_USER_THREAD, TCP_Client, (void *)cparamp, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + if (NULL == thr) { + fprintf(stderr,"%s: PR_CreateThread failed\n", program_name); + failed_already=1; + return -1; + } + PR_EnterMonitor(mon2); + connections++; + PR_ExitMonitor(mon2); + DPRINTF(("Created TCP client = 0x%lx\n", thr)); + } + /* Wait for client jobs to exit */ + PR_EnterMonitor(mon2); + while (0 != connections) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("Client job count = %d\n", connections)); + } + PR_ExitMonitor(mon2); + printf("%30s","TCP_Socket_Client_Server_Test:"); + printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l, + num_tcp_clients, num_tcp_connections_per_client); + printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":", + num_tcp_mesgs_per_connection, tcp_mesg_size); + + PR_DELETE(cparamp); + return 0; +} + +/************************************************************************/ + +int +main(int argc, char **argv) +{ + /* + * -d debug mode + */ + PLOptStatus os; + PLOptState *opt; + program_name = argv[0]; + + opt = PL_CreateOptState(argc, argv, "dp:"); + 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 'p': + server_port = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("socket.log"); +#endif + PR_SetConcurrency(4); + + TCP_Socket_Client_Server_Test(); + + PR_Cleanup(); + if (failed_already) + return 1; + else + return 0; +} diff --git a/nsprpub/pr/tests/thrpool_server.c b/nsprpub/pr/tests/thrpool_server.c new file mode 100644 index 00000000000..cafa67ad219 --- /dev/null +++ b/nsprpub/pr/tests/thrpool_server.c @@ -0,0 +1,607 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: thrpool.c +** +** Description: Test threadpool functionality. +** +** Modification History: +*/ +#include "primpl.h" + +#include "plgetopt.h" + +#include +#include +#include +#ifdef XP_UNIX +#include +#endif +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#endif + +/* for getcwd */ +#if defined(XP_UNIX) || defined (XP_OS2_EMX) || defined(XP_BEOS) +#include +#elif defined(XP_PC) +#include +#endif + +#ifdef WIN32 +#include +#endif + +static int _debug_on = 0; +static char *program_name = NULL; +static void serve_client_write(void *arg); + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +int fprintf(FILE *stream, const char *fmt, ...) +{ + PR_LogPrint(fmt); + return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +#ifdef XP_PC +#define mode_t int +#endif + +#define DPRINTF(arg) if (_debug_on) printf arg + + +#define BUF_DATA_SIZE (2 * 1024) +#define TCP_MESG_SIZE 1024 +#define NUM_TCP_CLIENTS 10 /* for a listen queue depth of 5 */ + + +#define NUM_TCP_CONNECTIONS_PER_CLIENT 10 +#define NUM_TCP_MESGS_PER_CONNECTION 10 +#define TCP_SERVER_PORT 10000 +#define SERVER_MAX_BIND_COUNT 100 + +static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS; +static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT; +static PRInt32 tcp_mesg_size = TCP_MESG_SIZE; +static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION; +static void TCP_Server_Accept(void *arg); + + +int failed_already=0; +typedef struct buffer { + char data[BUF_DATA_SIZE]; +} buffer; + + +typedef struct Server_Param { + PRJobIoDesc iod; /* socket to read from/write to */ + PRInt32 datalen; /* bytes of data transfered in each read/write */ + PRNetAddr netaddr; + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *job_counterp; /* counter to decrement, before exit */ + PRInt32 conn_counter; /* counter to decrement, before exit */ + PRThreadPool *tp; +} Server_Param; + +typedef struct Serve_Client_Param { + PRJobIoDesc iod; /* socket to read from/write to */ + PRInt32 datalen; /* bytes of data transfered in each read/write */ + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *job_counterp; /* counter to decrement, before exit */ + PRThreadPool *tp; +} Serve_Client_Param; + +typedef struct Session { + PRJobIoDesc iod; /* socket to read from/write to */ + buffer *in_buf; + PRInt32 bytes; + PRInt32 msg_num; + PRInt32 bytes_read; + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *job_counterp; /* counter to decrement, before exit */ + PRThreadPool *tp; +} Session; + +static void +serve_client_read(void *arg) +{ + Session *sp = (Session *) arg; + int rem; + int bytes; + int offset; + PRFileDesc *sockfd; + char *buf; + PRJob *jobp; + + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + + sockfd = sp->iod.socket; + buf = sp->in_buf->data; + + PR_ASSERT(sp->msg_num < num_tcp_mesgs_per_connection); + PR_ASSERT(sp->bytes_read < sp->bytes); + + offset = sp->bytes_read; + rem = sp->bytes - offset; + bytes = PR_Recv(sockfd, buf + offset, rem, 0, timeout); + if (bytes < 0) { + return; + } + sp->bytes_read += bytes; + sp->iod.timeout = PR_SecondsToInterval(60); + if (sp->bytes_read < sp->bytes) { + jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + return; + } + PR_ASSERT(sp->bytes_read == sp->bytes); + DPRINTF(("serve_client: read complete, msg(%d) \n", sp->msg_num)); + + sp->iod.timeout = PR_SecondsToInterval(60); + jobp = PR_QueueJob_Write(sp->tp, &sp->iod, serve_client_write, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + + return; +} + +static void +serve_client_write(void *arg) +{ + Session *sp = (Session *) arg; + int bytes; + PRFileDesc *sockfd; + char *buf; + PRJob *jobp; + + sockfd = sp->iod.socket; + buf = sp->in_buf->data; + + PR_ASSERT(sp->msg_num < num_tcp_mesgs_per_connection); + + bytes = PR_Send(sockfd, buf, sp->bytes, 0, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(bytes == sp->bytes); + + if (bytes < 0) { + return; + } + DPRINTF(("serve_client: write complete, msg(%d) \n", sp->msg_num)); + sp->msg_num++; + if (sp->msg_num < num_tcp_mesgs_per_connection) { + sp->bytes_read = 0; + sp->iod.timeout = PR_SecondsToInterval(60); + jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + return; + } + + DPRINTF(("serve_client: read/write complete, msg(%d) \n", sp->msg_num)); + if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { + fprintf(stderr,"%s: ERROR - PR_Shutdown\n", program_name); + } + + PR_Close(sockfd); + PR_EnterMonitor(sp->exit_mon); + --(*sp->job_counterp); + PR_Notify(sp->exit_mon); + PR_ExitMonitor(sp->exit_mon); + + PR_DELETE(sp->in_buf); + PR_DELETE(sp); + + return; +} + +/* + * Serve_Client + * Thread, started by the server, for serving a client connection. + * Reads data from socket and writes it back, unmodified, and + * closes the socket + */ +static void PR_CALLBACK +Serve_Client(void *arg) +{ + Serve_Client_Param *scp = (Serve_Client_Param *) arg; + buffer *in_buf; + Session *sp; + PRJob *jobp; + + sp = PR_NEW(Session); + sp->iod = scp->iod; + + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"%s: failed to alloc buffer struct\n",program_name); + failed_already=1; + return; + } + + sp->in_buf = in_buf; + sp->bytes = scp->datalen; + sp->msg_num = 0; + sp->bytes_read = 0; + sp->tp = scp->tp; + sp->exit_mon = scp->exit_mon; + sp->job_counterp = scp->job_counterp; + + sp->iod.timeout = PR_SecondsToInterval(60); + jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + PR_DELETE(scp); +} + +static void +print_stats(void *arg) +{ + Server_Param *sp = (Server_Param *) arg; + PRThreadPool *tp = sp->tp; + PRInt32 counter; + PRJob *jobp; + + PR_EnterMonitor(sp->exit_mon); + counter = (*sp->job_counterp); + PR_ExitMonitor(sp->exit_mon); + + printf("PRINT_STATS: #client connections = %d\n",counter); + + + jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(500), + print_stats, sp, PR_FALSE); + + PR_ASSERT(NULL != jobp); +} + +static int job_counter = 0; +/* + * TCP Server + * Server binds an address to a socket, starts a client process and + * listens for incoming connections. + * Each client connects to the server and sends a chunk of data + * Starts a Serve_Client job for each incoming connection, to read + * the data from the client and send it back to the client, unmodified. + * Each client checks that data received from server is same as the + * data it sent to the server. + * Finally, the threadpool is shutdown + */ +static void PR_CALLBACK +TCP_Server(void *arg) +{ + PRThreadPool *tp = (PRThreadPool *) arg; + Server_Param *sp; + PRFileDesc *sockfd; + PRNetAddr netaddr; + PRMonitor *sc_mon; + PRJob *jobp; + int i; + PRStatus rval; + + /* + * Create a tcp socket + */ + if ((sockfd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"%s: PR_NewTCPSocket failed\n", program_name); + return; + } + 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,"%s: ERROR - PR_Bind failed\n", program_name); + perror("PR_Bind"); + failed_already=1; + return; + } + + if (PR_Listen(sockfd, 32) < 0) { + fprintf(stderr,"%s: ERROR - PR_Listen failed\n", program_name); + failed_already=1; + return; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"%s: ERROR - PR_GetSockName failed\n", program_name); + failed_already=1; + return; + } + + DPRINTF(( + "TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + + sp = PR_NEW(Server_Param); + if (sp == NULL) { + fprintf(stderr,"%s: PR_NEW failed\n", program_name); + failed_already=1; + return; + } + sp->iod.socket = sockfd; + sp->iod.timeout = PR_SecondsToInterval(60); + sp->datalen = tcp_mesg_size; + sp->exit_mon = sc_mon; + sp->job_counterp = &job_counter; + sp->conn_counter = 0; + sp->tp = tp; + sp->netaddr = netaddr; + + /* create and cancel an io job */ + jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + rval = PR_CancelJob(jobp); + PR_ASSERT(PR_SUCCESS == rval); + + /* + * create the client process + */ + { +#define MAX_ARGS 4 + char *argv[MAX_ARGS + 1]; + int index = 0; + char port[32]; + char path[1024 + sizeof("/thrpool_client")]; + (void)getcwd(path, sizeof(path)); + (void)strcat(path, "/thrpool_client"); +#ifdef XP_PC + (void)strcat(path, ".exe"); +#endif + argv[index++] = path; + sprintf(port,"%d",PR_ntohs(netaddr.inet.port)); + if (_debug_on) + { + argv[index++] = "-d"; + argv[index++] = "-p"; + argv[index++] = port; + argv[index++] = NULL; + } else { + argv[index++] = "-p"; + argv[index++] = port; + argv[index++] = NULL; + } + PR_ASSERT(MAX_ARGS >= (index - 1)); + + DPRINTF(("creating client process %s ...\n", path)); + if (PR_FAILURE == PR_CreateProcessDetached(path, argv, NULL, NULL)) { + fprintf(stderr, + "thrpool_server: ERROR - PR_CreateProcessDetached failed\n"); + failed_already=1; + return; + } + } + + sc_mon = PR_NewMonitor(); + if (sc_mon == NULL) { + fprintf(stderr,"%s: PR_NewMonitor failed\n", program_name); + failed_already=1; + return; + } + + sp->iod.socket = sockfd; + sp->iod.timeout = PR_SecondsToInterval(60); + sp->datalen = tcp_mesg_size; + sp->exit_mon = sc_mon; + sp->job_counterp = &job_counter; + sp->conn_counter = 0; + sp->tp = tp; + sp->netaddr = netaddr; + + /* create and cancel a timer job */ + jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(5000), + print_stats, sp, PR_FALSE); + PR_ASSERT(NULL != jobp); + rval = PR_CancelJob(jobp); + PR_ASSERT(PR_SUCCESS == rval); + + DPRINTF(("TCP_Server: Accepting connections \n")); + + jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + return; +} + +static void +TCP_Server_Accept(void *arg) +{ + Server_Param *sp = (Server_Param *) arg; + PRThreadPool *tp = sp->tp; + Serve_Client_Param *scp; + PRFileDesc *newsockfd; + PRJob *jobp; + + if ((newsockfd = PR_Accept(sp->iod.socket, &sp->netaddr, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr,"%s: ERROR - PR_Accept failed\n", program_name); + failed_already=1; + goto exit; + } + scp = PR_NEW(Serve_Client_Param); + if (scp == NULL) { + fprintf(stderr,"%s: PR_NEW failed\n", program_name); + failed_already=1; + goto exit; + } + + /* + * Start a Serve_Client job for each incoming connection + */ + scp->iod.socket = newsockfd; + scp->iod.timeout = PR_SecondsToInterval(60); + scp->datalen = tcp_mesg_size; + scp->exit_mon = sp->exit_mon; + scp->job_counterp = sp->job_counterp; + scp->tp = sp->tp; + + PR_EnterMonitor(sp->exit_mon); + (*sp->job_counterp)++; + PR_ExitMonitor(sp->exit_mon); + jobp = PR_QueueJob(tp, Serve_Client, scp, + PR_FALSE); + + PR_ASSERT(NULL != jobp); + DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", jobp)); + + /* + * single-threaded update; no lock needed + */ + sp->conn_counter++; + if (sp->conn_counter < + (num_tcp_clients * num_tcp_connections_per_client)) { + jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + return; + } + jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(500), + print_stats, sp, PR_FALSE); + + PR_ASSERT(NULL != jobp); + DPRINTF(("TCP_Server: Created print_stats timer job = 0x%lx\n", jobp)); + +exit: + PR_EnterMonitor(sp->exit_mon); + /* Wait for server jobs to finish */ + while (0 != *sp->job_counterp) { + PR_Wait(sp->exit_mon, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("TCP_Server: conn_counter = %d\n", + *sp->job_counterp)); + } + + PR_ExitMonitor(sp->exit_mon); + if (sp->iod.socket) { + PR_Close(sp->iod.socket); + } + PR_DestroyMonitor(sp->exit_mon); + printf("%30s","TCP_Socket_Client_Server_Test:"); + printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l, + num_tcp_clients, num_tcp_connections_per_client); + printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":", + num_tcp_mesgs_per_connection, tcp_mesg_size); + + DPRINTF(("%s: calling PR_ShutdownThreadPool\n", program_name)); + PR_ShutdownThreadPool(sp->tp); + PR_DELETE(sp); +} + +/************************************************************************/ + +#define DEFAULT_INITIAL_THREADS 4 +#define DEFAULT_MAX_THREADS 100 +#define DEFAULT_STACKSIZE (512 * 1024) + +int +main(int argc, char **argv) +{ + PRInt32 initial_threads = DEFAULT_INITIAL_THREADS; + PRInt32 max_threads = DEFAULT_MAX_THREADS; + PRInt32 stacksize = DEFAULT_STACKSIZE; + PRThreadPool *tp = NULL; + PRStatus rv; + PRJob *jobp; + + /* + * -d debug mode + */ + PLOptStatus os; + PLOptState *opt; + + program_name = argv[0]; + opt = PL_CreateOptState(argc, argv, "d"); + 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; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("socket.log"); +#endif + PR_SetConcurrency(4); + + tp = PR_CreateThreadPool(initial_threads, max_threads, stacksize); + if (NULL == tp) { + printf("PR_CreateThreadPool failed\n"); + failed_already=1; + goto done; + } + jobp = PR_QueueJob(tp, TCP_Server, tp, PR_TRUE); + rv = PR_JoinJob(jobp); + PR_ASSERT(PR_SUCCESS == rv); + + DPRINTF(("%s: calling PR_JoinThreadPool\n", program_name)); + rv = PR_JoinThreadPool(tp); + PR_ASSERT(PR_SUCCESS == rv); + DPRINTF(("%s: returning from PR_JoinThreadPool\n", program_name)); + +done: + PR_Cleanup(); + if (failed_already) return 1; + else return 0; +} diff --git a/nsprpub/pr/tests/thruput.c b/nsprpub/pr/tests/thruput.c new file mode 100644 index 00000000000..e6319dbecce --- /dev/null +++ b/nsprpub/pr/tests/thruput.c @@ -0,0 +1,412 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: thruput.c +** Description: Test server's throughput capability comparing various +** implmentation strategies. +** +** Note: Requires a server machine and an aribitrary number of +** clients to bang on it. Trust the numbers on the server +** more than those being displayed by the various clients. +*/ + +#include "prerror.h" +#include "prinrval.h" +#include "prinit.h" +#include "prio.h" +#include "prlock.h" +#include "prmem.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prthread.h" + +#include "pprio.h" + +#include "plerror.h" +#include "plgetopt.h" + +#define ADDR_BUFFER 100 +#define PORT_NUMBER 51877 +#define SAMPLING_INTERVAL 10 +#define BUFFER_SIZE (32 * 1024) + +static PRInt32 domain = PR_AF_INET; +static PRInt32 protocol = 6; /* TCP */ +static PRFileDesc *err = NULL; +static PRIntn concurrency = 1; +static PRInt32 xport_buffer = -1; +static PRUint32 initial_streams = 1; +static PRInt32 buffer_size = BUFFER_SIZE; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +typedef struct Shared +{ + PRLock *ml; + PRUint32 sampled; + PRUint32 threads; + PRIntervalTime timein; + PRNetAddr server_address; +} Shared; + +static Shared *shared = NULL; + +static PRStatus PrintAddress(const PRNetAddr* address) +{ + char buffer[ADDR_BUFFER]; + PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); + if (PR_SUCCESS == rv) + PR_fprintf(err, "%s:%u\n", buffer, PR_ntohs(address->inet.port)); + else PL_FPrintError(err, "PR_NetAddrToString"); + return rv; +} /* PrintAddress */ + + +static void PR_CALLBACK Clientel(void *arg) +{ + PRStatus rv; + PRFileDesc *xport; + PRInt32 bytes, sampled; + PRIntervalTime now, interval; + PRBool do_display = PR_FALSE; + Shared *shared = (Shared*)arg; + char *buffer = (char*)PR_Malloc(buffer_size); + PRNetAddr *server_address = &shared->server_address; + PRIntervalTime connect_timeout = PR_SecondsToInterval(5); + PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL); + + PR_fprintf(err, "Client connecting to "); + (void)PrintAddress(server_address); + + do + { + xport = PR_Socket(domain, PR_SOCK_STREAM, protocol); + if (NULL == xport) + { + PL_FPrintError(err, "PR_Socket"); + return; + } + + if (xport_buffer != -1) + { + PRSocketOptionData data; + data.option = PR_SockOpt_RecvBufferSize; + data.value.recv_buffer_size = (PRSize)xport_buffer; + rv = PR_SetSocketOption(xport, &data); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_SetSocketOption - ignored"); + data.option = PR_SockOpt_SendBufferSize; + data.value.send_buffer_size = (PRSize)xport_buffer; + rv = PR_SetSocketOption(xport, &data); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_SetSocketOption - ignored"); + } + + rv = PR_Connect(xport, server_address, connect_timeout); + if (PR_FAILURE == rv) + { + PL_FPrintError(err, "PR_Connect"); + if (PR_IO_TIMEOUT_ERROR != PR_GetError()) + PR_Sleep(connect_timeout); + PR_Close(xport); /* delete it and start over */ + } + } while (PR_FAILURE == rv); + + do + { + bytes = PR_Recv( + xport, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT); + PR_Lock(shared->ml); + now = PR_IntervalNow(); + shared->sampled += bytes; + interval = now - shared->timein; + if (interval > sampling_interval) + { + sampled = shared->sampled; + shared->timein = now; + shared->sampled = 0; + do_display = PR_TRUE; + } + PR_Unlock(shared->ml); + + if (do_display) + { + PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval); + PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate); + do_display = PR_FALSE; + } + + } while (bytes > 0); +} /* Clientel */ + +static void Client(const char *server_name) +{ + PRStatus rv; + PRHostEnt host; + char buffer[PR_NETDB_BUF_SIZE]; + PRIntervalTime dally = PR_SecondsToInterval(60); + PR_fprintf(err, "Translating the name %s\n", server_name); + rv = PR_GetHostByName(server_name, buffer, sizeof(buffer), &host); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_GetHostByName"); + else + { + if (PR_EnumerateHostEnt( + 0, &host, PORT_NUMBER, &shared->server_address) < 0) + PL_FPrintError(err, "PR_EnumerateHostEnt"); + else + { + do + { + shared->threads += 1; + (void)PR_CreateThread( + PR_USER_THREAD, Clientel, shared, + PR_PRIORITY_NORMAL, thread_scope, + PR_UNJOINABLE_THREAD, 8 * 1024); + if (shared->threads == initial_streams) + { + PR_Sleep(dally); + initial_streams += 1; + } + } while (PR_TRUE); + } + } +} + +static void PR_CALLBACK Servette(void *arg) +{ + PRInt32 bytes, sampled; + PRIntervalTime now, interval; + PRBool do_display = PR_FALSE; + PRFileDesc *client = (PRFileDesc*)arg; + char *buffer = (char*)PR_Malloc(buffer_size); + PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL); + + if (xport_buffer != -1) + { + PRStatus rv; + PRSocketOptionData data; + data.option = PR_SockOpt_RecvBufferSize; + data.value.recv_buffer_size = (PRSize)xport_buffer; + rv = PR_SetSocketOption(client, &data); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_SetSocketOption - ignored"); + data.option = PR_SockOpt_SendBufferSize; + data.value.send_buffer_size = (PRSize)xport_buffer; + rv = PR_SetSocketOption(client, &data); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_SetSocketOption - ignored"); + } + + do + { + bytes = PR_Send( + client, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT); + + PR_Lock(shared->ml); + now = PR_IntervalNow(); + shared->sampled += bytes; + interval = now - shared->timein; + if (interval > sampling_interval) + { + sampled = shared->sampled; + shared->timein = now; + shared->sampled = 0; + do_display = PR_TRUE; + } + PR_Unlock(shared->ml); + + if (do_display) + { + PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval); + PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate); + do_display = PR_FALSE; + } + } while (bytes > 0); +} /* Servette */ + +static void Server(void) +{ + PRStatus rv; + PRNetAddr server_address, client_address; + PRFileDesc *xport = PR_Socket(domain, PR_SOCK_STREAM, protocol); + + if (NULL == xport) + { + PL_FPrintError(err, "PR_Socket"); + return; + } + + rv = PR_InitializeNetAddr(PR_IpAddrAny, PORT_NUMBER, &server_address); + if (PR_FAILURE == rv) PL_FPrintError(err, "PR_InitializeNetAddr"); + else + { + rv = PR_Bind(xport, &server_address); + if (PR_FAILURE == rv) PL_FPrintError(err, "PR_Bind"); + else + { + PRFileDesc *client; + rv = PR_Listen(xport, 10); + PR_fprintf(err, "Server listening on "); + (void)PrintAddress(&server_address); + do + { + client = PR_Accept( + xport, &client_address, PR_INTERVAL_NO_TIMEOUT); + if (NULL == client) PL_FPrintError(err, "PR_Accept"); + else + { + PR_fprintf(err, "Server accepting from "); + (void)PrintAddress(&client_address); + shared->threads += 1; + (void)PR_CreateThread( + PR_USER_THREAD, Servette, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_UNJOINABLE_THREAD, 8 * 1024); + } + } while (PR_TRUE); + + } + } +} /* Server */ + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-h] []\n"); + PR_fprintf(err, "\t-s Initial # of connections (default: 1)\n"); + PR_fprintf(err, "\t-C Set 'concurrency' (default: 1)\n"); + PR_fprintf(err, "\t-b Client buffer size (default: 32k)\n"); + PR_fprintf(err, "\t-B Transport recv/send buffer size (default: sys)\n"); + PR_fprintf(err, "\t-G Use GLOBAL threads (default: LOCAL)\n"); + PR_fprintf(err, "\t-X Use XTP transport (default: TCP)\n"); + PR_fprintf(err, "\t-6 Use IPv6 (default: IPv4)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); + PR_fprintf(err, "\t DNS name of server\n"); + PR_fprintf(err, "\t\tIf is not specified, this host will be\n"); + PR_fprintf(err, "\t\tthe server and not act as a client.\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + const char *server_name = NULL; + PLOptState *opt = PL_CreateOptState(argc, argv, "hGX6C:b:s:B:"); + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* Name of server */ + server_name = opt->value; + break; + case 'G': /* Globular threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'X': /* Use XTP as the transport */ + protocol = 36; + break; + case '6': /* Use IPv6 */ + domain = PR_AF_INET6; + break; + case 's': /* initial_streams */ + initial_streams = atoi(opt->value); + break; + case 'C': /* concurrency */ + concurrency = atoi(opt->value); + break; + case 'b': /* buffer size */ + buffer_size = 1024 * atoi(opt->value); + break; + case 'B': /* buffer size */ + xport_buffer = 1024 * atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + shared = PR_NEWZAP(Shared); + shared->ml = PR_NewLock(); + + PR_fprintf(err, + "This machine is %s\n", + (NULL == server_name) ? "the SERVER" : "a CLIENT"); + + PR_fprintf(err, + "Transport being used is %s\n", + (6 == protocol) ? "TCP" : "XTP"); + + if (PR_GLOBAL_THREAD == thread_scope) + { + if (1 != concurrency) + { + PR_fprintf(err, " **Concurrency > 1 and GLOBAL threads!?!?\n"); + PR_fprintf(err, " **Ignoring concurrency\n"); + concurrency = 1; + } + } + + if (1 != concurrency) + { + PR_SetConcurrency(concurrency); + PR_fprintf(err, "Concurrency set to %u\n", concurrency); + } + + PR_fprintf(err, + "All threads will be %s\n", + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); + + PR_fprintf(err, "Client buffer size will be %u\n", buffer_size); + + if (-1 != xport_buffer) + PR_fprintf( + err, "Transport send & receive buffer size will be %u\n", xport_buffer); + + + if (NULL == server_name) Server(); + else Client(server_name); + +} /* main */ + +/* thruput.c */ + diff --git a/nsprpub/pr/tests/time.c b/nsprpub/pr/tests/time.c new file mode 100644 index 00000000000..b8e7d61afcb --- /dev/null +++ b/nsprpub/pr/tests/time.c @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Program to test different ways to get the time; right now it is tuned + * only for solaris. + * solaris results (100000 iterations): + * time to get time with time(): 4.63 usec avg, 463 msec total + * time to get time with gethrtime(): 2.17 usec avg, 217 msec total + * time to get time with gettimeofday(): 1.25 usec avg, 125 msec total + * + * + */ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "prpriv.h" +#include "prinrval.h" + +#include +#include +#include +#include + +#define DEFAULT_COUNT 100000 +PRInt32 count; + +time_t itime; +hrtime_t ihrtime; + +void +ftime_init() +{ + itime = time(NULL); + ihrtime = gethrtime(); +} + +time_t +ftime() +{ + hrtime_t now = gethrtime(); + + return itime + ((now - ihrtime) / 1000000000ll); +} + +static void timeTime(void) +{ + PRInt32 index = count; + time_t rv; + + for (;index--;) + rv = time(NULL); +} + +static void timeGethrtime(void) +{ + PRInt32 index = count; + time_t rv; + + for (;index--;) + rv = ftime(); +} + +static void timeGettimeofday(void) +{ + PRInt32 index = count; + time_t rv; + struct timeval tp; + + for (;index--;) + rv = gettimeofday(&tp, NULL); +} + +static void timePRTime32(void) +{ + PRInt32 index = count; + PRInt32 rv32; + PRTime q; + PRTime rv; + + LL_I2L(q, 1000000); + + for (;index--;) { + rv = PR_Now(); + LL_DIV(rv, rv, q); + LL_L2I(rv32, rv); + } +} + +static void timePRTime64(void) +{ + PRInt32 index = count; + PRTime rv; + + for (;index--;) + rv = PR_Now(); +} + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + PRInt32 tot; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + tot = PR_IntervalToMilliseconds(stop-start); + + if (debug_mode) printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot); +} + +void main(int argc, char **argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + 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 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (argc > 1) { + count = atoi(argv[1]); + } else { + count = DEFAULT_COUNT; + } + + ftime_init(); + + Measure(timeTime, "time to get time with time()"); + Measure(timeGethrtime, "time to get time with gethrtime()"); + Measure(timeGettimeofday, "time to get time with gettimeofday()"); + Measure(timePRTime32, "time to get time with PR_Time() (32bit)"); + Measure(timePRTime64, "time to get time with PR_Time() (64bit)"); + + PR_Cleanup(); + return 0; +} + + + diff --git a/nsprpub/pr/tests/timemac.c b/nsprpub/pr/tests/timemac.c new file mode 100644 index 00000000000..c58c24bdd3f --- /dev/null +++ b/nsprpub/pr/tests/timemac.c @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * file: timemac.c + * description: test time and date routines on the Mac + */ +#include +#include "prinit.h" +#include "prtime.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + + +static char *dayOfWeek[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" }; +static char *month[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; + +static void printExplodedTime(const PRExplodedTime *et) { + PRInt32 totalOffset; + PRInt32 hourOffset, minOffset; + const char *sign; + + /* Print day of the week, month, day, hour, minute, and second */ + printf( "%s %s %ld %02ld:%02ld:%02ld ", + dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday, + et->tm_hour, et->tm_min, et->tm_sec); + + /* Print time zone */ + totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset; + if (totalOffset == 0) { + printf("UTC "); + } else { + sign = ""; + if (totalOffset < 0) { + totalOffset = -totalOffset; + sign = "-"; + } + hourOffset = totalOffset / 3600; + minOffset = (totalOffset % 3600) / 60; + printf("%s%02ld%02ld ", sign, hourOffset, minOffset); + } + + /* Print year */ + printf("%d", et->tm_year); +} + +int main(int argc, char** argv) +{ + PR_STDIO_INIT(); + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + +#ifdef XP_MAC + SetupMacPrintfLog("timemac.log"); +#endif + + /* + ************************************************************* + ** + ** Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime + ** on the current time + ** + ************************************************************* + */ + + { + PRTime t1, t2; + PRExplodedTime et; + + printf("*********************************************\n"); + printf("** **\n"); + printf("** Testing PR_Now(), PR_ExplodeTime, and **\n"); + printf("** PR_ImplodeTime on the current time **\n"); + printf("** **\n"); + printf("*********************************************\n\n"); + t1 = PR_Now(); + + /* First try converting to UTC */ + + PR_ExplodeTime(t1, PR_GMTParameters, &et); + if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) { + printf("ERROR: UTC has nonzero gmt or dst offset.\n"); + return 1; + } + printf("Current UTC is "); + printExplodedTime(&et); + printf("\n"); + + t2 = PR_ImplodeTime(&et); + if (LL_NE(t1, t2)) { + printf("ERROR: Explode and implode are NOT inverse.\n"); + return 1; + } + + /* Next, try converting to local (US Pacific) time */ + + PR_ExplodeTime(t1, PR_LocalTimeParameters, &et); + printf("Current local time is "); + printExplodedTime(&et); + printf("\n"); + printf("GMT offset is %ld, DST offset is %ld\n", + et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset); + t2 = PR_ImplodeTime(&et); + if (LL_NE(t1, t2)) { + printf("ERROR: Explode and implode are NOT inverse.\n"); + return 1; + } + } + + printf("Please examine the results\n"); + return 0; +} diff --git a/nsprpub/pr/tests/timetest.c b/nsprpub/pr/tests/timetest.c new file mode 100644 index 00000000000..c57c15e671f --- /dev/null +++ b/nsprpub/pr/tests/timetest.c @@ -0,0 +1,792 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * file: timetest.c + * description: test time and date routines + */ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prtime.h" +#include "prprf.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#include "macstdlibextras.h" +extern void SetupMacPrintfLog(char *logFile); +#endif + +int failed_already=0; +PRBool debug_mode = PR_FALSE; + +static char *dayOfWeek[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" }; +static char *month[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; + +static void PrintExplodedTime(const PRExplodedTime *et) { + PRInt32 totalOffset; + PRInt32 hourOffset, minOffset; + const char *sign; + + /* Print day of the week, month, day, hour, minute, and second */ + if (debug_mode) printf("%s %s %ld %02ld:%02ld:%02ld ", + dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday, + et->tm_hour, et->tm_min, et->tm_sec); + + /* Print time zone */ + totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset; + if (totalOffset == 0) { + if (debug_mode) printf("UTC "); + } else { + sign = "+"; + if (totalOffset < 0) { + totalOffset = -totalOffset; + sign = "-"; + } + hourOffset = totalOffset / 3600; + minOffset = (totalOffset % 3600) / 60; + if (debug_mode) + printf("%s%02ld%02ld ", sign, hourOffset, minOffset); + } + + /* Print year */ + if (debug_mode) printf("%hd", et->tm_year); +} + +static int ExplodedTimeIsEqual(const PRExplodedTime *et1, + const PRExplodedTime *et2) +{ + if (et1->tm_usec == et2->tm_usec && + et1->tm_sec == et2->tm_sec && + et1->tm_min == et2->tm_min && + et1->tm_hour == et2->tm_hour && + et1->tm_mday == et2->tm_mday && + et1->tm_month == et2->tm_month && + et1->tm_year == et2->tm_year && + et1->tm_wday == et2->tm_wday && + et1->tm_yday == et2->tm_yday && + et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset && + et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) { + return 1; + } else { + return 0; + } +} + +static void +testParseTimeString(PRTime t) +{ + PRExplodedTime et; + PRTime t2; + char timeString[128]; + char buf[128]; + PRInt32 totalOffset; + PRInt32 hourOffset, minOffset; + const char *sign; + PRInt64 usec_per_sec; + + /* Truncate the microsecond part of PRTime */ + LL_I2L(usec_per_sec, PR_USEC_PER_SEC); + LL_DIV(t, t, usec_per_sec); + LL_MUL(t, t, usec_per_sec); + + PR_ExplodeTime(t, PR_LocalTimeParameters, &et); + + /* Print day of the week, month, day, hour, minute, and second */ + PR_snprintf(timeString, 128, "%s %s %ld %02ld:%02ld:%02ld ", + dayOfWeek[et.tm_wday], month[et.tm_month], et.tm_mday, + et.tm_hour, et.tm_min, et.tm_sec); + /* Print time zone */ + totalOffset = et.tm_params.tp_gmt_offset + et.tm_params.tp_dst_offset; + if (totalOffset == 0) { + strcat(timeString, "GMT "); /* I wanted to use "UTC" here, but + * PR_ParseTimeString doesn't + * understand "UTC". */ + } else { + sign = "+"; + if (totalOffset < 0) { + totalOffset = -totalOffset; + sign = "-"; + } + hourOffset = totalOffset / 3600; + minOffset = (totalOffset % 3600) / 60; + PR_snprintf(buf, 128, "%s%02ld%02ld ", sign, hourOffset, minOffset); + strcat(timeString, buf); + } + /* Print year */ + PR_snprintf(buf, 128, "%hd", et.tm_year); + strcat(timeString, buf); + + if (PR_ParseTimeString(timeString, PR_FALSE, &t2) == PR_FAILURE) { + fprintf(stderr, "PR_ParseTimeString() failed\n"); + exit(1); + } + if (LL_NE(t, t2)) { + fprintf(stderr, "PR_ParseTimeString() incorrect\n"); + PR_snprintf(buf, 128, "t is %lld, t2 is %lld, time string is %s\n", + t, t2, timeString); + fprintf(stderr, "%s\n", buf); + exit(1); + } +} + +int main(int argc, char** argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt; + + PR_STDIO_INIT(); + opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + +#ifdef XP_MAC + /* Set up the console */ + InitializeSIOUX(true); + debug_mode = PR_TRUE; +#endif + /* Testing zero PRTime (the epoch) */ + { + PRTime t; + PRExplodedTime et; + + LL_I2L(t, 0); + if (debug_mode) printf("The NSPR epoch is:\n"); + PR_ExplodeTime(t, PR_LocalTimeParameters, &et); + PrintExplodedTime(&et); + if (debug_mode) printf("\n"); + PR_ExplodeTime(t, PR_GMTParameters, &et); + PrintExplodedTime(&et); + if (debug_mode) printf("\n\n"); + testParseTimeString(t); + } + + /* + ************************************************************* + ** + ** Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime + ** on the current time + ** + ************************************************************* + */ + + { + PRTime t1, t2; + PRExplodedTime et; + + if (debug_mode) { + printf("*********************************************\n"); + printf("** **\n"); + printf("** Testing PR_Now(), PR_ExplodeTime, and **\n"); + printf("** PR_ImplodeTime on the current time **\n"); + printf("** **\n"); + printf("*********************************************\n\n"); + } + t1 = PR_Now(); + + /* First try converting to UTC */ + + PR_ExplodeTime(t1, PR_GMTParameters, &et); + if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) { + if (debug_mode) printf("ERROR: UTC has nonzero gmt or dst offset.\n"); + else failed_already=1; + return 1; + } + if (debug_mode) printf("Current UTC is "); + PrintExplodedTime(&et); + if (debug_mode) printf("\n"); + + t2 = PR_ImplodeTime(&et); + if (LL_NE(t1, t2)) { + if (debug_mode) printf("ERROR: Explode and implode are NOT inverse.\n"); + else printf("FAIL\n"); + return 1; + } + + /* Next, try converting to local (US Pacific) time */ + + PR_ExplodeTime(t1, PR_LocalTimeParameters, &et); + if (debug_mode) printf("Current local time is "); + PrintExplodedTime(&et); + if (debug_mode) printf("\n"); + if (debug_mode) printf("GMT offset is %ld, DST offset is %ld\n", + et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset); + t2 = PR_ImplodeTime(&et); + if (LL_NE(t1, t2)) { + if (debug_mode) printf("ERROR: Explode and implode are NOT inverse.\n"); + return 1; + } + + if (debug_mode) printf("Please examine the results\n"); + testParseTimeString(t1); + } + + + /* + ******************************************* + ** + ** Testing PR_NormalizeTime() + ** + ******************************************* + */ + + /* July 4, 2001 is Wednesday */ + { + PRExplodedTime et; + + if (debug_mode) { + printf("\n"); + printf("**********************************\n"); + printf("** **\n"); + printf("** Testing PR_NormalizeTime() **\n"); + printf("** **\n"); + printf("**********************************\n\n"); + } + et.tm_year = 2001; + et.tm_month = 7 - 1; + et.tm_mday = 4; + et.tm_hour = 0; + et.tm_min = 0; + et.tm_sec = 0; + et.tm_usec = 0; + et.tm_params = PR_GMTParameters(&et); + + PR_NormalizeTime(&et, PR_GMTParameters); + + if (debug_mode) printf("July 4, 2001 is %s.\n", dayOfWeek[et.tm_wday]); + if (et.tm_wday == 3) { + if (debug_mode) printf("PASS\n"); + } else { + if (debug_mode) printf("ERROR: It should be Wednesday\n"); + else failed_already=1; + return 1; + } + testParseTimeString(PR_ImplodeTime(&et)); + + /* June 12, 1997 23:00 PST == June 13, 1997 00:00 PDT */ + et.tm_year = 1997; + et.tm_month = 6 - 1; + et.tm_mday = 12; + et.tm_hour = 23; + et.tm_min = 0; + et.tm_sec = 0; + et.tm_usec = 0; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 0; + + PR_NormalizeTime(&et, PR_USPacificTimeParameters); + + if (debug_mode) { + printf("Thu Jun 12, 1997 23:00:00 PST is "); + } + PrintExplodedTime(&et); + if (debug_mode) printf(".\n"); + if (et.tm_wday == 5) { + if (debug_mode) printf("PASS\n"); + } else { + if (debug_mode) printf("ERROR: It should be Friday\n"); + else failed_already=1; + return 1; + } + testParseTimeString(PR_ImplodeTime(&et)); + + /* Feb 14, 1997 00:00:00 PDT == Feb 13, 1997 23:00:00 PST */ + et.tm_year = 1997; + et.tm_month = 2 - 1; + et.tm_mday = 14; + et.tm_hour = 0; + et.tm_min = 0; + et.tm_sec = 0; + et.tm_usec = 0; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 3600; + + PR_NormalizeTime(&et, PR_USPacificTimeParameters); + + if (debug_mode) { + printf("Fri Feb 14, 1997 00:00:00 PDT is "); + } + PrintExplodedTime(&et); + if (debug_mode) printf(".\n"); + if (et.tm_wday == 4) { + if (debug_mode) printf("PASS\n"); + } else { + if (debug_mode) printf("ERROR: It should be Thursday\n"); + else failed_already=1; + return 1; + } + testParseTimeString(PR_ImplodeTime(&et)); + + /* What time is Nov. 7, 1996, 18:29:23 PDT? */ + et.tm_year = 1996; + et.tm_month = 11 - 1; + et.tm_mday = 7; + et.tm_hour = 18; + et.tm_min = 29; + et.tm_sec = 23; + et.tm_usec = 0; + et.tm_params.tp_gmt_offset = -8 * 3600; /* PDT */ + et.tm_params.tp_dst_offset = 3600; + + PR_NormalizeTime(&et, PR_LocalTimeParameters); + if (debug_mode) printf("Nov 7 18:29:23 PDT 1996 is "); + PrintExplodedTime(&et); + if (debug_mode) printf(".\n"); + testParseTimeString(PR_ImplodeTime(&et)); + + /* What time is Oct. 7, 1995, 18:29:23 PST? */ + et.tm_year = 1995; + et.tm_month = 10 - 1; + et.tm_mday = 7; + et.tm_hour = 18; + et.tm_min = 29; + et.tm_sec = 23; + et.tm_params.tp_gmt_offset = -8 * 3600; /* PST */ + et.tm_params.tp_dst_offset = 0; + + PR_NormalizeTime(&et, PR_LocalTimeParameters); + if (debug_mode) printf("Oct 7 18:29:23 PST 1995 is "); + PrintExplodedTime(&et); + if (debug_mode) printf(".\n"); + testParseTimeString(PR_ImplodeTime(&et)); + + if (debug_mode) printf("Please examine the results\n"); + } + + /* + ************************************************************** + ** + ** Testing range of years + ** + ************************************************************** + */ + + { + PRExplodedTime et1, et2; + PRTime ttt; + PRTime secs; + + if (debug_mode) { + printf("\n"); + printf("***************************************\n"); + printf("** **\n"); + printf("** Testing range of years **\n"); + printf("** **\n"); + printf("***************************************\n\n"); + } + /* April 4, 1917 GMT */ + et1.tm_usec = 0; + et1.tm_sec = 0; + et1.tm_min = 0; + et1.tm_hour = 0; + et1.tm_mday = 4; + et1.tm_month = 4 - 1; + et1.tm_year = 1917; + et1.tm_params = PR_GMTParameters(&et1); + PR_NormalizeTime(&et1, PR_LocalTimeParameters); + secs = PR_ImplodeTime(&et1); + if (LL_GE_ZERO(secs)) { + if (debug_mode) + printf("ERROR: April 4, 1917 GMT returns a nonnegative second count\n"); + failed_already = 1; + return 1; + } + PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2); + if (!ExplodedTimeIsEqual(&et1, &et2)) { + if (debug_mode) + printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for April 4, 1917 GMT\n"); + failed_already=1; + return 1; + } + ttt = PR_ImplodeTime(&et1); + testParseTimeString( ttt ); + + if (debug_mode) printf("Test passed for April 4, 1917\n"); + + /* July 4, 2050 */ + et1.tm_usec = 0; + et1.tm_sec = 0; + et1.tm_min = 0; + et1.tm_hour = 0; + et1.tm_mday = 4; + et1.tm_month = 7 - 1; + et1.tm_year = 2050; + et1.tm_params = PR_GMTParameters(&et1); + PR_NormalizeTime(&et1, PR_LocalTimeParameters); + secs = PR_ImplodeTime(&et1); + if (!LL_GE_ZERO(secs)) { + if (debug_mode) + printf("ERROR: July 4, 2050 GMT returns a negative second count\n"); + failed_already = 1; + return 1; + } + PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2); + if (!ExplodedTimeIsEqual(&et1, &et2)) { + if (debug_mode) + printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for July 4, 2050 GMT\n"); + failed_already=1; + return 1; + } + testParseTimeString(PR_ImplodeTime(&et1)); + + if (debug_mode) printf("Test passed for July 4, 2050\n"); + + } + + /* + ************************************************************** + ** + ** Stress test + * + ** Go through four years, starting from + ** 00:00:00 PST Jan. 1, 2005, incrementing + ** every 10 minutes. + ** + ************************************************************** + */ + + { + PRExplodedTime et, et1, et2; + PRInt64 usecPer10Min; + int day, hour, min; + PRTime usecs; + int dstInEffect = 0; + + if (debug_mode) { + printf("\n"); + printf("*******************************************************\n"); + printf("** **\n"); + printf("** Stress test Pacific Time **\n"); + printf("** Starting from midnight Jan. 1, 2005 PST, **\n"); + printf("** going through four years in 10-minute increment **\n"); + printf("** **\n"); + printf("*******************************************************\n\n"); + } + LL_I2L(usecPer10Min, 600000000L); + + /* 00:00:00 PST Jan. 1, 2005 */ + et.tm_usec = 0; + et.tm_sec = 0; + et.tm_min = 0; + et.tm_hour = 0; + et.tm_mday = 1; + et.tm_month = 0; + et.tm_year = 2005; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 0; + usecs = PR_ImplodeTime(&et); + + for (day = 0; day < 4 * 365 + 1; day++) { + for (hour = 0; hour < 24; hour++) { + for (min = 0; min < 60; min += 10) { + LL_ADD(usecs, usecs, usecPer10Min); + PR_ExplodeTime(usecs, PR_USPacificTimeParameters, &et1); + + et2 = et; + et2.tm_usec += 600000000L; + PR_NormalizeTime(&et2, PR_USPacificTimeParameters); + + if (!ExplodedTimeIsEqual(&et1, &et2)) { + printf("ERROR: componentwise comparison failed\n"); + PrintExplodedTime(&et1); + printf("\n"); + PrintExplodedTime(&et2); + printf("\n"); + failed_already=1; + return 1; + } + + if (LL_NE(usecs, PR_ImplodeTime(&et1))) { + printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n"); + PrintExplodedTime(&et1); + printf("\n"); + failed_already=1; + return 1; + } + testParseTimeString(usecs); + + if (!dstInEffect && et1.tm_params.tp_dst_offset) { + dstInEffect = 1; + if (debug_mode) { + printf("DST changeover from "); + PrintExplodedTime(&et); + printf(" to "); + PrintExplodedTime(&et1); + printf(".\n"); + } + } else if (dstInEffect && !et1.tm_params.tp_dst_offset) { + dstInEffect = 0; + if (debug_mode) { + printf("DST changeover from "); + PrintExplodedTime(&et); + printf(" to "); + PrintExplodedTime(&et1); + printf(".\n"); + } + } + + et = et1; + } + } + } + if (debug_mode) printf("Test passed\n"); + } + + + /* Same stress test, but with PR_LocalTimeParameters */ + + { + PRExplodedTime et, et1, et2; + PRInt64 usecPer10Min; + int day, hour, min; + PRTime usecs; + int dstInEffect = 0; + + if (debug_mode) { + printf("\n"); + printf("*******************************************************\n"); + printf("** **\n"); + printf("** Stress test Local Time **\n"); + printf("** Starting from midnight Jan. 1, 2005 PST, **\n"); + printf("** going through four years in 10-minute increment **\n"); + printf("** **\n"); + printf("*******************************************************\n\n"); + } + + LL_I2L(usecPer10Min, 600000000L); + + /* 00:00:00 PST Jan. 1, 2005 */ + et.tm_usec = 0; + et.tm_sec = 0; + et.tm_min = 0; + et.tm_hour = 0; + et.tm_mday = 1; + et.tm_month = 0; + et.tm_year = 2005; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 0; + usecs = PR_ImplodeTime(&et); + + for (day = 0; day < 4 * 365 + 1; day++) { + for (hour = 0; hour < 24; hour++) { + for (min = 0; min < 60; min += 10) { + LL_ADD(usecs, usecs, usecPer10Min); + PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1); + + et2 = et; + et2.tm_usec += 600000000L; + PR_NormalizeTime(&et2, PR_LocalTimeParameters); + + if (!ExplodedTimeIsEqual(&et1, &et2)) { + printf("ERROR: componentwise comparison failed\n"); + PrintExplodedTime(&et1); + printf("\n"); + PrintExplodedTime(&et2); + printf("\n"); + return 1; + } + + if (LL_NE(usecs, PR_ImplodeTime(&et1))) { + printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n"); + PrintExplodedTime(&et1); + printf("\n"); + failed_already=1; + return 1; + } + testParseTimeString(usecs); + + if (!dstInEffect && et1.tm_params.tp_dst_offset) { + dstInEffect = 1; + if (debug_mode) { + printf("DST changeover from "); + PrintExplodedTime(&et); + printf(" to "); + PrintExplodedTime(&et1); + printf(".\n"); + } + } else if (dstInEffect && !et1.tm_params.tp_dst_offset) { + dstInEffect = 0; + if (debug_mode) { + printf("DST changeover from "); + PrintExplodedTime(&et); + printf(" to "); + PrintExplodedTime(&et1); + printf(".\n"); + } + } + + et = et1; + } + } + } + if (debug_mode) printf("Test passed\n"); + } + + /* Same stress test, but with PR_LocalTimeParameters and going backward */ + + { + PRExplodedTime et, et1, et2; + PRInt64 usecPer10Min; + int day, hour, min; + PRTime usecs; + int dstInEffect = 0; + + if (debug_mode) { + printf("\n"); + printf("*******************************************************\n"); + printf("** **\n"); + printf("** Stress test Local Time **\n"); + printf("** Starting from midnight Jan. 1, 2009 PST, **\n"); + printf("** going back four years in 10-minute increment **\n"); + printf("** **\n"); + printf("*******************************************************\n\n"); + } + + LL_I2L(usecPer10Min, 600000000L); + + /* 00:00:00 PST Jan. 1, 2009 */ + et.tm_usec = 0; + et.tm_sec = 0; + et.tm_min = 0; + et.tm_hour = 0; + et.tm_mday = 1; + et.tm_month = 0; + et.tm_year = 2009; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 0; + usecs = PR_ImplodeTime(&et); + + for (day = 0; day < 4 * 365 + 1; day++) { + for (hour = 0; hour < 24; hour++) { + for (min = 0; min < 60; min += 10) { + LL_SUB(usecs, usecs, usecPer10Min); + PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1); + + et2 = et; + et2.tm_usec -= 600000000L; + PR_NormalizeTime(&et2, PR_LocalTimeParameters); + + if (!ExplodedTimeIsEqual(&et1, &et2)) { + printf("ERROR: componentwise comparison failed\n"); + PrintExplodedTime(&et1); + printf("\n"); + PrintExplodedTime(&et2); + printf("\n"); + return 1; + } + + if (LL_NE(usecs, PR_ImplodeTime(&et1))) { + printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n"); + PrintExplodedTime(&et1); + printf("\n"); + failed_already=1; + return 1; + } + testParseTimeString(usecs); + + if (!dstInEffect && et1.tm_params.tp_dst_offset) { + dstInEffect = 1; + if (debug_mode) { + printf("DST changeover from "); + PrintExplodedTime(&et); + printf(" to "); + PrintExplodedTime(&et1); + printf(".\n"); + } + } else if (dstInEffect && !et1.tm_params.tp_dst_offset) { + dstInEffect = 0; + if (debug_mode) { + printf("DST changeover from "); + PrintExplodedTime(&et); + printf(" to "); + PrintExplodedTime(&et1); + printf(".\n"); + } + } + + et = et1; + } + } + } + } + +#ifdef XP_MAC + if (1) + { + char dummyChar; + + printf("Press return to exit\n\n"); + scanf("%c", &dummyChar); + } +#endif + + if (failed_already) return 1; + else return 0; + +} diff --git a/nsprpub/pr/tests/tmoacc.c b/nsprpub/pr/tests/tmoacc.c new file mode 100644 index 00000000000..fa974a136a5 --- /dev/null +++ b/nsprpub/pr/tests/tmoacc.c @@ -0,0 +1,333 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" + +#include +#include + +#include "plerror.h" +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + +#define BASE_PORT 9867 +#define DEFAULT_THREADS 1 +#define DEFAULT_BACKLOG 10 +#define DEFAULT_TIMEOUT 10 +#define RANDOM_RANGE 100 /* should be significantly smaller than RAND_MAX */ + +typedef enum {running, stopped} Status; + +typedef struct Shared +{ + PRLock *ml; + PRCondVar *cv; + PRBool passed; + PRBool random; + PRFileDesc *debug; + PRIntervalTime timeout; + PRFileDesc *listenSock; + Status status; +} Shared; + +static PRIntervalTime Timeout(const Shared *shared) +{ + PRIntervalTime timeout = shared->timeout; + if (shared->random) + { + PRIntervalTime half = timeout >> 1; /* one half of the interval */ + PRIntervalTime quarter = half >> 1; /* one quarter of the interval */ + /* something in [0..timeout / 2) */ + PRUint32 random = (rand() % RANDOM_RANGE) * half / RANDOM_RANGE; + timeout = (3 * quarter) + random; /* [75..125)% */ + } + return timeout; +} /* Timeout */ + +static void Accept(void *arg) +{ + PRStatus rv; + char *buffer = NULL; + PRNetAddr clientAddr; + Shared *shared = (Shared*)arg; + PRInt32 recv_length = 0, flags = 0; + PRFileDesc *clientSock; + PRIntn toread, byte, bytes, loop = 0; + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; + + do + { + PRUint32 checksum = 0; + if (NULL != shared->debug) + PR_fprintf(shared->debug, "[%d]accepting ... ", loop++); + clientSock = PR_Accept( + shared->listenSock, &clientAddr, Timeout(shared)); + if (clientSock != NULL) + { + if (NULL != shared->debug) + PR_fprintf(shared->debug, "reading length ... "); + bytes = PR_Recv( + clientSock, &descriptor, sizeof(descriptor), + flags, Timeout(shared)); + if (sizeof(descriptor) == bytes) + { + /* and, before doing something stupid ... */ + descriptor.length = PR_ntohl(descriptor.length); + descriptor.checksum = PR_ntohl(descriptor.checksum); + if (NULL != shared->debug) + PR_fprintf(shared->debug, "%d bytes ... ", descriptor.length); + toread = descriptor.length; + if (recv_length < descriptor.length) + { + if (NULL != buffer) PR_DELETE(buffer); + buffer = (char*)PR_MALLOC(descriptor.length); + recv_length = descriptor.length; + } + for (toread = descriptor.length; toread > 0; toread -= bytes) + { + bytes = PR_Recv( + clientSock, &buffer[descriptor.length - toread], + toread, flags, Timeout(shared)); + if (-1 == bytes) + { + if (NULL != shared->debug) + PR_fprintf(shared->debug, "read data failed..."); + bytes = 0; + } + } + } + else if (NULL != shared->debug) + { + PR_fprintf(shared->debug, "read desciptor failed..."); + descriptor.length = -1; + } + if (NULL != shared->debug) + PR_fprintf(shared->debug, "closing"); + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); + if ((PR_FAILURE == rv) && (NULL != shared->debug)) + { + PR_fprintf(shared->debug, " failed"); + shared->passed = PR_FALSE; + } + rv = PR_Close(clientSock); + if (PR_FAILURE == rv) if (NULL != shared->debug) + { + PR_fprintf(shared->debug, " failed"); + shared->passed = PR_FALSE; + } + if (descriptor.length > 0) + { + for (byte = 0; byte < descriptor.length; ++byte) + { + PRUint32 overflow = checksum & 0x80000000; + checksum = (checksum << 1); + if (0x00000000 != overflow) checksum += 1; + checksum += buffer[byte]; + } + if ((descriptor.checksum != checksum) && (NULL != shared->debug)) + { + PR_fprintf(shared->debug, " ... data mismatch"); + shared->passed = PR_FALSE; + } + } + else if (0 == descriptor.length) + { + PR_Lock(shared->ml); + shared->status = stopped; + PR_NotifyCondVar(shared->cv); + PR_Unlock(shared->ml); + } + if (NULL != shared->debug) + PR_fprintf(shared->debug, "\n"); + } + else + { + if (PR_PENDING_INTERRUPT_ERROR != PR_GetError()) + { + if (NULL != shared->debug) PL_PrintError("Accept"); + shared->passed = PR_FALSE; + } + } + } while (running == shared->status); + if (NULL != buffer) PR_DELETE(buffer); +} /* Accept */ + +PRIntn Tmoacc(PRIntn argc, char **argv) +{ + PRStatus rv; + PRIntn exitStatus; + PRIntn index; + Shared *shared; + PLOptStatus os; + PRThread **thread; + PRNetAddr listenAddr; + PRSocketOptionData sockOpt; + PRIntn timeout = DEFAULT_TIMEOUT; + PRIntn threads = DEFAULT_THREADS; + PRIntn backlog = DEFAULT_BACKLOG; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + + PLOptState *opt = PL_CreateOptState(argc, argv, "dGb:t:T:R"); + + shared = PR_NEWZAP(Shared); + + shared->debug = NULL; + shared->passed = PR_TRUE; + shared->random = PR_TRUE; + shared->status = running; + shared->ml = PR_NewLock(); + shared->cv = PR_NewCondVar(shared->ml); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + shared->debug = PR_GetSpecialFD(PR_StandardError); + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'b': /* size of listen backlog */ + backlog = atoi(opt->value); + break; + case 't': /* number of threads doing accept */ + threads = atoi(opt->value); + break; + case 'T': /* timeout used for network operations */ + timeout = atoi(opt->value); + break; + case 'R': /* randomize the timeout values */ + shared->random = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + if (0 == threads) threads = DEFAULT_THREADS; + if (0 == backlog) backlog = DEFAULT_BACKLOG; + if (0 == timeout) timeout = DEFAULT_TIMEOUT; + + PR_STDIO_INIT(); + memset(&listenAddr, 0, sizeof(listenAddr)); + rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr); + PR_ASSERT(PR_SUCCESS == rv); + + shared->timeout = PR_SecondsToInterval(timeout); + + /* First bind to the socket */ + shared->listenSock = PR_NewTCPSocket(); + if (shared->listenSock) + { + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(shared->listenSock, &sockOpt); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(shared->listenSock, &listenAddr); + if (rv != PR_FAILURE) + { + rv = PR_Listen(shared->listenSock, threads + backlog); + if (PR_SUCCESS == rv) + { + thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*)); + for (index = 0; index < threads; ++index) + { + thread[index] = PR_CreateThread( + PR_USER_THREAD, Accept, shared, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 0); + PR_ASSERT(NULL != thread[index]); + } + + PR_Lock(shared->ml); + while (shared->status == running) + PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(shared->ml); + for (index = 0; index < threads; ++index) + { + rv = PR_Interrupt(thread[index]); + PR_ASSERT(PR_SUCCESS== rv); + rv = PR_JoinThread(thread[index]); + PR_ASSERT(PR_SUCCESS== rv); + } + PR_DELETE(thread); + } + else + { + if (shared->debug) PL_PrintError("Listen"); + shared->passed = PR_FALSE; + } + } + else + { + if (shared->debug) PL_PrintError("Bind"); + shared->passed = PR_FALSE; + } + + PR_Close(shared->listenSock); + } + else + { + if (shared->debug) PL_PrintError("Create"); + shared->passed = PR_FALSE; + } + + PR_DestroyCondVar(shared->cv); + PR_DestroyLock(shared->ml); + + PR_fprintf( + PR_GetSpecialFD(PR_StandardError), "%s\n", + ((shared->passed) ? "PASSED" : "FAILED")); + + exitStatus = (shared->passed) ? 0 : 1; + PR_DELETE(shared); + return exitStatus; +} + +int main(int argc, char **argv) +{ + return (PR_VersionCheck(PR_VERSION)) ? + PR_Initialize(Tmoacc, argc, argv, 4) : -1; +} /* main */ + +/* tmoacc */ diff --git a/nsprpub/pr/tests/tmocon.c b/nsprpub/pr/tests/tmocon.c new file mode 100644 index 00000000000..1cd8f77f2cc --- /dev/null +++ b/nsprpub/pr/tests/tmocon.c @@ -0,0 +1,404 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/*********************************************************************** +** +** Name: tmocon.c +** +** Description: test client socket connection. +** +** Modification History: +** 19-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. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprio.h" + +#include "plerror.h" +#include "plgetopt.h" + +#include +#include +#include + +/* for getcwd */ +#if defined(XP_UNIX) || defined (XP_OS2_EMX) || defined(XP_BEOS) +#include +#elif defined(XP_PC) +#include +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + + +#define BASE_PORT 9867 + +#define DEFAULT_DALLY 1 +#define DEFAULT_THREADS 1 +#define DEFAULT_TIMEOUT 10 +#define DEFAULT_MESSAGES 100 +#define DEFAULT_MESSAGESIZE 100 + +static PRFileDesc *debug_out = NULL; + +typedef struct Shared +{ + PRBool random; + PRBool failed; + PRBool intermittant; + PRIntn debug; + PRInt32 messages; + PRIntervalTime dally; + PRIntervalTime timeout; + PRInt32 message_length; + PRNetAddr serverAddress; +} Shared; + +static PRIntervalTime Timeout(const Shared *shared) +{ + PRIntervalTime timeout = shared->timeout; + if (shared->random) + { + PRIntervalTime quarter = timeout >> 2; /* one quarter of the interval */ + PRUint32 random = rand() % quarter; /* something in[0..timeout / 4) */ + timeout = (((3 * quarter) + random) >> 2) + quarter; /* [75..125)% */ + } + return timeout; +} /* Timeout */ + +static void CauseTimeout(const Shared *shared) +{ + if (shared->intermittant) PR_Sleep(Timeout(shared)); +} /* CauseTimeout */ + +static PRStatus MakeReceiver(Shared *shared) +{ + PRStatus rv = PR_FAILURE; + if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback)) + { + char *argv[3]; + char path[1024 + sizeof("/tmoacc")]; + (void)getcwd(path, sizeof(path)); + (void)strcat(path, "/tmoacc"); +#ifdef XP_PC + (void)strcat(path, ".exe"); +#endif + argv[0] = path; + if (shared->debug > 0) + { + argv[1] = "-d"; + argv[2] = NULL; + } + else argv[1] = NULL; + if (shared->debug > 1) + PR_fprintf(debug_out, " creating accept process %s ...", path); + fflush(stdout); + rv = PR_CreateProcessDetached(path, argv, NULL, NULL); + if (PR_SUCCESS == rv) + { + if (shared->debug > 1) + PR_fprintf(debug_out, " wait 5 seconds"); + if (shared->debug > 1) + PR_fprintf(debug_out, " before connecting to accept process ..."); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(5)); + return rv; + } + shared->failed = PR_TRUE; + if (shared->debug > 0) + PL_FPrintError(debug_out, "PR_CreateProcessDetached failed"); + } + return rv; +} /* MakeReceiver */ + +static void Connect(void *arg) +{ + PRStatus rv; + char *buffer = NULL; + PRFileDesc *clientSock; + Shared *shared = (Shared*)arg; + PRInt32 loop, bytes, flags = 0; + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; + debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError); + + buffer = (char*)PR_MALLOC(shared->message_length); + + for (bytes = 0; bytes < shared->message_length; ++bytes) + buffer[bytes] = (char)bytes; + + descriptor.checksum = 0; + for (bytes = 0; bytes < shared->message_length; ++bytes) + { + PRUint32 overflow = descriptor.checksum & 0x80000000; + descriptor.checksum = (descriptor.checksum << 1); + if (0x00000000 != overflow) descriptor.checksum += 1; + descriptor.checksum += buffer[bytes]; + } + descriptor.checksum = PR_htonl(descriptor.checksum); + + for (loop = 0; loop < shared->messages; ++loop) + { + if (shared->debug > 1) + PR_fprintf(debug_out, "[%d]socket ... ", loop); + clientSock = PR_NewTCPSocket(); + if (clientSock) + { + /* + * We need to slow down the rate of generating connect requests, + * otherwise the listen backlog queue on the accept side may + * become full and we will get connection refused or timeout + * error. + */ + + PR_Sleep(shared->dally); + if (shared->debug > 1) + { + char buf[128]; + PR_NetAddrToString(&shared->serverAddress, buf, sizeof(buf)); + PR_fprintf(debug_out, "connecting to %s ... ", buf); + } + rv = PR_Connect( + clientSock, &shared->serverAddress, Timeout(shared)); + if (PR_SUCCESS == rv) + { + PRInt32 descriptor_length = (loop < (shared->messages - 1)) ? + shared->message_length : 0; + descriptor.length = PR_htonl(descriptor_length); + if (shared->debug > 1) + PR_fprintf( + debug_out, "sending %d bytes ... ", descriptor_length); + CauseTimeout(shared); /* might cause server to timeout */ + bytes = PR_Send( + clientSock, &descriptor, sizeof(descriptor), + flags, Timeout(shared)); + if (bytes != sizeof(descriptor)) + { + shared->failed = PR_TRUE; + if (shared->debug > 0) + PL_FPrintError(debug_out, "PR_Send failed"); + } + if (0 != descriptor_length) + { + CauseTimeout(shared); + bytes = PR_Send( + clientSock, buffer, descriptor_length, + flags, Timeout(shared)); + if (bytes != descriptor_length) + { + shared->failed = PR_TRUE; + if (shared->debug > 0) + PL_FPrintError(debug_out, "PR_Send failed"); + } + } + if (shared->debug > 1) PR_fprintf(debug_out, "closing ... "); + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); + rv = PR_Close(clientSock); + if (shared->debug > 1) + { + if (PR_SUCCESS == rv) PR_fprintf(debug_out, "\n"); + else PL_FPrintError(debug_out, "shutdown failed"); + } + } + else + { + if (shared->debug > 1) PL_FPrintError(debug_out, "connect failed"); + PR_Close(clientSock); + if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR)) + { + if (MakeReceiver(shared) == PR_FAILURE) break; + } + else + { + if (shared->debug > 1) PR_fprintf(debug_out, " exiting\n"); + break; + } + } + } + else + { + shared->failed = PR_TRUE; + if (shared->debug > 0) PL_FPrintError(debug_out, "create socket"); + break; + } + } + + PR_DELETE(buffer); +} /* Connect */ + +int Tmocon(int argc, char **argv) +{ + /* + * USAGE + * -d turn on debugging output (default = off) + * -v turn on verbose output (default = off) + * -h dns name of host serving the connection (default = self) + * -i dally intermittantly to cause timeouts (default = off) + * -m number of messages to send (default = 100) + * -s size of each message (default = 100) + * -t number of threads sending (default = 1) + * -G use global threads (default = local) + * -T timeout on I/O operations (seconds) (default = 10) + * -D dally between connect requests (seconds)(default = 0) + * -R randomize the dally types around 'T' (default = no) + */ + + PRStatus rv; + int exitStatus; + PLOptStatus os; + Shared *shared = NULL; + PRThread **thread = NULL; + PRIntn index, threads = DEFAULT_THREADS; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT; + PLOptState *opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:"); + + shared = PR_NEWZAP(Shared); + + shared->debug = 0; + shared->failed = PR_FALSE; + shared->random = PR_FALSE; + shared->messages = DEFAULT_MESSAGES; + shared->message_length = DEFAULT_MESSAGESIZE; + + PR_STDIO_INIT(); + memset(&shared->serverAddress, 0, sizeof(shared->serverAddress)); + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &shared->serverAddress); + PR_ASSERT(PR_SUCCESS == rv); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': + if (0 == shared->debug) shared->debug = 1; + break; + case 'v': + if (0 == shared->debug) shared->debug = 2; + break; + case 'i': + shared->intermittant = PR_TRUE; + break; + case 'R': + shared->random = PR_TRUE; + break; + case 'G': + thread_scope = PR_GLOBAL_THREAD; + break; + case 'h': /* the value for backlock */ + { + PRIntn es = 0; + PRHostEnt host; + char buffer[1024]; + (void)PR_GetHostByName( + opt->value, buffer, sizeof(buffer), &host); + es = PR_EnumerateHostEnt( + es, &host, BASE_PORT, &shared->serverAddress); + PR_ASSERT(es > 0); + } + break; + case 'm': /* number of messages to send */ + shared->messages = atoi(opt->value); + break; + case 't': /* number of threads sending */ + threads = atoi(opt->value); + break; + case 'D': /* dally time between transmissions */ + dally = atoi(opt->value); + break; + case 'T': /* timeout on I/O operations */ + timeout = atoi(opt->value); + break; + case 's': /* total size of each message */ + shared->message_length = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == timeout) timeout = DEFAULT_TIMEOUT; + if (0 == threads) threads = DEFAULT_THREADS; + if (0 == shared->messages) shared->messages = DEFAULT_MESSAGES; + if (0 == shared->message_length) shared->message_length = DEFAULT_MESSAGESIZE; + + shared->dally = PR_SecondsToInterval(dally); + shared->timeout = PR_SecondsToInterval(timeout); + + thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*)); + + for (index = 0; index < threads; ++index) + thread[index] = PR_CreateThread( + PR_USER_THREAD, Connect, shared, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 0); + for (index = 0; index < threads; ++index) + rv = PR_JoinThread(thread[index]); + + PR_DELETE(thread); + + PR_fprintf( + PR_GetSpecialFD(PR_StandardError), "%s\n", + ((shared->failed) ? "FAILED" : "PASSED")); + exitStatus = (shared->failed) ? 1 : 0; + PR_DELETE(shared); + return exitStatus; +} + +int main(int argc, char **argv) +{ + return (PR_VersionCheck(PR_VERSION)) ? + PR_Initialize(Tmocon, argc, argv, 4) : -1; +} /* main */ + +/* tmocon.c */ + + diff --git a/nsprpub/pr/tests/tpd.c b/nsprpub/pr/tests/tpd.c new file mode 100644 index 00000000000..c9bc5c78207 --- /dev/null +++ b/nsprpub/pr/tests/tpd.c @@ -0,0 +1,334 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: tpd.c +** Description: Exercising the thread private data bailywick. +*/ + +#include "prmem.h" +#include "prinit.h" +#include "prlog.h" +#include "prprf.h" +#include "prthread.h" +#include "prtypes.h" + +#if defined(XP_MAC) +#include "pprio.h" +#else +#include "private/pprio.h" +#endif + +#include "plgetopt.h" + +static PRUintn key[128]; +static PRIntn debug = 0; +static PRBool failed = PR_FALSE; +static PRBool should = PR_TRUE; +static PRBool did = PR_TRUE; +static PRFileDesc *fout = NULL; + +static void PrintProgress(PRIntn line) +{ + failed = failed || (should && !did); + failed = failed || (!should && did); + if (debug > 0) + { +#if defined(WIN16) + printf( + "@ line %d destructor should%s have been called and was%s\n", + line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); +#else + PR_fprintf( + fout, "@ line %d destructor should%s have been called and was%s\n", + line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); +#endif + } +} /* PrintProgress */ + +static void MyAssert(const char *expr, const char *file, PRIntn line) +{ + if (debug > 0) + (void)PR_fprintf(fout, "'%s' in file: %s: %d\n", expr, file, line); +} /* MyAssert */ + +#define MY_ASSERT(_expr) \ + ((_expr)?((void)0):MyAssert(# _expr,__FILE__,__LINE__)) + + +static void PR_CALLBACK Destructor(void *data) +{ + MY_ASSERT(NULL != data); + if (should) did = PR_TRUE; + else failed = PR_TRUE; + /* + * 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) +{ + void *pd; + PRStatus rv; + PRUintn keys; + char *key_string[] = { + "Key #0", "Key #1", "Key #2", "Key #3", + "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; + + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = PR_GetThreadPrivate(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + 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 = should = PR_FALSE; + for (keys = 4; keys < 8; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_FAILURE == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + 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; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + 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) +{ + void *pd; + PRStatus rv; + PRUintn keys; + PRThread *thread; + char *key_string[] = { + "Key #0", "Key #1", "Key #2", "Key #3", + "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; + + fout = PR_STDOUT; + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_NewThreadPrivateIndex(&key[keys], Destructor); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = PR_GetThreadPrivate(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + 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__); + + for (keys = 4; keys < 8; ++keys) + key[keys] = 4096; /* set to invalid value */ + did = should = PR_FALSE; + for (keys = 4; keys < 8; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_FAILURE == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + 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; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_NewThreadPrivateIndex(&key[keys], Destructor); + MY_ASSERT(PR_SUCCESS == rv); + rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + + thread = PR_CreateThread( + PR_USER_THREAD, Thread, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + (void)PR_JoinThread(thread); + + PrintProgress(__LINE__); + +#if defined(WIN16) + printf( + "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); +#else + (void)PR_fprintf( + fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); +#endif + + return 0; + +} /* Tpd */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dl:r:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + return PR_Initialize(Tpd, argc, argv, 0); +} /* main */ + +/* tpd.c */ diff --git a/nsprpub/pr/tests/udpsrv.c b/nsprpub/pr/tests/udpsrv.c new file mode 100644 index 00000000000..b9b615a2490 --- /dev/null +++ b/nsprpub/pr/tests/udpsrv.c @@ -0,0 +1,566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/******************************************************************* +** udpsrc.c -- Test basic function of UDP server +** +** udpsrv operates on the same machine with program udpclt. +** udpsrv is the server side of a udp sockets application. +** udpclt is the client side of a udp sockets application. +** +** The test is designed to assist developers in porting/debugging +** the UDP socket functions of NSPR. +** +** This test is not a stress test. +** +** main() starts two threads: UDP_Server() and UDP_Client(); +** main() uses PR_JoinThread() to wait for the threads to complete. +** +** UDP_Server() does repeated recvfrom()s from a socket. +** He detects an EOF condition set by UDP_Client(). For each +** packet received by UDP_Server(), he checks its content for +** expected content, then sends the packet back to UDP_Client(). +** +** UDP_Client() sends packets to UDP_Server() using sendto() +** he recieves packets back from the server via recvfrom(). +** After he sends enough packets containing UDP_AMOUNT_TO_WRITE +** bytes of data, he sends an EOF message. +** +** The test issues a pass/fail message at end. +** +** Notes: +** The variable "_debug_on" can be set to 1 to cause diagnostic +** messages related to client/server synchronization. Useful when +** the test hangs. +** +** Error messages are written to stdout. +** +******************************************************************** +*/ +/* --- include files --- */ +#include "nspr.h" +#include "prpriv.h" + +#include "plgetopt.h" +#include "prttools.h" + +#include +#include +#include +#include + +#ifdef XP_PC +#define mode_t int +#endif + +#define UDP_BUF_SIZE 4096 +#define UDP_DGRAM_SIZE 128 +#define UDP_AMOUNT_TO_WRITE (PRInt32)((UDP_DGRAM_SIZE * 1000l) +1) +#define NUM_UDP_CLIENTS 1 +#define NUM_UDP_DATAGRAMS_PER_CLIENT 5 +#define UDP_SERVER_PORT 9050 +#define UDP_CLIENT_PORT 9053 +#define MY_INADDR PR_INADDR_ANY +#define PEER_INADDR PR_INADDR_LOOPBACK + +#define UDP_TIMEOUT 400000 +/* #define UDP_TIMEOUT PR_INTERVAL_NO_TIMEOUT */ + +/* --- static data --- */ +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) PR_fprintf(output, arg) + + + +/******************************************************************* +** ListNetAddr() -- Display the Net Address on stdout +** +** Description: displays the component parts of a PRNetAddr struct +** +** Arguments: address of PRNetAddr structure to display +** +** Returns: void +** +** Notes: +** +******************************************************************** +*/ +void ListNetAddr( char *msg, PRNetAddr *na ) +{ + char mbuf[256]; + + sprintf( mbuf, "ListNetAddr: %s family: %d, port: %d, ip: %8.8X\n", + msg, na->inet.family, PR_ntohs( na->inet.port), PR_ntohl(na->inet.ip) ); +#if 0 + DPRINTF( mbuf ); +#endif +} /* --- end ListNetAddr() --- */ + +/******************************************************************** +** UDP_Server() -- Test a UDP server application +** +** Description: The Server side of a UDP Client/Server application. +** +** Arguments: none +** +** Returns: void +** +** Notes: +** +** +******************************************************************** +*/ +static void PR_CALLBACK UDP_Server( void *arg ) +{ + static char svrBuf[UDP_BUF_SIZE]; + PRFileDesc *svrSock; + PRInt32 rv; + PRNetAddr netaddr; + PRBool bound = PR_FALSE; + PRBool endOfInput = PR_FALSE; + PRInt32 numBytes = UDP_DGRAM_SIZE; + + DPRINTF("udpsrv: UDP_Server(): starting\n" ); + + /* --- Create the socket --- */ + DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n" ); + svrSock = PR_NewUDPSocket(); + if ( svrSock == NULL ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" ); + return; + } + + /* --- Initialize the sockaddr_in structure --- */ + memset( &netaddr, 0, sizeof( netaddr )); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.port = PR_htons( UDP_SERVER_PORT ); + netaddr.inet.ip = PR_htonl( MY_INADDR ); + + /* --- Bind the socket --- */ + while ( !bound ) + { + DPRINTF("udpsrv: UDP_Server(): Binding socket\n" ); + rv = PR_Bind( svrSock, &netaddr ); + if ( rv < 0 ) + { + if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) + { + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ + PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); + PR_Sleep( PR_MillisecondsToInterval( 2000 )); + continue; + } + else + { + passed = PR_FALSE; + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ + PR_Bind(): failed: %ld with error: %ld\n", + rv, PR_GetError() ); + PR_Close( svrSock ); + return; + } + } + else + bound = PR_TRUE; + } + ListNetAddr( "UDP_Server: after bind", &netaddr ); + + /* --- Recv the socket --- */ + while( !endOfInput ) + { + DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n" ); + rv = PR_RecvFrom( svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT ); + if ( rv == -1 ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n", + PR_GetError() ); + PR_Close( svrSock ); + return; + } + ListNetAddr( "UDP_Server after RecvFrom", &netaddr ); + + srvBytesRead += rv; + + if ( svrBuf[0] == 'E' ) + { + DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" ); + endOfInput = PR_TRUE; + } + + /* --- Send the socket --- */ + DPRINTF("udpsrv: UDP_Server(): SendTo(): socket\n" ); + rv = PR_SendTo( svrSock, svrBuf, rv, 0, &netaddr, PR_INTERVAL_NO_TIMEOUT ); + if ( rv == -1 ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n", + PR_GetError() ); + PR_Close( svrSock ); + return; + } + ListNetAddr( "UDP_Server after SendTo", &netaddr ); + } + + /* --- Close the socket --- */ + DPRINTF("udpsrv: UDP_Server(): Closing socket\n" ); + rv = PR_Close( svrSock ); + if ( rv != PR_SUCCESS ) + { + passed = PR_FALSE; + 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]; +/******************************************************************** +** UDP_Client() -- Test a UDP client application +** +** Description: +** +** Arguments: +** +** +** Returns: +** 0 -- Successful execution +** 1 -- Test failed. +** +** Notes: +** +** +******************************************************************** +*/ +static void PR_CALLBACK UDP_Client( void *arg ) +{ + PRFileDesc *cltSock; + PRInt32 rv; + PRBool bound = PR_FALSE; + PRNetAddr netaddr; + PRNetAddr netaddrx; + PRBool endOfInput = PR_FALSE; + PRInt32 numBytes = UDP_DGRAM_SIZE; + PRInt32 writeThisMany = UDP_AMOUNT_TO_WRITE; + int i; + + + DPRINTF("udpsrv: UDP_Client(): starting\n" ); + + /* --- Create the socket --- */ + cltSock = PR_NewUDPSocket(); + if ( cltSock == NULL ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" ); + return; + } + + /* --- Initialize the sockaddr_in structure --- */ + memset( &netaddr, 0, sizeof( netaddr )); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.ip = PR_htonl( MY_INADDR ); + netaddr.inet.port = PR_htons( UDP_CLIENT_PORT ); + + /* --- Initialize the write buffer --- */ + for ( i = 0; i < UDP_BUF_SIZE ; i++ ) + cltBuf[i] = i; + + /* --- Bind the socket --- */ + while ( !bound ) + { + DPRINTF("udpsrv: UDP_Client(): Binding socket\n" ); + rv = PR_Bind( cltSock, &netaddr ); + if ( rv < 0 ) + { + if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) + { + 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) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n", + rv, PR_GetError() ); + PR_Close( cltSock ); + return; + } + } + else + bound = PR_TRUE; + } + ListNetAddr( "UDP_Client after Bind", &netaddr ); + + /* --- Initialize the sockaddr_in structure --- */ + memset( &netaddr, 0, sizeof( netaddr )); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.ip = PR_htonl( PEER_INADDR ); + netaddr.inet.port = PR_htons( UDP_SERVER_PORT ); + + /* --- send and receive packets until no more data left */ + while( !endOfInput ) + { + /* + ** Signal EOF in the data stream on the last packet + */ + if ( writeThisMany <= UDP_DGRAM_SIZE ) + { + DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n" ); + cltBuf[0] = 'E'; + endOfInput = PR_TRUE; + } + + /* --- SendTo the socket --- */ + if ( writeThisMany > UDP_DGRAM_SIZE ) + numBytes = UDP_DGRAM_SIZE; + else + numBytes = writeThisMany; + writeThisMany -= numBytes; + { + char mbuf[256]; + sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n", + writeThisMany, numBytes ); + DPRINTF( mbuf ); + } + + DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n" ); + rv = PR_SendTo( cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT ); + if ( rv == -1 ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n", + PR_GetError() ); + PR_Close( cltSock ); + return; + } + ListNetAddr( "UDP_Client after SendTo", &netaddr ); + + /* --- RecvFrom the socket --- */ + memset( cltBufin, 0, UDP_BUF_SIZE ); + DPRINTF("udpsrv: UDP_Client(): RecvFrom(): socket\n" ); + rv = PR_RecvFrom( cltSock, cltBufin, numBytes, 0, &netaddrx, UDP_TIMEOUT ); + if ( rv == -1 ) + { + passed = PR_FALSE; + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n", + PR_GetError() ); + PR_Close( cltSock ); + return; + } + ListNetAddr( "UDP_Client after RecvFrom()", &netaddr ); + cltBytesRead += rv; + + /* --- verify buffer --- */ + for ( i = 0; i < rv ; i++ ) + { + if ( cltBufin[i] != i ) + { + /* --- special case, end of input --- */ + if ( endOfInput && i == 0 && cltBufin[0] == 'E' ) + continue; + passed = PR_FALSE; + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): return data mismatch\n" ); + PR_Close( cltSock ); + return; + } + } + if (debug_mode) PR_fprintf(output, "."); + } + + /* --- Close the socket --- */ + DPRINTF("udpsrv: UDP_Server(): Closing socket\n" ); + rv = PR_Close( cltSock ); + if ( rv != PR_SUCCESS ) + { + passed = PR_FALSE; + 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 +** +** arguments: +** +** Returns: +** 0 -- Successful execution +** 1 -- Test failed. +** +** Description: +** +** Standard test case setup. +** +** Calls the function UDP_Server() +** +******************************************************************** +*/ + +int main(int argc, char **argv) +{ + PRThread *srv, *clt; +/* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d -v + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dv"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'v': /* verbose mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + output = PR_STDERR; + +#ifdef XP_MAC + SetupMacPrintfLog("udpsrv.log"); +#endif + + PR_SetConcurrency(4); + + /* + ** Create the Server thread + */ + DPRINTF( "udpsrv: Creating Server Thread\n" ); + srv = PR_CreateThread( PR_USER_THREAD, + UDP_Server, + (void *) 0, + PR_PRIORITY_LOW, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + if ( srv == NULL ) + { + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); + passed = PR_FALSE; + } + + /* + ** Give the Server time to Start + */ + DPRINTF( "udpsrv: Pausing to allow Server to start\n" ); + PR_Sleep( PR_MillisecondsToInterval(200) ); + + /* + ** Create the Client thread + */ + DPRINTF( "udpsrv: Creating Client Thread\n" ); + clt = PR_CreateThread( PR_USER_THREAD, + UDP_Client, + (void *) 0, + PR_PRIORITY_LOW, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + if ( clt == NULL ) + { + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); + passed = PR_FALSE; + } + + /* + ** + */ + DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" ); + PR_JoinThread( srv ); + PR_JoinThread( clt ); + + /* + ** Evaluate test results + */ + 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 ) + { + passed = PR_FALSE; + } + PR_Cleanup(); + if ( passed ) + return 0; + else + return 1; +} /* --- end main() --- */ diff --git a/nsprpub/pr/tests/ut_ttools.h b/nsprpub/pr/tests/ut_ttools.h new file mode 100644 index 00000000000..dc38f316a07 --- /dev/null +++ b/nsprpub/pr/tests/ut_ttools.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Used in Regress Tool */ +#define NOSTATUS 2 +#define PASS 1 +#define FAIL 0 + +PRIntn debug_mode=0; diff --git a/nsprpub/pr/tests/vercheck.c b/nsprpub/pr/tests/vercheck.c new file mode 100644 index 00000000000..c47eb899d6f --- /dev/null +++ b/nsprpub/pr/tests/vercheck.c @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * File: vercheck.c + * + * Description: + * This test tests the PR_VersionCheck() function. The + * compatible_version and incompatible_version arrays + * need to be updated for each patch or release. + * + * Tested areas: library version compatibility check. + */ + +#include "prinit.h" + +#include +#include + +/* + * This release (4.7) is backward compatible with the + * 4.0.x, 4.1.x, 4.2.x, 4.3.x, 4.4.x, 4.5.x, and 4.6.x releases. + * It, of course, is compatible with itself. + */ +static char *compatible_version[] = { + "4.0", "4.0.1", "4.1", "4.1.1", "4.1.2", "4.1.3", + "4.2", "4.2.1", "4.2.2", "4.3", "4.4", "4.4.1", + "4.5", "4.5.1", + "4.6", "4.6.1", "4.6.2", "4.6.3", "4.6.4", "4.6.5", "4.6.6", "4.6.7", "4.6.8", + "4.7", PR_VERSION +}; + +/* + * This release is not backward compatible with the old + * NSPR 2.1 and 3.x releases. + * + * Any release is incompatible with future releases and + * patches. + */ +static char *incompatible_version[] = { + "2.1 19980529", + "3.0", "3.0.1", + "3.1", "3.1.1", "3.1.2", "3.1.3", + "3.5", "3.5.1", + "4.7.3", + "4.8", "4.8.1", + "10.0", "11.1", "12.14.20" +}; + +int main() +{ + int idx; + int num_compatible = sizeof(compatible_version) / sizeof(char *); + int num_incompatible = sizeof(incompatible_version) / sizeof(char *); + + printf("NSPR release %s:\n", PR_VERSION); + for (idx = 0; idx < num_compatible; idx++) { + if (PR_VersionCheck(compatible_version[idx]) == PR_FALSE) { + fprintf(stderr, "Should be compatible with version %s\n", + compatible_version[idx]); + exit(1); + } + printf("Compatible with version %s\n", compatible_version[idx]); + } + + for (idx = 0; idx < num_incompatible; idx++) { + if (PR_VersionCheck(incompatible_version[idx]) == PR_TRUE) { + fprintf(stderr, "Should be incompatible with version %s\n", + incompatible_version[idx]); + exit(1); + } + printf("Incompatible with version %s\n", incompatible_version[idx]); + } + + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/version.c b/nsprpub/pr/tests/version.c new file mode 100644 index 00000000000..597f5571ffe --- /dev/null +++ b/nsprpub/pr/tests/version.c @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prprf.h" +#include "prlink.h" +#include "prvrsion.h" + +#include "plerror.h" +#include "plgetopt.h" + +PR_IMPORT(const PRVersionDescription *) libVersionPoint(void); + +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; + char buffer[100]; + PRExplodedTime exploded; + 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) + { + runtime = PR_LoadLibrary(library_name); + if (NULL == runtime) { + PL_FPrintError(err, "PR_LoadLibrary"); + return 3; + } else { + versionEntryPointType versionPoint = (versionEntryPointType) + PR_FindSymbol(runtime, "libVersionPoint"); + if (NULL == versionPoint) { + PL_FPrintError(err, "PR_FindSymbol"); + return 4; + } + version_info = versionPoint(); + } + } else + version_info = libVersionPoint(); /* NSPR's version info */ + + (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 */ diff --git a/nsprpub/pr/tests/writev.c b/nsprpub/pr/tests/writev.c new file mode 100644 index 00000000000..603526c9f16 --- /dev/null +++ b/nsprpub/pr/tests/writev.c @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nspr.h" + +#include "plgetopt.h" + +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + + +#ifndef IOV_MAX +#define IOV_MAX 16 +#endif + +#define BASE_PORT 9867 + +int PR_CALLBACK Writev(int argc, char **argv) +{ + + PRStatus rv; + PRNetAddr serverAddr; + PRFileDesc *clientSock, *debug = NULL; + + char *buffer = NULL; + PRIOVec *iov = NULL; + PRBool passed = PR_TRUE; + PRIntervalTime timein, elapsed, timeout; + PRIntervalTime tmo_min = 0x7fffffff, tmo_max = 0, tmo_elapsed = 0; + PRInt32 tmo_counted = 0, iov_index, loop, bytes, number_fragments; + PRInt32 message_length = 100, fragment_length = 100, messages = 100; + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; + + /* + * USAGE + * -h dns name of host serving the connection (default = self) + * -m number of messages to send (default = 100) + * -s size of each message (default = 100) + * -f size of each message fragment (default = 100) + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dh:m:s:f:"); + + PR_STDIO_INIT(); + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddr); + PR_ASSERT(PR_SUCCESS == rv); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'h': /* the remote host */ + { + PRIntn es = 0; + PRHostEnt host; + char buffer[1024]; + (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host); + es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &serverAddr); + PR_ASSERT(es > 0); + } + break; + case 'd': /* debug mode */ + debug = PR_GetSpecialFD(PR_StandardError); + break; + case 'm': /* number of messages to send */ + messages = atoi(opt->value); + break; + case 's': /* total size of each message */ + message_length = atoi(opt->value); + break; + case 'f': /* size of each message fragment */ + fragment_length = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + buffer = (char*)malloc(message_length); + + number_fragments = (message_length + fragment_length - 1) / fragment_length + 1; + while (IOV_MAX < number_fragments) + { + fragment_length = message_length / (IOV_MAX - 2); + number_fragments = (message_length + fragment_length - 1) / + fragment_length + 1; + if (NULL != debug) PR_fprintf(debug, + "Too many fragments - reset fragment length to %ld\n", fragment_length); + } + iov = (PRIOVec*)malloc(number_fragments * sizeof(PRIOVec)); + + iov[0].iov_base = (char*)&descriptor; + iov[0].iov_len = sizeof(descriptor); + for (iov_index = 1; iov_index < number_fragments; ++iov_index) + { + iov[iov_index].iov_base = buffer + (iov_index - 1) * fragment_length; + iov[iov_index].iov_len = fragment_length; + } + + for (bytes = 0; bytes < message_length; ++bytes) + buffer[bytes] = (char)bytes; + + timeout = PR_SecondsToInterval(1); + + for (loop = 0; loop < messages; ++loop) + { + if (NULL != debug) + PR_fprintf(debug, "[%d]socket ... ", loop); + clientSock = PR_NewTCPSocket(); + if (clientSock) + { + timein = PR_IntervalNow(); + if (NULL != debug) + PR_fprintf(debug, "connecting ... "); + rv = PR_Connect(clientSock, &serverAddr, timeout); + if (PR_SUCCESS == rv) + { + descriptor.checksum = 0; + descriptor.length = (loop < (messages - 1)) ? message_length : 0; + if (0 == descriptor.length) number_fragments = 1; + else + for (iov_index = 0; iov_index < descriptor.length; ++iov_index) + { + PRUint32 overflow = descriptor.checksum & 0x80000000; + descriptor.checksum = (descriptor.checksum << 1); + if (0x00000000 != overflow) descriptor.checksum += 1; + descriptor.checksum += buffer[iov_index]; + } + if (NULL != debug) PR_fprintf( + debug, "sending %d bytes ... ", descriptor.length); + + /* then, at the last moment ... */ + descriptor.length = PR_ntohl(descriptor.length); + descriptor.checksum = PR_ntohl(descriptor.checksum); + + bytes = PR_Writev(clientSock, iov, number_fragments, timeout); + if (NULL != debug) + PR_fprintf(debug, "closing ... "); + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); + rv = PR_Close(clientSock); + if (NULL != debug) PR_fprintf( + debug, "%s\n", ((PR_SUCCESS == rv) ? "good" : "bad")); + elapsed = PR_IntervalNow() - timein; + if (elapsed < tmo_min) tmo_min = elapsed; + else if (elapsed > tmo_max) tmo_max = elapsed; + tmo_elapsed += elapsed; + tmo_counted += 1; + } + else + { + if (NULL != debug) PR_fprintf( + debug, "failed - retrying (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + PR_Close(clientSock); + } + } + else if (NULL != debug) + { + PR_fprintf(debug, "unable to create client socket\n"); + passed = PR_FALSE; + } + } + if (NULL != debug) { + if (0 == tmo_counted) { + PR_fprintf(debug, "No connection made\n"); + } else { + PR_fprintf( + debug, "\nTimings: %d [%d] %d (microseconds)\n", + PR_IntervalToMicroseconds(tmo_min), + PR_IntervalToMicroseconds(tmo_elapsed / tmo_counted), + PR_IntervalToMicroseconds(tmo_max)); + } + } + + PR_DELETE(buffer); + PR_DELETE(iov); + + PR_fprintf( + PR_GetSpecialFD(PR_StandardError), + "%s\n", (passed) ? "PASSED" : "FAILED"); + return (passed) ? 0 : 1; +} + +int main(int argc, char **argv) +{ + return (PR_VersionCheck(PR_VERSION)) ? + PR_Initialize(Writev, argc, argv, 4) : -1; +} /* main */ + +/* writev.c */ + + diff --git a/nsprpub/pr/tests/xnotify.c b/nsprpub/pr/tests/xnotify.c new file mode 100644 index 00000000000..97f64917803 --- /dev/null +++ b/nsprpub/pr/tests/xnotify.c @@ -0,0 +1,389 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "plerror.h" +#include "plgetopt.h" + +#include "prinit.h" +#include "prprf.h" +#include "prio.h" +#include "prcvar.h" +#include "prmon.h" +#include "prcmon.h" +#include "prlock.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prthread.h" + +static PRLock *ml = NULL; +static PRIntervalTime base; +static PRFileDesc *err = NULL; + +typedef struct CMonShared +{ + PRInt32 o1, o2; +} CMonShared; + +typedef struct MonShared +{ + PRMonitor *o1, *o2; +} MonShared; + +typedef struct LockShared +{ + PRLock *o1, *o2; + PRCondVar *cv1, *cv2; +} LockShared; + +static void LogNow(const char *msg, PRStatus rv) +{ + PRIntervalTime now = PR_IntervalNow(); + PR_Lock(ml); + PR_fprintf(err, "%6ld: %s", (now - base), msg); + if (PR_FAILURE == rv) PL_FPrintError(err, " "); + else PR_fprintf(err, "\n"); + PR_Unlock(ml); +} /* LogNow */ + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-[d][l][m][c]] [-h]\n"); + PR_fprintf(err, "\t-d debug mode (default: FALSE)\n"); + PR_fprintf(err, "\t-l test with locks (default: FALSE)\n"); + PR_fprintf(err, "\t-m tests with monitors (default: FALSE)\n"); + PR_fprintf(err, "\t-c tests with cmonitors (default: FALSE)\n"); + PR_fprintf(err, "\t-h help\n"); +} /* Help */ + +static void PR_CALLBACK T2CMon(void *arg) +{ + PRStatus rv; + CMonShared *shared = (CMonShared*)arg; + + PR_CEnterMonitor(&shared->o1); + LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); + rv = PR_CWait(&shared->o1, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T2 resuming on o1", rv); + else LogNow("T2 wait failed on o1", rv); + + rv = PR_CNotify(&shared->o1); + if (PR_SUCCESS == rv) LogNow("T2 notified o1", rv); + else LogNow("T2 notify on o1 failed", rv); + + PR_CExitMonitor(&shared->o1); +} /* T2CMon */ + +static void PR_CALLBACK T3CMon(void *arg) +{ + PRStatus rv; + CMonShared *shared = (CMonShared*)arg; + + PR_CEnterMonitor(&shared->o2); + LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); + rv = PR_CWait(&shared->o2, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T3 resuming on o2", rv); + else LogNow("T3 wait failed on o2", rv); + rv = PR_CNotify(&shared->o2); + LogNow("T3 notify on o2", rv); + PR_CExitMonitor(&shared->o2); + +} /* T3CMon */ + +static CMonShared sharedCM; + +static void T1CMon(void) +{ + PRStatus rv; + PRThread *t2, *t3; + + PR_fprintf(err, "\n**********************************\n"); + PR_fprintf(err, " CACHED MONITORS\n"); + PR_fprintf(err, "**********************************\n"); + + base = PR_IntervalNow(); + + PR_CEnterMonitor(&sharedCM.o1); + LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); + rv = PR_CWait(&sharedCM.o1, PR_SecondsToInterval(3)); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o1", rv); + else LogNow("T1 wait on o1 failed", rv); + PR_CExitMonitor(&sharedCM.o1); + + LogNow("T1 creating T2", PR_SUCCESS); + t2 = PR_CreateThread( + PR_USER_THREAD, T2CMon, &sharedCM, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + LogNow("T1 creating T3", PR_SUCCESS); + t3 = PR_CreateThread( + PR_USER_THREAD, T3CMon, &sharedCM, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + PR_CEnterMonitor(&sharedCM.o2); + LogNow("T1 waiting forever on o2", PR_SUCCESS); + rv = PR_CWait(&sharedCM.o2, PR_INTERVAL_NO_TIMEOUT); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o2", rv); + else LogNow("T1 wait on o2 failed", rv); + PR_CExitMonitor(&sharedCM.o2); + + (void)PR_JoinThread(t2); + (void)PR_JoinThread(t3); + +} /* T1CMon */ + +static void PR_CALLBACK T2Mon(void *arg) +{ + PRStatus rv; + MonShared *shared = (MonShared*)arg; + + PR_EnterMonitor(shared->o1); + LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); + rv = PR_Wait(shared->o1, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T2 resuming on o1", rv); + else LogNow("T2 wait failed on o1", rv); + + rv = PR_Notify(shared->o1); + if (PR_SUCCESS == rv) LogNow("T2 notified o1", rv); + else LogNow("T2 notify on o1 failed", rv); + + PR_ExitMonitor(shared->o1); +} /* T2Mon */ + +static void PR_CALLBACK T3Mon(void *arg) +{ + PRStatus rv; + MonShared *shared = (MonShared*)arg; + + PR_EnterMonitor(shared->o2); + LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); + rv = PR_Wait(shared->o2, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T3 resuming on o2", rv); + else LogNow("T3 wait failed on o2", rv); + rv = PR_Notify(shared->o2); + LogNow("T3 notify on o2", rv); + PR_ExitMonitor(shared->o2); + +} /* T3Mon */ + +static MonShared sharedM; +static void T1Mon(void) +{ + PRStatus rv; + PRThread *t2, *t3; + + PR_fprintf(err, "\n**********************************\n"); + PR_fprintf(err, " MONITORS\n"); + PR_fprintf(err, "**********************************\n"); + + sharedM.o1 = PR_NewMonitor(); + sharedM.o2 = PR_NewMonitor(); + + base = PR_IntervalNow(); + + PR_EnterMonitor(sharedM.o1); + LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); + rv = PR_Wait(sharedM.o1, PR_SecondsToInterval(3)); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o1", rv); + else LogNow("T1 wait on o1 failed", rv); + PR_ExitMonitor(sharedM.o1); + + LogNow("T1 creating T2", PR_SUCCESS); + t2 = PR_CreateThread( + PR_USER_THREAD, T2Mon, &sharedM, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + LogNow("T1 creating T3", PR_SUCCESS); + t3 = PR_CreateThread( + PR_USER_THREAD, T3Mon, &sharedM, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + PR_EnterMonitor(sharedM.o2); + LogNow("T1 waiting forever on o2", PR_SUCCESS); + rv = PR_Wait(sharedM.o2, PR_INTERVAL_NO_TIMEOUT); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o2", rv); + else LogNow("T1 wait on o2 failed", rv); + PR_ExitMonitor(sharedM.o2); + + (void)PR_JoinThread(t2); + (void)PR_JoinThread(t3); + + PR_DestroyMonitor(sharedM.o1); + PR_DestroyMonitor(sharedM.o2); + +} /* T1Mon */ + +static void PR_CALLBACK T2Lock(void *arg) +{ + PRStatus rv; + LockShared *shared = (LockShared*)arg; + + PR_Lock(shared->o1); + LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); + rv = PR_WaitCondVar(shared->cv1, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T2 resuming on o1", rv); + else LogNow("T2 wait failed on o1", rv); + + rv = PR_NotifyCondVar(shared->cv1); + if (PR_SUCCESS == rv) LogNow("T2 notified o1", rv); + else LogNow("T2 notify on o1 failed", rv); + + PR_Unlock(shared->o1); +} /* T2Lock */ + +static void PR_CALLBACK T3Lock(void *arg) +{ + PRStatus rv; + LockShared *shared = (LockShared*)arg; + + PR_Lock(shared->o2); + LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); + rv = PR_WaitCondVar(shared->cv2, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T3 resuming on o2", rv); + else LogNow("T3 wait failed on o2", rv); + rv = PR_NotifyCondVar(shared->cv2); + LogNow("T3 notify on o2", rv); + PR_Unlock(shared->o2); + +} /* T3Lock */ + +/* +** Make shared' a static variable for Win16 +*/ +static LockShared sharedL; + +static void T1Lock(void) +{ + PRStatus rv; + PRThread *t2, *t3; + sharedL.o1 = PR_NewLock(); + sharedL.o2 = PR_NewLock(); + sharedL.cv1 = PR_NewCondVar(sharedL.o1); + sharedL.cv2 = PR_NewCondVar(sharedL.o2); + + PR_fprintf(err, "\n**********************************\n"); + PR_fprintf(err, " LOCKS\n"); + PR_fprintf(err, "**********************************\n"); + + base = PR_IntervalNow(); + + PR_Lock(sharedL.o1); + LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); + rv = PR_WaitCondVar(sharedL.cv1, PR_SecondsToInterval(3)); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o1", rv); + else LogNow("T1 wait on o1 failed", rv); + PR_Unlock(sharedL.o1); + + LogNow("T1 creating T2", PR_SUCCESS); + t2 = PR_CreateThread( + PR_USER_THREAD, T2Lock, &sharedL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + LogNow("T1 creating T3", PR_SUCCESS); + t3 = PR_CreateThread( + PR_USER_THREAD, T3Lock, &sharedL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + PR_Lock(sharedL.o2); + LogNow("T1 waiting forever on o2", PR_SUCCESS); + rv = PR_WaitCondVar(sharedL.cv2, PR_INTERVAL_NO_TIMEOUT); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o2", rv); + else LogNow("T1 wait on o2 failed", rv); + PR_Unlock(sharedL.o2); + + (void)PR_JoinThread(t2); + (void)PR_JoinThread(t3); + + PR_DestroyLock(sharedL.o1); + PR_DestroyLock(sharedL.o2); + PR_DestroyCondVar(sharedL.cv1); + PR_DestroyCondVar(sharedL.cv2); +} /* T1Lock */ + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dhlmc"); + PRBool locks = PR_FALSE, monitors = PR_FALSE, cmonitors = PR_FALSE; + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode (noop) */ + break; + case 'l': /* locks */ + locks = PR_TRUE; + break; + case 'm': /* monitors */ + monitors = PR_TRUE; + break; + case 'c': /* cached monitors */ + cmonitors = PR_TRUE; + break; + case 'h': /* needs guidance */ + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + ml = PR_NewLock(); + if (locks) T1Lock(); + if (monitors) T1Mon(); + if (cmonitors) T1CMon(); + + PR_DestroyLock(ml); + + PR_fprintf(err, "Done!\n"); + return 0; +} /* main */ + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ +/* xnotify.c */ diff --git a/nsprpub/pr/tests/y2k.c b/nsprpub/pr/tests/y2k.c new file mode 100644 index 00000000000..80fc10a54f7 --- /dev/null +++ b/nsprpub/pr/tests/y2k.c @@ -0,0 +1,840 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * file: y2k.c + * description: Test for y2k compliance for NSPR. + * + * Sep 1999. lth. Added "Sun" specified dates to the test data. + */ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prtime.h" +#include "prprf.h" +#include "prlog.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#include "macstdlibextras.h" +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define PRINT_DETAILS + +int failed_already=0; +PRBool debug_mode = PR_FALSE; + +static char *dayOfWeek[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" }; +static char *month[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; + +PRLogModuleInfo *lm; + +static void PrintExplodedTime(const PRExplodedTime *et) { + PRInt32 totalOffset; + PRInt32 hourOffset, minOffset; + const char *sign; + + /* Print day of the week, month, day, hour, minute, and second */ + printf("%s %s %2ld %02ld:%02ld:%02ld ", + dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday, + et->tm_hour, et->tm_min, et->tm_sec); + + /* Print year */ + printf("%hd ", et->tm_year); + + /* Print time zone */ + totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset; + if (totalOffset == 0) { + printf("UTC "); + } else { + sign = "+"; + if (totalOffset < 0) { + totalOffset = -totalOffset; + sign = "-"; + } + hourOffset = totalOffset / 3600; + minOffset = (totalOffset % 3600) / 60; + printf("%s%02ld%02ld ", sign, hourOffset, minOffset); + } +#ifdef PRINT_DETAILS + printf("{%d, %d, %d, %d, %d, %d, %d, %d, %d, { %d, %d}}\n",et->tm_usec, + et->tm_sec, + et->tm_min, + et->tm_hour, + et->tm_mday, + et->tm_month, + et->tm_year, + et->tm_wday, + et->tm_yday, + et->tm_params.tp_gmt_offset, + et->tm_params.tp_dst_offset); +#endif +} + +static int ExplodedTimeIsEqual(const PRExplodedTime *et1, + const PRExplodedTime *et2) +{ + if (et1->tm_usec == et2->tm_usec && + et1->tm_sec == et2->tm_sec && + et1->tm_min == et2->tm_min && + et1->tm_hour == et2->tm_hour && + et1->tm_mday == et2->tm_mday && + et1->tm_month == et2->tm_month && + et1->tm_year == et2->tm_year && + et1->tm_wday == et2->tm_wday && + et1->tm_yday == et2->tm_yday && + et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset && + et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) { + return 1; + } else { + return 0; + } +} + +/* + * TEST 1: TestExplodeImplodeTime + * Description: + * For each given timestamp T (a PRTime value), call PR_ExplodeTime + * with GMT, US Pacific, and local time parameters. Compare the + * resulting calendar (exploded) time values with the expected + * values. + * + * Note: the expected local time values depend on the local time + * zone. The local time values stored in this test are for the US + * Pacific Time Zone. If you are running this test in a different + * time zone, you need to modify the values in the localt array. + * An example is provided below. + * + * Call PR_ImplodeTime for each of the exploded values and compare + * the resulting PRTime values with the original input. + * + * This test is run for the values of time T corresponding to the + * following dates: + * - 12/31/99 - before 2000 + * - 01/01/00 - after 2000 + * - Leap year - Feb 29, 2000 + * - March 1st, 2001 (after 1 year) + * - March 1st, 2005 (after second leap year) + * - 09/09/99 (used by some programs as an end of file marker) + * + * Call PR_Now, convert to calendar time using PR_ExplodeTime and + * manually check the result for correctness. The time should match + * the system clock. + * + * Tested functions: PR_Now, PR_ExplodeTime, PR_ImplodeTime, + * PR_LocalTimeParameters, PR_GMTParameters. + */ + +static PRTime prt[] = { + LL_INIT(220405, 2133125120), /* 946634400000000 */ + LL_INIT(220425, 2633779200), /* 946720800000000 */ + LL_INIT(221612, 2107598848), /* 951818400000000 */ + LL_INIT(228975, 663398400), /* 983440800000000 */ + LL_INIT(258365, 1974568960), /* 1109671200000000 */ + LL_INIT(218132, 1393788928), /* 936871200000000 */ + /* Sun's dates follow */ + LL_INIT( 213062, 4077979648 ), /* Dec 31 1998 10:00:00 */ + LL_INIT( 218152, 1894443008 ), /* Sep 10 1999 10:00:00 */ + LL_INIT( 221592, 1606944768 ), /* Feb 28 2000 10:00:00 */ + LL_INIT( 227768, 688924672 ), /* Dec 31 2000 10:00:00 */ + LL_INIT( 227788, 1189578752 ), /* Jan 1 2001 10:00:00 */ +}; + +static PRExplodedTime gmt[] = { + { 0, 0, 0, 10, 31, 11, 1999, 5, 364, {0, 0}}, /* 1999/12/31 10:00:00 GMT */ + { 0, 0, 0, 10, 1, 0, 2000, 6, 0, {0, 0}}, /* 2000/01/01 10:00:00 GMT */ + { 0, 0, 0, 10, 29, 1, 2000, 2, 59, {0, 0}}, /* 2000/02/29 10:00:00 GMT */ + { 0, 0, 0, 10, 1, 2, 2001, 4, 59, {0, 0}}, /* 2001/3/1 10:00:00 GMT */ + { 0, 0, 0, 10, 1, 2, 2005, 2, 59, {0, 0}}, /* 2005/3/1 10:00:00 GMT */ + { 0, 0, 0, 10, 9, 8, 1999, 4, 251, {0, 0}}, /* 1999/9/9 10:00:00 GMT */ + /* Sun's dates follow */ + { 0, 0, 0, 10, 31, 11, 1998, 4, 364, {0, 0}}, /* 12/31/1998 10:00:00 GMT */ + { 0, 0, 0, 10, 10, 8, 1999, 5, 252, {0, 0}}, /* 9/10/1999 10:00:00 GMT */ + { 0, 0, 0, 10, 28, 1, 2000, 1, 58, {0, 0}}, /* 2/28/2000 10:00:00 GMT */ + { 0, 0, 0, 10, 31, 11, 2000, 0, 365, {0, 0}}, /* 12/31/2000 10:00:00 GMT */ + { 0, 0, 0, 10, 1, 0, 2001, 1, 0, {0, 0}} /* 1/1/2001 10:00:00 GMT */ +}; + +static PRExplodedTime uspt[] = { +{ 0, 0, 0, 2, 31, 11, 1999, 5, 364, {-28800, 0}}, /* 1999/12/31 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 0, 2000, 6, 0, {-28800, 0}}, /* 2000/01/01 2:00:00 PST */ +{ 0, 0, 0, 2, 29, 1, 2000, 2, 59, {-28800, 0}}, /* 2000/02/29 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 2, 2001, 4, 59, {-28800, 0}}, /* 2001/3/1 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 2, 2005, 2, 59, {-28800, 0}}, /* 2005/3/1 2:00:00 PST */ +{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}}, /* 1999/9/9 3:00:00 PDT */ + /* Sun's dates follow */ + { 0, 0, 0, 2, 31, 11, 1998, 4, 364, {-28800, 0}}, /* 12/31/1998 00:00:00 GMT */ + { 0, 0, 0, 3, 10, 8, 1999, 5, 252, {-28800, 3600}}, /* 9/10/1999 00:00:00 GMT */ + { 0, 0, 0, 2, 28, 1, 2000, 1, 58, {-28800, 0}}, /* 2/28/2000 00:00:00 GMT */ + { 0, 0, 0, 2, 31, 11, 2000, 0, 365, {-28800, 0}}, /* 12/31/2000 00:00:00 GMT */ + { 0, 0, 0, 2, 1, 0, 2001, 1, 0, {-28800, 0}} /* 1/1/2001 00:00:00 GMT */ +}; + +/* + * This test assumes that we are in US Pacific Time Zone. + * If you are running this test in a different time zone, + * you need to modify the localt array and fill in the + * expected results. The localt array for US Eastern Time + * Zone is provided as an example. + */ +static PRExplodedTime localt[] = { +{ 0, 0, 0, 2, 31, 11, 1999, 5, 364, {-28800, 0}}, /* 1999/12/31 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 0, 2000, 6, 0, {-28800, 0}}, /* 2000/01/01 2:00:00 PST */ +{ 0, 0, 0, 2, 29, 1, 2000, 2, 59, {-28800, 0}}, /* 2000/02/29 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 2, 2001, 4, 59, {-28800, 0}}, /* 2001/3/1 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 2, 2005, 2, 59, {-28800, 0}}, /* 2005/3/1 2:00:00 PST */ +{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}}, /* 1999/9/9 3:00:00 PDT */ + /* Sun's dates follow */ + { 0, 0, 0, 2, 31, 11, 1998, 4, 364, {-28800, 0}}, /* 12/31/1998 00:00:00 GMT */ + { 0, 0, 0, 3, 10, 8, 1999, 5, 252, {-28800, 3600}}, /* 9/10/1999 00:00:00 GMT */ + { 0, 0, 0, 2, 28, 1, 2000, 1, 58, {-28800, 0}}, /* 2/28/2000 00:00:00 GMT */ + { 0, 0, 0, 2, 31, 11, 2000, 0, 365, {-28800, 0}}, /* 12/31/2000 00:00:00 GMT */ + { 0, 0, 0, 2, 1, 0, 2001, 1, 0, {-28800, 0}} /* 1/1/2001 00:00:00 GMT */ +}; + +#ifdef US_EASTERN_TIME +static PRExplodedTime localt[] = { +{ 0, 0, 0, 5, 31, 11, 1999, 5, 364, {-18000, 0}}, /* 1999/12/31 2:00:00 EST */ +{ 0, 0, 0, 5, 1, 0, 2000, 6, 0, {-18000, 0}}, /* 2000/01/01 2:00:00 EST */ +{ 0, 0, 0, 5, 29, 1, 2000, 2, 59, {-18000, 0}}, /* 2000/02/29 2:00:00 EST */ +{ 0, 0, 0, 5, 1, 2, 2001, 4, 59, {-18000, 0}}, /* 2001/3/1 2:00:00 EST */ +{ 0, 0, 0, 5, 1, 2, 2005, 2, 59, {-18000, 0}}, /* 2005/3/1 2:00:00 EST */ +{ 0, 0, 0, 6, 9, 8, 1999, 4, 251, {-18000, 3600}}, /* 1999/9/9 3:00:00 EDT */ + /* Sun's dates follow */ + { 0, 0, 0, 5, 31, 11, 1998, 4, 364, {-18000 0}}, /* 12/31/1998 00:00:00 GMT */ + { 0, 0, 0, 6, 10, 8, 1999, 5, 252, {-18000 3600}}, /* 9/10/1999 00:00:00 GMT */ + { 0, 0, 0, 5, 28, 1, 2000, 1, 58, {-18000 0}}, /* 2/28/2000 00:00:00 GMT */ + { 0, 0, 0, 5, 31, 11, 2000, 0, 365, {-18000 0}}, /* 12/31/2000 00:00:00 GMT */ + { 0, 0, 0, 5, 1, 0, 2001, 1, 0, {-18000 0}} /* 1/1/2001 00:00:00 GMT */ +}; +#endif + +static PRStatus TestExplodeImplodeTime(void) +{ + PRTime prt_tmp; + PRTime now; + int idx; + int array_size = sizeof(prt) / sizeof(PRTime); + PRExplodedTime et_tmp; + char buf[1024]; + + for (idx = 0; idx < array_size; idx++) { + PR_snprintf(buf, sizeof(buf), "%lld", prt[idx]); + if (debug_mode) printf("Time stamp %s\n", buf); + PR_ExplodeTime(prt[idx], PR_GMTParameters, &et_tmp); + if (!ExplodedTimeIsEqual(&et_tmp, &gmt[idx])) { + fprintf(stderr, "GMT not equal\n"); + PrintExplodedTime(&et_tmp); + PrintExplodedTime(&gmt[idx]); + exit(1); + } + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, prt[idx])) { + fprintf(stderr, "PRTime not equal\n"); + exit(1); + } + if (debug_mode) { + printf("GMT: "); + PrintExplodedTime(&et_tmp); + printf("\n"); + } + + PR_ExplodeTime(prt[idx], PR_USPacificTimeParameters, &et_tmp); + if (!ExplodedTimeIsEqual(&et_tmp, &uspt[idx])) { + fprintf(stderr, "US Pacific Time not equal\n"); + PrintExplodedTime(&et_tmp); + PrintExplodedTime(&uspt[idx]); + exit(1); + } + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, prt[idx])) { + fprintf(stderr, "PRTime not equal\n"); + exit(1); + } + if (debug_mode) { + printf("US Pacific Time: "); + PrintExplodedTime(&et_tmp); + printf("\n"); + } + + PR_ExplodeTime(prt[idx], PR_LocalTimeParameters, &et_tmp); + if (!ExplodedTimeIsEqual(&et_tmp, &localt[idx])) { + fprintf(stderr, "not equal\n"); + PrintExplodedTime(&et_tmp); + PrintExplodedTime(&localt[idx]); + exit(1); + } + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, prt[idx])) { + fprintf(stderr, "not equal\n"); + exit(1); + } + if (debug_mode) { + printf("Local time:"); + PrintExplodedTime(&et_tmp); + printf("\n\n"); + } + } + + now = PR_Now(); + PR_ExplodeTime(now, PR_GMTParameters, &et_tmp); + printf("Current GMT is "); + PrintExplodedTime(&et_tmp); + printf("\n"); + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, now)) { + fprintf(stderr, "not equal\n"); + exit(1); + } + PR_ExplodeTime(now, PR_USPacificTimeParameters, &et_tmp); + printf("Current US Pacific Time is "); + PrintExplodedTime(&et_tmp); + printf("\n"); + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, now)) { + fprintf(stderr, "not equal\n"); + exit(1); + } + PR_ExplodeTime(now, PR_LocalTimeParameters, &et_tmp); + printf("Current local time is "); + PrintExplodedTime(&et_tmp); + printf("\n"); + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, now)) { + fprintf(stderr, "not equal\n"); + exit(1); + } + printf("Please verify the results\n\n"); + + if (debug_mode) printf("Test 1 passed\n"); + return PR_SUCCESS; +} +/* End of Test 1: TestExplodeImplodeTime */ + +/* + * Test 2: Normalize Time + */ + +/* + * time increment for addition to PRExplodeTime + */ +typedef struct time_increment { + PRInt32 ti_usec; + PRInt32 ti_sec; + PRInt32 ti_min; + PRInt32 ti_hour; +} time_increment_t; + +/* + * Data for testing PR_Normalize + * Add the increment to base_time, normalize it to GMT and US Pacific + * Time zone. + */ +typedef struct normalize_test_data { + PRExplodedTime base_time; + time_increment_t increment; + PRExplodedTime expected_gmt_time; + PRExplodedTime expected_uspt_time; +} normalize_test_data_t; + + +/* + * Test data - the base time values cover dates of interest including y2k - 1, + * y2k + 1, y2k leap year, y2k leap date + 1year, + * y2k leap date + 4 years + */ +normalize_test_data_t normalize_test_array[] = { + /*usec sec min hour mday mo year wday yday {gmtoff, dstoff }*/ + + /* Fri 12/31/1999 19:32:48 PST */ + {{0, 48, 32, 19, 31, 11, 1999, 5, 364, { -28800, 0}}, + {0, 0, 30, 20}, + {0, 48, 2, 0, 2, 0, 2000, 0, 1, { 0, 0}}, /*Sun Jan 2 00:02:48 UTC 2000*/ + {0, 48, 2, 16, 1, 0, 2000, 6, 0, { -28800, 0}},/* Sat Jan 1 16:02:48 + PST 2000*/ + }, + /* Fri 99-12-31 23:59:02 GMT */ + {{0, 2, 59, 23, 31, 11, 1999, 5, 364, { 0, 0}}, + {0, 0, 45, 0}, + {0, 2, 44, 0, 1, 0, 2000, 6, 0, { 0, 0}},/* Sat Jan 1 00:44:02 UTC 2000*/ + {0, 2, 44, 16, 31, 11, 1999, 5, 364, { -28800, 0}}/*Fri Dec 31 16:44:02 + PST 1999*/ + }, + /* 99-12-25 12:00:00 GMT */ + {{0, 0, 0, 12, 25, 11, 1999, 6, 358, { 0, 0}}, + {0, 0, 0, 364 * 24}, + {0, 0, 0, 12, 23, 11, 2000, 6, 357, { 0, 0}},/*Sat Dec 23 12:00:00 + 2000 UTC*/ + {0, 0, 0, 4, 23, 11, 2000, 6, 357, { -28800, 0}}/*Sat Dec 23 04:00:00 + 2000 -0800*/ + }, + /* 00-01-1 00:00:00 PST */ + {{0, 0, 0, 0, 1, 0, 2000, 6, 0, { -28800, 0}}, + {0, 0, 0, 48}, + {0, 0, 0, 8, 3, 0, 2000, 1, 2, { 0, 0}},/*Mon Jan 3 08:00:00 2000 UTC*/ + {0, 0, 0, 0, 3, 0, 2000, 1, 2, { -28800, 0}}/*Mon Jan 3 00:00:00 2000 + -0800*/ + }, + /* 00-01-10 12:00:00 PST */ + {{0, 0, 0, 12, 10, 0, 2000, 1, 9, { -28800, 0}}, + {0, 0, 0, 364 * 5 * 24}, + {0, 0, 0, 20, 3, 0, 2005, 1, 2, { 0, 0}},/*Mon Jan 3 20:00:00 2005 UTC */ + {0, 0, 0, 12, 3, 0, 2005, 1, 2, { -28800, 0}}/*Mon Jan 3 12:00:00 + 2005 -0800*/ + }, + /* 00-02-28 15:39 GMT */ + {{0, 0, 39, 15, 28, 1, 2000, 1, 58, { 0, 0}}, + {0, 0, 0, 24}, + {0, 0, 39, 15, 29, 1, 2000, 2, 59, { 0, 0}}, /*Tue Feb 29 15:39:00 2000 + UTC*/ + {0, 0, 39, 7, 29, 1, 2000, 2, 59, { -28800, 0}}/*Tue Feb 29 07:39:00 + 2000 -0800*/ + }, + /* 01-03-01 12:00 PST */ + {{0, 0, 0, 12, 3, 0, 2001, 3, 2, { -28800, 0}},/*Wed Jan 3 12:00:00 + -0800 2001*/ + {0, 30, 30,45}, + {0, 30, 30, 17, 5, 0, 2001, 5, 4, { 0, 0}}, /*Fri Jan 5 17:30:30 2001 + UTC*/ + {0, 30, 30, 9, 5, 0, 2001, 5, 4, { -28800, 0}} /*Fri Jan 5 09:30:30 + 2001 -0800*/ + }, + /* 2004-04-26 12:00 GMT */ + {{0, 0, 0, 20, 3, 0, 2001, 3, 2, { 0, 0}}, + {0, 0, 30,0}, + {0, 0, 30, 20, 3, 0, 2001, 3, 2, { 0, 0}},/*Wed Jan 3 20:30:00 2001 UTC*/ + {0, 0, 30, 12, 3, 0, 2001, 3, 2, { -28800, 0}}/*Wed Jan 3 12:30:00 + 2001 -0800*/ + }, + /* 99-09-09 00:00 GMT */ + {{0, 0, 0, 0, 9, 8, 1999, 4, 251, { 0, 0}}, + {0, 0, 0, 12}, + {0, 0, 0, 12, 9, 8, 1999, 4, 251, { 0, 0}},/*Thu Sep 9 12:00:00 1999 UTC*/ + {0, 0, 0, 5, 9, 8, 1999, 4, 251, { -28800, 3600}}/*Thu Sep 9 05:00:00 + 1999 -0700*/ + } +}; + +void add_time_increment(PRExplodedTime *et1, time_increment_t *it) +{ + et1->tm_usec += it->ti_usec; + et1->tm_sec += it->ti_sec; + et1->tm_min += it->ti_min; + et1->tm_hour += it->ti_hour; +} + +/* +** TestNormalizeTime() -- Test PR_NormalizeTime() +** For each data item, add the time increment to the base_time and then +** normalize it for GMT and local time zones. This test assumes that +** the local time zone is the Pacific Time Zone. The normalized values +** should match the expected values in the data item. +** +*/ +PRStatus TestNormalizeTime(void) +{ +int idx, count; +normalize_test_data_t *itemp; +time_increment_t *itp; + + count = sizeof(normalize_test_array)/sizeof(normalize_test_array[0]); + for (idx = 0; idx < count; idx++) { + itemp = &normalize_test_array[idx]; + if (debug_mode) { + printf("%2d. %15s",idx +1,"Base time: "); + PrintExplodedTime(&itemp->base_time); + printf("\n"); + } + itp = &itemp->increment; + if (debug_mode) { + printf("%20s %2d hrs %2d min %3d sec\n","Add",itp->ti_hour, + itp->ti_min, itp->ti_sec); + } + add_time_increment(&itemp->base_time, &itemp->increment); + PR_NormalizeTime(&itemp->base_time, PR_LocalTimeParameters); + if (debug_mode) { + printf("%19s","PST time: "); + PrintExplodedTime(&itemp->base_time); + printf("\n"); + } + if (!ExplodedTimeIsEqual(&itemp->base_time, + &itemp->expected_uspt_time)) { + printf("PR_NormalizeTime failed\n"); + if (debug_mode) + PrintExplodedTime(&itemp->expected_uspt_time); + return PR_FAILURE; + } + PR_NormalizeTime(&itemp->base_time, PR_GMTParameters); + if (debug_mode) { + printf("%19s","GMT time: "); + PrintExplodedTime(&itemp->base_time); + printf("\n"); + } + + if (!ExplodedTimeIsEqual(&itemp->base_time, + &itemp->expected_gmt_time)) { + printf("PR_NormalizeTime failed\n"); + return PR_FAILURE; + } + } + return PR_SUCCESS; +} + + +/* +** ParseTest. Structure defining a string time and a matching exploded time +** +*/ +typedef struct ParseTest +{ + char *sDate; /* string to be converted using PR_ParseTimeString() */ + PRExplodedTime et; /* expected result of the conversion */ +} ParseTest; + +static ParseTest parseArray[] = +{ + /* |<----- expected result ------------------------------------------->| */ + /* "string to test" usec sec min hour day mo year wday julian {gmtoff, dstoff }*/ + { "Thursday 1 Jan 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "1 Jan 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "1-Jan-1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01-Jan-1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 1, 1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 1, 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 01, 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 01 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 01 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01-01-1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01/01/1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01/01/70", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01/01/70 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "70/01/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "70/1/1 00:00:", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "00:00 Thursday, January 1, 1970",{ 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "1-Jan-70 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "70-01-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "70/01/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + + /* 31-Dec-1969 */ + { "Wed 31 Dec 1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}}, + { "31 Dec 1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}}, + { "12/31/69 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}}, + { "12/31/1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}}, + { "12-31-69 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}}, + { "12-31-1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}}, + { "69-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}}, + { "69/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}}, + + /* "Sun". 31-Dec-1998 (?) */ + { "Thu 31 Dec 1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "12/31/98 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "12/31/1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "12-31-98 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "12-31-1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "98-12-31 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "98/12/31 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + + /* 09-Sep-1999. Interesting because of its use as an eof marker? */ + { "09 Sep 1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "9/9/99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "9/9/1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "9-9-99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "9-9-1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "09-09-99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "09-09-1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "99-09-09 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + + /* "Sun". 10-Sep-1999. Because Sun said so. */ + { "10 Sep 1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "9/10/99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "9/10/1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "9-10-99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "9-10-1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "09-10-99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "09-10-1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "99-09-10 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + + /* 31-Dec-1999 */ + { "31 Dec 1999 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "12/31/99 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "12/31/1999 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "12-31-99 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "12-31-1999 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "99-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "99/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + + /* 01-Jan-2000 */ + { "01 Jan 2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "1/1/00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "1/1/2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "1-1-00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "1-1-2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "01-01-00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "Saturday 01-01-2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + + /* "Sun". 28-Feb-2000 */ + { "28 Feb 2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "2/28/00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "2/28/2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "2-28-00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "2-28-2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "02-28-00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "02-28-2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + + /* 29-Feb-2000 */ + { "29 Feb 2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "2/29/00 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "2/29/2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "2-29-00 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "2-29-2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "02-29-00 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "02-29-2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + + /* 01-Mar-2000 */ + { "01 Mar 2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "3/1/00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "3/1/2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "3-1-00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "03-01-00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "03-01-2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + + /* "Sun". 31-Dec-2000 */ + { "31 Dec 2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "12/31/00 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "12/31/2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "12-31-00 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "12-31-2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "00-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "00/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + + /* "Sun". 01-Jan-2001 */ + { "01 Jan 2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "1/1/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "1/1/2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "1-1-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "1-1-2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "01-01-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "Saturday 01-01-2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + + /* 01-Mar-2001 */ + { "01 Mar 2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "3/1/01 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "3/1/2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "3-1-01 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "3-1-2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "03-01-01 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "03-01-2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + + /* 29-Feb-2004 */ + { "29 Feb 2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + { "2/29/04 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + { "2/29/2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + { "2-29-04 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + { "2-29-2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + + /* 01-Mar-2004 */ + { "01 Mar 2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "3/1/04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "3/1/2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "3-1-04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "3-1-2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "03-01-04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "03-01-2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + + /* 01-Mar-2005 */ + { "01 Mar 2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "3/1/05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "3/1/2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "3-1-05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "3-1-2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "03-01-05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "03-01-2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + + /* last element. string must be null */ + { NULL } +}; /* end array of ParseTest */ + +/* +** TestParseTime() -- Test PR_ParseTimeString() for y2k compliance +** +** TestParseTime() loops thru the array parseArray. For each element in +** the array, he calls PR_ParseTimeString() with sDate as the conversion +** argument. The result (ct) is then converted to a PRExplodedTime structure +** and compared with the exploded time value (parseArray[n].et) in the +** array element; if equal, the element passes the test. +** +** The array parseArray[] contains entries that are interesting to the +** y2k problem. +** +** +*/ +static PRStatus TestParseTime( void ) +{ + ParseTest *ptp = parseArray; + PRTime ct; + PRExplodedTime cet; + char *sp = ptp->sDate; + PRStatus rc; + PRStatus rv = PR_SUCCESS; + + while ( sp != NULL) + { + rc = PR_ParseTimeString( sp, PR_FALSE, &ct ); + if ( PR_FAILURE == rc ) + { + printf("TestParseTime(): PR_ParseTimeString() failed to convert: %s\n", sp ); + rv = PR_FAILURE; + failed_already = 1; + } + else + { + PR_ExplodeTime( ct, PR_LocalTimeParameters , &cet ); + + if ( !ExplodedTimeIsEqual( &cet, &ptp->et )) + { + printf("TestParseTime(): Exploded time compare failed: %s\n", sp ); + if ( debug_mode ) + { + PrintExplodedTime( &cet ); + printf("\n"); + PrintExplodedTime( &ptp->et ); + printf("\n"); + } + + rv = PR_FAILURE; + failed_already = 1; + } + } + + /* point to next element in array, keep going */ + ptp++; + sp = ptp->sDate; + } /* end while() */ + + return( rv ); +} /* end TestParseTime() */ + +int main(int argc, char** argv) +{ + /* 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. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt; + + PR_STDIO_INIT(); + opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + lm = PR_NewLogModule("test"); + +#ifdef XP_MAC + /* Set up the console */ + InitializeSIOUX(true); + debug_mode = PR_TRUE; +#endif + + if ( PR_FAILURE == TestExplodeImplodeTime()) + { + PR_LOG( lm, PR_LOG_ERROR, + ("TestExplodeImplodeTime() failed")); + } + else + printf("Test 1: Calendar Time Test passed\n"); + + if ( PR_FAILURE == TestNormalizeTime()) + { + PR_LOG( lm, PR_LOG_ERROR, + ("TestNormalizeTime() failed")); + } + else + printf("Test 2: Normalize Time Test passed\n"); + + if ( PR_FAILURE == TestParseTime()) + { + PR_LOG( lm, PR_LOG_ERROR, + ("TestParseTime() failed")); + } + else + printf("Test 3: Parse Time Test passed\n"); + +#ifdef XP_MAC + if (1) + { + char dummyChar; + + printf("Press return to exit\n\n"); + scanf("%c", &dummyChar); + } +#endif + + if (failed_already) + return 1; + else + return 0; +} /* end main() y2k.c */ + diff --git a/nsprpub/pr/tests/y2ktmo.c b/nsprpub/pr/tests/y2ktmo.c new file mode 100644 index 00000000000..a37ae07217b --- /dev/null +++ b/nsprpub/pr/tests/y2ktmo.c @@ -0,0 +1,546 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Test: y2ktmo + * + * Description: + * This test tests the interval time facilities in NSPR for Y2K + * compliance. All the functions that take a timeout argument + * are tested: PR_Sleep, socket I/O (PR_Accept is taken as a + * representative), PR_Poll, PR_WaitCondVar, PR_Wait, and + * PR_CWait. A thread of each thread scope (local, global, and + * global bound) is created to call each of these functions. + * The test should be started at the specified number of seconds + * (called the lead time) before a Y2K rollover test date. The + * timeout values for these threads will span over the rollover + * date by at least the specified number of seconds. For + * example, if the lead time is 5 seconds, the test should + * be started at time (D - 5), where D is a rollover date, and + * the threads will time out at or after time (D + 5). The + * timeout values for the threads are spaced one second apart. + * + * When a thread times out, it calls PR_IntervalNow() to verify + * that it did wait for the specified time. In addition, it + * calls a platform-native function to verify the actual elapsed + * time again, to rule out the possibility that PR_IntervalNow() + * is broken. We allow the actual elapsed time to deviate from + * the specified timeout by a certain tolerance (in milliseconds). + */ + +#include "nspr.h" +#include "plgetopt.h" + +#include +#include +#include +#if defined(XP_UNIX) +#include /* for gettimeofday */ +#endif +#if defined(WIN32) +#include +#include /* for _ftime */ +#endif + +#define DEFAULT_LEAD_TIME_SECS 5 +#define DEFAULT_TOLERANCE_MSECS 500 + +static PRBool debug_mode = PR_FALSE; +static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS; +static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS; +static PRIntervalTime start_time; +static PRIntervalTime tolerance; + +#if defined(XP_UNIX) +static struct timeval start_time_tv; +#endif +#if defined(WIN32) +static struct _timeb start_time_tb; +#endif + +static void SleepThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + + if (PR_Sleep(timeout) == PR_FAILURE) { + fprintf(stderr, "PR_Sleep failed\n"); + exit(1); + } + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + if (debug_mode) { + fprintf(stderr, "Sleep thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void AcceptThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + PRFileDesc *sock; + PRNetAddr addr; + PRFileDesc *accepted; + + sock = PR_NewTCPSocket(); + if (sock == NULL) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.port = 0; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + if (PR_Bind(sock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_Listen(sock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + accepted = PR_Accept(sock, NULL, timeout); + if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) { + fprintf(stderr, "PR_Accept did not time out\n"); + exit(1); + } + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (debug_mode) { + fprintf(stderr, "Accept thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void PollThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + PRFileDesc *sock; + PRNetAddr addr; + PRPollDesc pd; + PRIntn rv; + + sock = PR_NewTCPSocket(); + if (sock == NULL) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.port = 0; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + if (PR_Bind(sock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_Listen(sock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + pd.fd = sock; + pd.in_flags = PR_POLL_READ; + rv = PR_Poll(&pd, 1, timeout); + if (rv != 0) { + fprintf(stderr, "PR_Poll did not time out\n"); + exit(1); + } + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (debug_mode) { + fprintf(stderr, "Poll thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void WaitCondVarThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + PRLock *ml; + PRCondVar *cv; + + ml = PR_NewLock(); + if (ml == NULL) { + fprintf(stderr, "PR_NewLock failed\n"); + exit(1); + } + cv = PR_NewCondVar(ml); + if (cv == NULL) { + fprintf(stderr, "PR_NewCondVar failed\n"); + exit(1); + } + PR_Lock(ml); + PR_WaitCondVar(cv, timeout); + PR_Unlock(ml); + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + if (debug_mode) { + fprintf(stderr, "wait cond var thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void WaitMonitorThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + PRMonitor *mon; + + mon = PR_NewMonitor(); + if (mon == NULL) { + fprintf(stderr, "PR_NewMonitor failed\n"); + exit(1); + } + PR_EnterMonitor(mon); + PR_Wait(mon, timeout); + PR_ExitMonitor(mon); + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + PR_DestroyMonitor(mon); + if (debug_mode) { + fprintf(stderr, "wait monitor thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void WaitCMonitorThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + int dummy; + + PR_CEnterMonitor(&dummy); + PR_CWait(&dummy, timeout); + PR_CExitMonitor(&dummy); + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + if (debug_mode) { + fprintf(stderr, "wait cached monitor thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +typedef void (*NSPRThreadFunc)(void*); + +static NSPRThreadFunc threadFuncs[] = { + SleepThread, AcceptThread, PollThread, + WaitCondVarThread, WaitMonitorThread, WaitCMonitorThread}; + +static PRThreadScope threadScopes[] = { + PR_LOCAL_THREAD, PR_GLOBAL_THREAD, PR_GLOBAL_BOUND_THREAD}; + +static void Help(void) +{ + fprintf(stderr, "y2ktmo test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-l lead time (%d)\n", + DEFAULT_LEAD_TIME_SECS); + fprintf(stderr, "\t-t tolerance (%d)\n", + DEFAULT_TOLERANCE_MSECS); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PRThread **threads; + int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc); + int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope); + int i, j; + int idx; + PRInt32 secs; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dl:t:h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'l': /* lead time */ + lead_time_secs = atoi(opt->value); + break; + case 't': /* tolerance */ + tolerance_msecs = atoi(opt->value); + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (debug_mode) { + fprintf(stderr, "lead time: %d secs\n", lead_time_secs); + fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs); + } + + start_time = PR_IntervalNow(); +#if defined(XP_UNIX) + gettimeofday(&start_time_tv, NULL); +#endif +#if defined(WIN32) + _ftime(&start_time_tb); +#endif + tolerance = PR_MillisecondsToInterval(tolerance_msecs); + + threads = PR_Malloc( + num_thread_scopes * num_thread_funcs * sizeof(PRThread*)); + if (threads == NULL) { + fprintf(stderr, "PR_Malloc failed\n"); + exit(1); + } + + /* start to time out 5 seconds after a rollover date */ + secs = lead_time_secs + 5; + idx = 0; + for (i = 0; i < num_thread_scopes; i++) { + for (j = 0; j < num_thread_funcs; j++) { + threads[idx] = PR_CreateThread(PR_USER_THREAD, threadFuncs[j], + (void*)PR_SecondsToInterval(secs), PR_PRIORITY_NORMAL, + threadScopes[i], PR_JOINABLE_THREAD, 0); + if (threads[idx] == NULL) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + secs++; + idx++; + } + } + for (idx = 0; idx < num_thread_scopes*num_thread_funcs; idx++) { + if (PR_JoinThread(threads[idx]) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + } + PR_Free(threads); + printf("PASS\n"); + return 0; +} diff --git a/nsprpub/pr/tests/yield.c b/nsprpub/pr/tests/yield.c new file mode 100644 index 00000000000..5f441a19a7d --- /dev/null +++ b/nsprpub/pr/tests/yield.c @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include "prthread.h" +#include "prinit.h" +#ifndef XP_OS2 +#include "private/pprmisc.h" +#include +#else +#include "primpl.h" +#include +#endif + +#define THREADS 10 + + +void +threadmain(void *_id) +{ + int id = (int)_id; + int index; + + printf("thread %d alive\n", id); + for (index=0; index<10; index++) { + printf("thread %d yielding\n", id); + PR_Sleep(0); + printf("thread %d awake\n", id); + } + printf("thread %d dead\n", id); + +} + +main() +{ + int index; + PRThread *a[THREADS]; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 5); + PR_STDIO_INIT(); + + for (index=0; index + +int main() +{ + printf("PASS\n"); + return 0; +} + +#else /* XP_UNIX */ + +#include "nspr.h" +#include "private/pprio.h" + +#include +#include +#include +#include +#include + +static void ClientThread(void *arg) +{ + PRFileDesc *sock; + PRNetAddr addr; + PRUint16 port = (PRUint16) arg; + char buf[1024]; + PRInt32 nbytes; + + sock = PR_NewTCPSocket(); + if (NULL == sock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrLoopback, port, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + fprintf(stderr, "PR_Connect failed\n"); + exit(1); + } + /* + * Sleep 5 seconds to force the server thread to get EAGAIN. + */ + if (PR_Sleep(PR_SecondsToInterval(5)) == PR_FAILURE) { + fprintf(stderr, "PR_Sleep failed\n"); + exit(1); + } + /* + * Then start reading. + */ + while ((nbytes = PR_Read(sock, buf, sizeof(buf))) > 0) { + /* empty loop body */ + } + if (-1 == nbytes) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +int main() +{ + PRFileDesc *listenSock; + PRFileDesc *acceptSock; + int osfd; + PRThread *clientThread; + PRNetAddr addr; + char buf[1024]; + PRInt32 nbytes; + PRIOVec iov; + + memset(buf, 0, sizeof(buf)); /* Initialize the buffer. */ + listenSock = PR_NewTCPSocket(); + if (NULL == listenSock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + /* Find out what port number we are bound to. */ + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + /* + * First test PR_Writev. + */ + clientThread = PR_CreateThread(PR_USER_THREAD, + ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == clientThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + osfd = PR_FileDesc2NativeHandle(acceptSock); + while ((nbytes = write(osfd, buf, sizeof(buf))) != -1) { + /* empty loop body */ + } + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { + fprintf(stderr, "write failed\n"); + exit(1); + } + iov.iov_base = buf; + iov.iov_len = 0; + printf("calling PR_Writev with a zero-length buffer\n"); + fflush(stdout); + nbytes = PR_Writev(acceptSock, &iov, 1, PR_INTERVAL_NO_TIMEOUT); + if (nbytes != 0) { + fprintf(stderr, "PR_Writev should return 0 but returns %d\n", nbytes); + exit(1); + } + if (PR_Close(acceptSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_JoinThread(clientThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + + /* + * Then test PR_Write. + */ + clientThread = PR_CreateThread(PR_USER_THREAD, + ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == clientThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + osfd = PR_FileDesc2NativeHandle(acceptSock); + while ((nbytes = write(osfd, buf, sizeof(buf))) != -1) { + /* empty loop body */ + } + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { + fprintf(stderr, "write failed\n"); + exit(1); + } + printf("calling PR_Write with a zero-length buffer\n"); + fflush(stdout); + nbytes = PR_Write(acceptSock, buf, 0); + if (nbytes != 0) { + fprintf(stderr, "PR_Write should return 0 but returns %d\n", nbytes); + exit(1); + } + if (PR_Close(acceptSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_JoinThread(clientThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + + /* + * Finally test PR_Send. + */ + clientThread = PR_CreateThread(PR_USER_THREAD, + ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == clientThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + osfd = PR_FileDesc2NativeHandle(acceptSock); + while ((nbytes = write(osfd, buf, sizeof(buf))) != -1) { + /* empty loop body */ + } + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { + fprintf(stderr, "write failed\n"); + exit(1); + } + printf("calling PR_Send with a zero-length buffer\n"); + fflush(stdout); + nbytes = PR_Send(acceptSock, buf, 0, 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes != 0) { + fprintf(stderr, "PR_Send should return 0 but returns %d\n", nbytes); + exit(1); + } + if (PR_Close(acceptSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_JoinThread(clientThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + + if (PR_Close(listenSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + printf("PASS\n"); + return 0; +} + +#endif /* XP_UNIX */ diff --git a/nsprpub/tools/.cvsignore b/nsprpub/tools/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/nsprpub/tools/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/nsprpub/tools/Makefile.in b/nsprpub/tools/Makefile.in new file mode 100644 index 00000000000..c01b0a648ff --- /dev/null +++ b/nsprpub/tools/Makefile.in @@ -0,0 +1,249 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape Portable Runtime (NSPR). +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#! gmake + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + + +DIRS = + +CSRCS = \ + httpget.c \ + tail.c \ + $(NULL) + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) + +INCLUDES = -I$(dist_includedir) + +NSPR_VERSION = 3 + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(NSPR_VERSION) +LIBPLC = -lplc$(NSPR_VERSION) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(NSPR_VERSION).lib + LIBPLC= $(dist_libdir)/plc$(NSPR_VERSION).lib +else +LDOPTS = -NOLOGO -DEBUG -INCREMENTAL:NO +LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).$(LIB_SUFFIX) +LIBPLC= $(dist_libdir)/libplc$(NSPR_VERSION).$(LIB_SUFFIX) +endif +endif + +ifeq ($(OS_ARCH),OS2) + ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO + LIBPR = $(dist_libdir)/nspr$(NSPR_VERSION).lib + LIBPLC= $(dist_libdir)/plc$(NSPR_VERSION).lib + else + LDOPTS += -Zomf -Zlinker /PM:VIO + endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), IRIX) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) -lpthread +endif + +ifeq ($(OS_ARCH), HP-UX) +LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) +LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib +LIBPR = -lnspr$(NSPR_VERSION)_shr +LIBPLC = -lplc$(NSPR_VERSION)_shr +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) +ifneq ($(OS_RELEASE), 4.1.3_U1) +ifdef NS_USE_GCC +LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) +else +LDOPTS += -R $(PWD)/$(dist_libdir) +endif +endif + +# 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 # SunOS + +ifeq ($(OS_ARCH), NCR) +# XXX: We see some strange problems when we link with libnspr.so. +# So for now we use static libraries on NCR. The shared library +# stuff below is commented out. +LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).a +LIBPLC = $(dist_libdir)/libplc$(NSPR_VERSION).a +EXTRA_LIBS = -lsocket -lnsl -ldl + +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +#EXTRA_LIBS = -lsocket -lnsl +# 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_libdir) +endif + +ifeq ($(OS_ARCH), SCOOS) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# 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_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(NSPR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPLC), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPR) $(LIBPLC) wsock32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(LDOPTS) $< $(LIBPR) $(LIBPLC) $(OS_LIBS) $(EXTRA_LIBS) -o $@ +else + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPLC) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + diff --git a/nsprpub/tools/httpget.c b/nsprpub/tools/httpget.c new file mode 100644 index 00000000000..774a4c7a7b3 --- /dev/null +++ b/nsprpub/tools/httpget.c @@ -0,0 +1,466 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* + * Author: Wan-Teh Chang + * + * Given an HTTP URL, httpget uses the GET method to fetch the file. + * The fetched file is written to stdout by default, or can be + * saved in an output file. + * + * This is a single-threaded program. + */ + +#include "prio.h" +#include "prnetdb.h" +#include "prlog.h" +#include "prerror.h" +#include "prprf.h" +#include "prinit.h" + +#include +#include +#include /* for atoi */ + +#define FCOPY_BUFFER_SIZE (16 * 1024) +#define INPUT_BUFFER_SIZE 1024 +#define LINE_SIZE 512 +#define HOST_SIZE 256 +#define PORT_SIZE 32 +#define PATH_SIZE 512 + +/* + * A buffer for storing the excess input data for ReadLine. + * The data in the buffer starts from (including) the element pointed to + * by inputHead, and ends just before (not including) the element pointed + * to by inputTail. The buffer is empty if inputHead == inputTail. + */ + +static char inputBuf[INPUT_BUFFER_SIZE]; +/* + * inputBufEnd points just past the end of inputBuf + */ +static char *inputBufEnd = inputBuf + sizeof(inputBuf); +static char *inputHead = inputBuf; +static char *inputTail = inputBuf; + +static PRBool endOfStream = PR_FALSE; + +/* + * ReadLine -- + * + * Read in a line of text, terminated by CRLF or LF, from fd into buf. + * The terminating CRLF or LF is included (always as '\n'). The text + * in buf is terminated by a null byte. The excess bytes are stored in + * inputBuf for use in the next ReadLine call or FetchFile call. + * Returns the number of bytes in buf. 0 means end of stream. Returns + * -1 if read fails. + */ + +PRInt32 ReadLine(PRFileDesc *fd, char *buf, PRUint32 bufSize) +{ + char *dst = buf; + char *bufEnd = buf + bufSize; /* just past the end of buf */ + PRBool lineFound = PR_FALSE; + char *crPtr = NULL; /* points to the CR ('\r') character */ + PRInt32 nRead; + +loop: + PR_ASSERT(inputBuf <= inputHead && inputHead <= inputTail + && inputTail <= inputBufEnd); + while (lineFound == PR_FALSE && inputHead != inputTail + && dst < bufEnd - 1) { + if (*inputHead == '\r') { + crPtr = dst; + } else if (*inputHead == '\n') { + lineFound = PR_TRUE; + if (crPtr == dst - 1) { + dst--; + } + } + *(dst++) = *(inputHead++); + } + if (lineFound == PR_TRUE || dst == bufEnd - 1 || endOfStream == PR_TRUE) { + *dst = '\0'; + return dst - buf; + } + + /* + * The input buffer should be empty now + */ + PR_ASSERT(inputHead == inputTail); + + nRead = PR_Read(fd, inputBuf, sizeof(inputBuf)); + if (nRead == -1) { + *dst = '\0'; + return -1; + } else if (nRead == 0) { + endOfStream = PR_TRUE; + *dst = '\0'; + return dst - buf; + } + inputHead = inputBuf; + inputTail = inputBuf + nRead; + goto loop; +} + +PRInt32 DrainInputBuffer(char *buf, PRUint32 bufSize) +{ + PRInt32 nBytes = inputTail - inputHead; + + if (nBytes == 0) { + if (endOfStream) { + return -1; + } else { + return 0; + } + } + if ((PRInt32) bufSize < nBytes) { + nBytes = bufSize; + } + memcpy(buf, inputHead, nBytes); + inputHead += nBytes; + return nBytes; +} + +PRStatus FetchFile(PRFileDesc *in, PRFileDesc *out) +{ + char buf[FCOPY_BUFFER_SIZE]; + PRInt32 nBytes; + + while ((nBytes = DrainInputBuffer(buf, sizeof(buf))) > 0) { + if (PR_Write(out, buf, nBytes) != nBytes) { + fprintf(stderr, "httpget: cannot write to file\n"); + return PR_FAILURE; + } + } + if (nBytes < 0) { + /* Input buffer is empty and end of stream */ + return PR_SUCCESS; + } + while ((nBytes = PR_Read(in, buf, sizeof(buf))) > 0) { + if (PR_Write(out, buf, nBytes) != nBytes) { + fprintf(stderr, "httpget: cannot write to file\n"); + return PR_FAILURE; + } + } + if (nBytes < 0) { + fprintf(stderr, "httpget: cannot read from socket\n"); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRStatus FastFetchFile(PRFileDesc *in, PRFileDesc *out, PRUint32 size) +{ + PRInt32 nBytes; + PRFileMap *outfMap; + void *addr; + char *start; + PRUint32 rem; + PRUint32 bytesToRead; + PRStatus rv; + PRInt64 sz64; + + LL_UI2L(sz64, size); + outfMap = PR_CreateFileMap(out, sz64, PR_PROT_READWRITE); + PR_ASSERT(outfMap); + addr = PR_MemMap(outfMap, LL_ZERO, size); + if (addr == (void *) -1) { + fprintf(stderr, "cannot memory-map file: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + + PR_CloseFileMap(outfMap); + return PR_FAILURE; + } + PR_ASSERT(addr != (void *) -1); + start = (char *) addr; + rem = size; + while ((nBytes = DrainInputBuffer(start, rem)) > 0) { + start += nBytes; + rem -= nBytes; + } + if (nBytes < 0) { + /* Input buffer is empty and end of stream */ + return PR_SUCCESS; + } + bytesToRead = (rem < FCOPY_BUFFER_SIZE) ? rem : FCOPY_BUFFER_SIZE; + while (rem > 0 && (nBytes = PR_Read(in, start, bytesToRead)) > 0) { + start += nBytes; + rem -= nBytes; + bytesToRead = (rem < FCOPY_BUFFER_SIZE) ? rem : FCOPY_BUFFER_SIZE; + } + if (nBytes < 0) { + fprintf(stderr, "httpget: cannot read from socket\n"); + return PR_FAILURE; + } + rv = PR_MemUnmap(addr, size); + PR_ASSERT(rv == PR_SUCCESS); + rv = PR_CloseFileMap(outfMap); + PR_ASSERT(rv == PR_SUCCESS); + return PR_SUCCESS; +} + +PRStatus ParseURL(char *url, char *host, PRUint32 hostSize, + char *port, PRUint32 portSize, char *path, PRUint32 pathSize) +{ + char *start, *end; + char *dst; + char *hostEnd; + char *portEnd; + char *pathEnd; + + if (strncmp(url, "http", 4)) { + fprintf(stderr, "httpget: the protocol must be http\n"); + return PR_FAILURE; + } + if (strncmp(url + 4, "://", 3) || url[7] == '\0') { + fprintf(stderr, "httpget: malformed URL: %s\n", url); + return PR_FAILURE; + } + + start = end = url + 7; + dst = host; + hostEnd = host + hostSize; + while (*end && *end != ':' && *end != '/') { + if (dst == hostEnd - 1) { + fprintf(stderr, "httpget: host name too long\n"); + return PR_FAILURE; + } + *(dst++) = *(end++); + } + *dst = '\0'; + + if (*end == '\0') { + PR_snprintf(port, portSize, "%d", 80); + PR_snprintf(path, pathSize, "%s", "/"); + return PR_SUCCESS; + } + + if (*end == ':') { + end++; + dst = port; + portEnd = port + portSize; + while (*end && *end != '/') { + if (dst == portEnd - 1) { + fprintf(stderr, "httpget: port number too long\n"); + return PR_FAILURE; + } + *(dst++) = *(end++); + } + *dst = '\0'; + if (*end == '\0') { + PR_snprintf(path, pathSize, "%s", "/"); + return PR_SUCCESS; + } + } else { + PR_snprintf(port, portSize, "%d", 80); + } + + dst = path; + pathEnd = path + pathSize; + while (*end) { + if (dst == pathEnd - 1) { + fprintf(stderr, "httpget: file pathname too long\n"); + return PR_FAILURE; + } + *(dst++) = *(end++); + } + *dst = '\0'; + return PR_SUCCESS; +} + +void PrintUsage(void) { + fprintf(stderr, "usage: httpget url\n" + " httpget -o outputfile url\n" + " httpget url -o outputfile\n"); +} + +int main(int argc, char **argv) +{ + PRHostEnt hostentry; + char buf[PR_NETDB_BUF_SIZE]; + PRNetAddr addr; + PRFileDesc *socket = NULL, *file = NULL; + PRIntn cmdSize; + char host[HOST_SIZE]; + char port[PORT_SIZE]; + char path[PATH_SIZE]; + char line[LINE_SIZE]; + int exitStatus = 0; + PRBool endOfHeader = PR_FALSE; + char *url; + char *fileName = NULL; + PRUint32 fileSize; + + if (argc != 2 && argc != 4) { + PrintUsage(); + exit(1); + } + + if (argc == 2) { + /* + * case 1: httpget url + */ + url = argv[1]; + } else { + if (strcmp(argv[1], "-o") == 0) { + /* + * case 2: httpget -o outputfile url + */ + fileName = argv[2]; + url = argv[3]; + } else { + /* + * case 3: httpget url -o outputfile + */ + url = argv[1]; + if (strcmp(argv[2], "-o") != 0) { + PrintUsage(); + exit(1); + } + fileName = argv[3]; + } + } + + if (ParseURL(url, host, sizeof(host), port, sizeof(port), + path, sizeof(path)) == PR_FAILURE) { + exit(1); + } + + if (PR_GetHostByName(host, buf, sizeof(buf), &hostentry) + == PR_FAILURE) { + fprintf(stderr, "httpget: unknown host name: %s\n", host); + exit(1); + } + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons((short) atoi(port)); + addr.inet.ip = *((PRUint32 *) hostentry.h_addr_list[0]); + + socket = PR_NewTCPSocket(); + if (socket == NULL) { + fprintf(stderr, "httpget: cannot create new tcp socket\n"); + exit(1); + } + + if (PR_Connect(socket, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + fprintf(stderr, "httpget: cannot connect to http server\n"); + exitStatus = 1; + goto done; + } + + if (fileName == NULL) { + file = PR_STDOUT; + } else { + file = PR_Open(fileName, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, + 00777); + if (file == NULL) { + fprintf(stderr, "httpget: cannot open file %s: (%d, %d)\n", + fileName, PR_GetError(), PR_GetOSError()); + exitStatus = 1; + goto done; + } + } + + cmdSize = PR_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n", path); + PR_ASSERT(cmdSize == (PRIntn) strlen("GET HTTP/1.0\r\n\r\n") + + (PRIntn) strlen(path)); + if (PR_Write(socket, buf, cmdSize) != cmdSize) { + fprintf(stderr, "httpget: cannot write to http server\n"); + exitStatus = 1; + goto done; + } + + if (ReadLine(socket, line, sizeof(line)) <= 0) { + fprintf(stderr, "httpget: cannot read line from http server\n"); + exitStatus = 1; + goto done; + } + + /* HTTP response: 200 == OK */ + if (strstr(line, "200") == NULL) { + fprintf(stderr, "httpget: %s\n", line); + exitStatus = 1; + goto done; + } + + while (ReadLine(socket, line, sizeof(line)) > 0) { + if (line[0] == '\n') { + endOfHeader = PR_TRUE; + break; + } + if (strncmp(line, "Content-Length", 14) == 0 + || strncmp(line, "Content-length", 14) == 0) { + char *p = line + 14; + + while (*p == ' ' || *p == '\t') { + p++; + } + if (*p != ':') { + continue; + } + p++; + while (*p == ' ' || *p == '\t') { + p++; + } + fileSize = 0; + while ('0' <= *p && *p <= '9') { + fileSize = 10 * fileSize + (*p - '0'); + p++; + } + } + } + if (endOfHeader == PR_FALSE) { + fprintf(stderr, "httpget: cannot read line from http server\n"); + exitStatus = 1; + goto done; + } + + if (fileName == NULL || fileSize == 0) { + FetchFile(socket, file); + } else { + FastFetchFile(socket, file, fileSize); + } + +done: + if (socket) PR_Close(socket); + if (file) PR_Close(file); + PR_Cleanup(); + return exitStatus; +} diff --git a/nsprpub/tools/tail.c b/nsprpub/tools/tail.c new file mode 100644 index 00000000000..dc729c15988 --- /dev/null +++ b/nsprpub/tools/tail.c @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prio.h" +#include "prprf.h" +#include "prinit.h" +#include "prthread.h" +#include "prinrval.h" + +#include "plerror.h" +#include "plgetopt.h" + +#include + +#define BUFFER_SIZE 500 + +static PRFileDesc *out = NULL, *err = NULL; + +static void Help(void) +{ + PR_fprintf(err, "Usage: tail [-n ] [-f] [-h] \n"); + PR_fprintf(err, "\t-t Dally time in milliseconds\n"); + PR_fprintf(err, "\t-n Number of bytes before \n"); + PR_fprintf(err, "\t-f Follow the \n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv = 0; + PLOptStatus os; + PRStatus status; + PRFileDesc *file; + PRFileInfo fileInfo; + PRIntervalTime dally; + char buffer[BUFFER_SIZE]; + PRBool follow = PR_FALSE; + const char *filename = NULL; + PRUint32 position = 0, seek = 0, time = 0; + PLOptState *opt = PL_CreateOptState(argc, argv, "hfn:"); + + out = PR_GetSpecialFD(PR_StandardOutput); + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* it's the filename */ + filename = opt->value; + break; + case 'n': /* bytes before end of file */ + seek = atoi(opt->value); + break; + case 't': /* dally time */ + time = atoi(opt->value); + break; + case 'f': /* follow the end of file */ + follow = PR_TRUE; + break; + case 'h': /* user wants some guidance */ + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == time) time = 1000; + dally = PR_MillisecondsToInterval(time); + + if (NULL == filename) + { + (void)PR_fprintf(out, "Input file not specified\n"); + rv = 1; goto done; + } + file = PR_Open(filename, PR_RDONLY, 0); + if (NULL == file) + { + PL_FPrintError(err, "File cannot be opened for reading"); + return 1; + } + + status = PR_GetOpenFileInfo(file, &fileInfo); + if (PR_FAILURE == status) + { + PL_FPrintError(err, "Cannot acquire status of file"); + rv = 1; goto done; + } + if (seek > 0) + { + if (seek > fileInfo.size) seek = 0; + position = PR_Seek(file, (fileInfo.size - seek), PR_SEEK_SET); + if (-1 == (PRInt32)position) + PL_FPrintError(err, "Cannot seek to starting position"); + } + + do + { + while (position < fileInfo.size) + { + PRInt32 read, bytes = fileInfo.size - position; + if (bytes > sizeof(buffer)) bytes = sizeof(buffer); + read = PR_Read(file, buffer, bytes); + if (read != bytes) + PL_FPrintError(err, "Cannot read to eof"); + position += read; + PR_Write(out, buffer, read); + } + + if (follow) + { + PR_Sleep(dally); + status = PR_GetOpenFileInfo(file, &fileInfo); + if (PR_FAILURE == status) + { + PL_FPrintError(err, "Cannot acquire status of file"); + rv = 1; goto done; + } + } + } while (follow); + +done: + PR_Close(file); + + return rv; +} /* main */ + +/* tail.c */