summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/src/cplus
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /nsprpub/pr/src/cplus
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'nsprpub/pr/src/cplus')
-rw-r--r--nsprpub/pr/src/cplus/Makefile.in43
-rw-r--r--nsprpub/pr/src/cplus/rcascii.h143
-rw-r--r--nsprpub/pr/src/cplus/rcbase.cpp31
-rw-r--r--nsprpub/pr/src/cplus/rcbase.h55
-rw-r--r--nsprpub/pr/src/cplus/rccv.cpp70
-rw-r--r--nsprpub/pr/src/cplus/rccv.h64
-rw-r--r--nsprpub/pr/src/cplus/rcfileio.cpp247
-rw-r--r--nsprpub/pr/src/cplus/rcfileio.h131
-rw-r--r--nsprpub/pr/src/cplus/rcinrval.cpp37
-rw-r--r--nsprpub/pr/src/cplus/rcinrval.h191
-rw-r--r--nsprpub/pr/src/cplus/rcio.cpp14
-rw-r--r--nsprpub/pr/src/cplus/rcio.h117
-rw-r--r--nsprpub/pr/src/cplus/rclock.cpp42
-rw-r--r--nsprpub/pr/src/cplus/rclock.h74
-rw-r--r--nsprpub/pr/src/cplus/rcmon.h47
-rw-r--r--nsprpub/pr/src/cplus/rcnetdb.cpp233
-rw-r--r--nsprpub/pr/src/cplus/rcnetdb.h99
-rw-r--r--nsprpub/pr/src/cplus/rcnetio.cpp225
-rw-r--r--nsprpub/pr/src/cplus/rcnetio.h94
-rw-r--r--nsprpub/pr/src/cplus/rcthread.cpp221
-rw-r--r--nsprpub/pr/src/cplus/rcthread.h195
-rw-r--r--nsprpub/pr/src/cplus/rctime.cpp56
-rw-r--r--nsprpub/pr/src/cplus/rctime.h136
-rw-r--r--nsprpub/pr/src/cplus/tests/Makefile.in199
-rw-r--r--nsprpub/pr/src/cplus/tests/fileio.cpp33
-rw-r--r--nsprpub/pr/src/cplus/tests/interval.cpp101
-rw-r--r--nsprpub/pr/src/cplus/tests/ranfile.cpp449
-rw-r--r--nsprpub/pr/src/cplus/tests/switch.cpp248
-rw-r--r--nsprpub/pr/src/cplus/tests/thread.cpp110
-rw-r--r--nsprpub/pr/src/cplus/tests/time.cpp29
-rw-r--r--nsprpub/pr/src/cplus/tests/tpd.cpp353
31 files changed, 4087 insertions, 0 deletions
diff --git a/nsprpub/pr/src/cplus/Makefile.in b/nsprpub/pr/src/cplus/Makefile.in
new file mode 100644
index 0000000000..ec08eab1fb
--- /dev/null
+++ b/nsprpub/pr/src/cplus/Makefile.in
@@ -0,0 +1,43 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#! 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 0000000000..f8b59ce0f9
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcascii.h
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..7c12e6d3d4
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcbase.cpp
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..3cc91f8041
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcbase.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** RCBase.h - Mixin class for NSPR C++ wrappers
+*/
+
+#if defined(_RCRUNTIME_H)
+#else
+#define _RCRUNTIME_H
+
+#include <prerror.h>
+
+/*
+** 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 0000000000..f124385350
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rccv.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** RCCondition - C++ wrapper around NSPR's PRCondVar
+*/
+
+#include "rccv.h"
+
+#include <prlog.h>
+#include <prerror.h>
+#include <prcvar.h>
+
+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 0000000000..afeec61614
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rccv.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..91c5fde6ff
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcfileio.cpp
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** Class implementation for normal and special file I/O (ref: prio.h)
+*/
+
+#include "rcfileio.h"
+
+#include <string.h>
+
+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 0000000000..9e28b36ace
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcfileio.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..3805a57663
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcinrval.cpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..333209e618
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcinrval.h
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 <prinrval.h>
+
+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 0000000000..081a9f694a
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcio.cpp
@@ -0,0 +1,14 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..1bd3ac4140
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcio.h
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..8c106de088
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rclock.cpp
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+** C++ access to NSPR locks (PRLock)
+*/
+
+#include "rclock.h"
+#include <prlog.h>
+
+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 0000000000..c86c2f17b6
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rclock.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** C++ access to NSPR locks (PRLock)
+*/
+
+#if defined(_RCLOCK_H)
+#else
+#define _RCLOCK_H
+
+#include "rcbase.h"
+
+#include <prlock.h>
+
+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 0000000000..5d084efdea
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcmon.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..19eb66540f
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcnetdb.cpp
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** Base class implementation for network access functions (ref: prnetdb.h)
+*/
+
+#include "rclock.h"
+#include "rcnetdb.h"
+
+#include <prmem.h>
+#include <prlog.h>
+#include <string.h>
+
+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_NOT_REACHED("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 0000000000..14e96ecd85
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcnetdb.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 <prnetdb.h>
+
+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 0000000000..e351345e43
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcnetio.cpp
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** Subclass implementation for streamed network I/O (ref: prio.h)
+*/
+
+#include "rcnetio.h"
+
+#include <private/pprio.h>
+
+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 0000000000..7f6b669d55
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcnetio.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 100644
index 0000000000..471e580a2c
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcthread.cpp
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* RCThread.cpp - C++ wrapper on NSPR */
+
+#include "rcthread.h"
+#include "rcinrval.h"
+
+#include <prmem.h>
+#include <prlog.h>
+#include <stdio.h>
+#include <prinit.h>
+
+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 0000000000..b7716d4b99
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rcthread.h
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* RCThread.h */
+
+#if defined(_RCTHREAD_H)
+#else
+#define _RCTHREAD_H
+
+#include "rcbase.h"
+
+#include <prthread.h>
+
+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 <empty> - 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 0000000000..2c9823e15b
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rctime.cpp
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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 0000000000..3752a3d53d
--- /dev/null
+++ b/nsprpub/pr/src/cplus/rctime.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** Class definitions for calendar time routines (ref: prtime.h)
+*/
+
+#if defined(_RCTIME_H)
+#else
+#define _RCTIME_H
+
+#include "rcbase.h"
+
+#include <prtime.h>
+
+/*
+** 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/Makefile.in b/nsprpub/pr/src/cplus/tests/Makefile.in
new file mode 100644
index 0000000000..df48276569
--- /dev/null
+++ b/nsprpub/pr/src/cplus/tests/Makefile.in
@@ -0,0 +1,199 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+#! 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)
+
+# Solaris
+ifeq ($(OS_ARCH), SunOS)
+ ifdef NS_USE_GCC
+ LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir)
+ else
+ LDOPTS += -R $(PWD)/$(dist_libdir)
+ endif
+
+# SunOS 5.5 needs to link with -lpthread, even though we already
+# linked with this system library when we built libnspr.so.
+ ifeq ($(OS_RELEASE), 5.5)
+ ifdef USE_PTHREADS
+ EXTRA_LIBS = -lpthread
+ endif
+ endif
+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)
+LDOPTS += -Zomf -Zlinker /PM:VIO -lstdcpp
+endif
+
+ifneq ($(OS_ARCH), WINNT)
+PWD = $(shell pwd)
+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), 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) ws2_32.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 0000000000..fdffe99972
--- /dev/null
+++ b/nsprpub/pr/src/cplus/tests/fileio.cpp
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* fileio.cpp - a test program */
+
+#include "rcfileio.h"
+
+#include <prlog.h>
+#include <prprf.h>
+
+#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 0000000000..8acf506256
--- /dev/null
+++ b/nsprpub/pr/src/cplus/tests/interval.cpp
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* interval.cpp - a test program */
+
+#include "rclock.h"
+#include "rcthread.h"
+#include "rcinrval.h"
+#include "rccv.h"
+
+#include <prio.h>
+#include <prlog.h>
+#include <prprf.h>
+
+#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 0000000000..0fb4c5d23a
--- /dev/null
+++ b/nsprpub/pr/src/cplus/tests/ranfile.cpp
@@ -0,0 +1,449 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Contact: AOF<mailto:freier@netscape.com>
+**
+** 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 <prprf.h>
+#include <prio.h>
+
+#include "rccv.h"
+#include "rcthread.h"
+#include "rcfileio.h"
+#include "rclock.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+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 0000000000..00de8e3064
--- /dev/null
+++ b/nsprpub/pr/src/cplus/tests/switch.cpp
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: switch.cpp
+** Description: trying to time context switches
+*/
+
+#include "rccv.h"
+#include "rcinrval.h"
+#include "rclock.h"
+#include "rcthread.h"
+
+#include <prio.h>
+#include <prlog.h>
+#include <prprf.h>
+#include <plerror.h>
+#include <plgetopt.h>
+
+#include <stdlib.h>
+
+#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 0000000000..ff01402d8d
--- /dev/null
+++ b/nsprpub/pr/src/cplus/tests/thread.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* thread.cpp - a test program */
+
+#include "rcthread.h"
+
+#include <prlog.h>
+
+#include <stdio.h>
+
+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 0000000000..ad27caaacc
--- /dev/null
+++ b/nsprpub/pr/src/cplus/tests/time.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* time.cpp - a test program */
+
+#include "rctime.h"
+
+#include <prlog.h>
+#include <prprf.h>
+
+#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 0000000000..2a18c9cb11
--- /dev/null
+++ b/nsprpub/pr/src/cplus/tests/tpd.cpp
@@ -0,0 +1,353 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: tpd.cpp
+** Description: Exercising the thread private data bailywick.
+*/
+
+#include "prlog.h"
+#include "prprf.h"
+#include "rcthread.h"
+
+#include <string.h>
+
+#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 <empty> */
+ 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 <empty> */
+ 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 <empty> 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 */