Merging NSPR v3.0 release from internal source repository to
cvs.mozilla.org NSPRPUB_RELEASE_3_0_LANDING_BRANCH.
--- a/config/Linux.mk
+++ b/config/Linux.mk
@@ -74,18 +74,17 @@ OS_CFLAGS = $(DSO_CFLAGS) $(PLATFORM_FL
# Version-specific stuff
######################################################################
ifeq ($(CPU_ARCH),alpha)
PLATFORM_FLAGS += -D_ALPHA_ -D__alpha -mieee
PORT_FLAGS += -D_XOPEN_SOURCE
endif
ifeq ($(CPU_ARCH),ppc)
-PLATFORM_FLAGS += -DMKLINUX
-OS_INCLUDES += -I/usr/local/include
+PORT_FLAGS += -D_XOPEN_SOURCE
endif
ifeq ($(CPU_ARCH),x86)
PLATFORM_FLAGS += -mno-486 -Di386
PORT_FLAGS += -D_XOPEN_SOURCE
endif
ifeq ($(CPU_ARCH),m68k)
#
# gcc on Linux/m68k either has a bug or triggers a code-sequence
@@ -94,17 +93,17 @@ ifeq ($(CPU_ARCH),m68k)
#
ifndef BUILD_OPT
OPTIMIZER += -O
endif
PLATFORM_FLAGS += -m68020-40
endif
#
-# Linux ppc and 2.0 have shared libraries.
+# Linux 2.x has shared libraries.
#
MKSHLIB = $(LD) $(DSO_LDOPTS) -soname $(@:$(OBJDIR)/%.so=%.so)
ifdef BUILD_OPT
OPTIMIZER = -O2
endif
######################################################################
--- a/config/nsinstall.c
+++ b/config/nsinstall.c
@@ -79,30 +79,35 @@ usage(void)
exit(2);
}
static int
mkdirs(char *path, mode_t mode)
{
char *cp;
struct stat sb;
+ int res;
while (*path == '/' && path[1] == '/')
path++;
while ((cp = strrchr(path, '/')) && cp[1] == '\0')
*cp = '\0';
if (cp && cp != path) {
*cp = '\0';
if ((lstat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
mkdirs(path, mode) < 0) {
return -1;
}
*cp = '/';
}
- return mkdir(path, mode);
+ res = mkdir(path, mode);
+ if ((res != 0) && (errno == EEXIST))
+ return 0;
+ else
+ return res;
}
static uid_t
touid(char *owner)
{
struct passwd *pw;
uid_t uid;
char *cp;
--- a/lib/ds/plarena.c
+++ b/lib/ds/plarena.c
@@ -22,29 +22,73 @@
* David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
*/
#include <stdlib.h>
#include <string.h>
#include "plarena.h"
#include "prmem.h"
#include "prbit.h"
#include "prlog.h"
+#include "prmon.h"
+#include "prinit.h"
static PLArena *arena_freelist;
#ifdef PL_ARENAMETER
static PLArenaStats *arena_stats_list;
#define COUNT(pool,what) (pool)->stats.what++
#else
#define COUNT(pool,what) /* nothing */
#endif
#define PL_ARENA_DEFAULT_ALIGN sizeof(double)
+static PRMonitor *arenaLock;
+static PRCallOnceType once;
+
+/*
+** InitializeArenas() -- Initialize arena operations.
+**
+** InitializeArenas() is called exactly once and only once from
+** LockArena(). This function creates the arena protection
+** monitor: arenaLock.
+**
+** Note: If the arenaLock cannot be created, InitializeArenas()
+** fails quietly, returning only PR_FAILURE. This percolates up
+** to the application using the Arena API. He gets no arena
+** from PL_ArenaAllocate(). It's up to him to fail gracefully
+** or recover.
+**
+*/
+static PRStatus InitializeArenas( void )
+{
+ PR_ASSERT( arenaLock == NULL );
+ arenaLock = PR_NewMonitor();
+ if ( arenaLock == NULL )
+ return PR_FAILURE;
+ else
+ return PR_SUCCESS;
+} /* end ArenaInitialize() */
+
+static PRStatus LockArena( void )
+{
+ PRStatus rc = PR_CallOnce( &once, InitializeArenas );
+
+ if ( PR_FAILURE != rc )
+ PR_EnterMonitor( arenaLock );
+ return(rc);
+} /* end LockArena() */
+
+static void UnlockArena( void )
+{
+ PR_ExitMonitor( arenaLock );
+ return;
+} /* end UnlockArena() */
+
PR_IMPLEMENT(void) PL_InitArenaPool(
PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align)
{
#if defined(XP_MAC)
#pragma unused (name)
#endif
if (align == 0)
@@ -69,16 +113,18 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PL
PRUint32 sz;
void *p;
PR_ASSERT((nb & pool->mask) == 0);
#if defined(WIN16)
if (nb >= 60000U)
return 0;
#endif /* WIN16 */
+ if ( PR_FAILURE == LockArena())
+ return(0);
ap = &arena_freelist;
for (a = pool->current; a->avail + nb > a->limit; pool->current = a) {
if (a->next) { /* move to next arena */
a = a->next;
continue;
}
while ((b = *ap) != 0) { /* reclaim a free arena */
if (b->limit - b->base == pool->arenasize) {
@@ -89,25 +135,29 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PL
goto claim;
}
ap = &b->next;
}
sz = PR_MAX(pool->arenasize, nb); /* allocate a new arena */
sz += sizeof *a + pool->mask; /* header and alignment slop */
b = (PLArena*)PR_MALLOC(sz);
if (!b)
+ {
+ UnlockArena();
return 0;
+ }
a = a->next = b;
a->next = 0;
a->limit = (PRUword)a + sz;
PL_COUNT_ARENA(pool,++);
COUNT(pool, nmallocs);
claim:
a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
}
+ UnlockArena();
p = (void *)a->avail;
a->avail += nb;
return p;
}
PR_IMPLEMENT(void *) PL_ArenaGrow(
PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr)
{
@@ -148,19 +198,21 @@ static void FreeArenaList(PLArenaPool *p
PL_COUNT_ARENA(pool,--);
PR_DELETE(a);
} while ((a = *ap) != 0);
} else {
/* Insert the whole arena chain at the front of the freelist. */
do {
ap = &(*ap)->next;
} while (*ap);
+ LockArena();
*ap = arena_freelist;
arena_freelist = a;
head->next = 0;
+ UnlockArena();
}
pool->current = head;
}
PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
{
PLArena *a;
@@ -214,21 +266,23 @@ PR_IMPLEMENT(void) PL_CompactArenaPool(P
#endif
#endif
}
PR_IMPLEMENT(void) PL_ArenaFinish()
{
PLArena *a, *next;
+ LockArena();
for (a = arena_freelist; a; a = next) {
next = a->next;
PR_DELETE(a);
}
arena_freelist = NULL;
+ UnlockArena();
}
#ifdef PL_ARENAMETER
PR_IMPLEMENT(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb)
{
pool->stats.nallocs++;
pool->stats.nbytes += nb;
if (nb > pool->stats.maxalloc)
--- a/lib/libc/src/plerror.c
+++ b/lib/libc/src/plerror.c
@@ -91,16 +91,17 @@ static const char *tags[] =
"PR_FILE_EXISTS_ERROR",
"PR_MAX_DIRECTORY_ENTRIES_ERROR",
"PR_INVALID_DEVICE_STATE_ERROR",
"PR_DEVICE_IS_LOCKED_ERROR",
"PR_NO_MORE_FILES_ERROR",
"PR_END_OF_FILE_ERROR",
"PR_FILE_SEEK_ERROR",
"PR_FILE_IS_BUSY_ERROR",
+ "<unused error code>",
"PR_IN_PROGRESS_ERROR",
"PR_ALREADY_INITIATED_ERROR",
"PR_GROUP_EMPTY_ERROR",
"PR_INVALID_STATE_ERROR",
"PR_NETWORK_DOWN_ERROR",
"PR_SOCKET_SHUTDOWN_ERROR",
"PR_CONNECT_ABORTED_ERROR",
"PR_HOST_UNREACHABLE_ERROR",
new file mode 100644
--- /dev/null
+++ b/lib/tests/arena.c
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+** File: arena.c
+** Description: Testing arenas
+**
+*/
+
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include "nspr.h"
+#include "plarena.h"
+#include "plgetopt.h"
+
+PRLogModuleInfo *tLM;
+PRIntn threadCount = 0;
+PRMonitor *tMon;
+PRBool failed_already = PR_FALSE;
+
+/* Arguments from the command line with default values */
+PRIntn debug_mode = 0;
+PRIntn poolMin = 4096;
+PRIntn poolMax = (100 * 4096);
+PRIntn arenaMin = 40;
+PRIntn arenaMax = (100 * 40);
+PRIntn stressIterations = 15;
+PRIntn maxAlloc = (1024 * 1024);
+PRIntn stressThreads = 4;
+
+/*
+** Test arena Mark and Release.
+*/
+static void MarkAndRelease( void )
+{
+ PLArenaPool ap;
+ void *ptr;
+ void *mark;
+
+ PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double));
+ PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+
+ mark = PL_ARENA_MARK( &ap );
+
+ PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+
+ PL_ARENA_RELEASE( &ap, mark );
+ PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+
+ if ( ptr != mark )
+ {
+ failed_already = PR_TRUE;
+ PR_LOG( tLM, PR_LOG_ERROR, ("Mark and Release failed: expected %p, got %p\n", mark, ptr));
+ }
+ else
+ PR_LOG( tLM, PR_LOG_DEBUG, ("Mark and Release passed\n"));
+
+ return;
+} /* end MarkAndRelease() */
+
+/*
+** RandSize() returns a random number in the range
+** min..max, rounded to the next doubleword
+**
+*/
+static PRIntn RandSize( PRIntn min, PRIntn max )
+{
+ PRIntn sz = (rand() % (max -min)) + min + sizeof(double);
+
+ sz &= ~sizeof(double)-1;
+
+ return(sz);
+}
+
+
+/*
+** StressThread()
+** A bunch of these beat on individual arenas
+** This tests the free_list protection.
+**
+*/
+static void PR_CALLBACK StressThread( void *arg )
+{
+ PLArenaPool ap;
+ PRIntn i;
+ PRIntn sz;
+ void *ptr;
+ PRThread *tp = PR_GetCurrentThread();
+
+ PR_LOG( tLM, PR_LOG_DEBUG, ("Stress Thread %p started\n", PR_GetCurrentThread()));
+ PL_InitArenaPool( &ap, "TheArena", RandSize( poolMin, poolMax), sizeof(double));
+
+ for ( i = 0; i < stressIterations; i++ )
+ {
+ PRIntn allocated = 0;
+
+ while ( allocated < maxAlloc )
+ {
+ sz = RandSize( arenaMin, arenaMax );
+ PL_ARENA_ALLOCATE( ptr, &ap, sz );
+ if ( ptr == NULL )
+ {
+ PR_LOG( tLM, PR_LOG_ERROR, ("ARENA_ALLOCATE() returned NULL\n\tAllocated: %d\n", allocated));
+ break;
+ }
+ allocated += sz;
+ }
+ PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished one iteration\n", tp));
+ PL_FreeArenaPool( &ap );
+ }
+ PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished all iteration\n", tp));
+ PL_FinishArenaPool( &ap );
+ PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p after FinishArenaPool()\n", tp));
+
+ /* That's all folks! let's quit */
+ PR_EnterMonitor(tMon);
+ threadCount--;
+ PR_Notify(tMon);
+ PR_ExitMonitor(tMon);
+ return;
+}
+
+/*
+** Stress()
+** Flog the hell out of arenas multi-threaded.
+** Do NOT pass an individual arena to another thread.
+**
+*/
+static void Stress( void )
+{
+ PRThread *tt;
+ PRIntn i;
+
+ tMon = PR_NewMonitor();
+
+ for ( i = 0 ; i < stressThreads ; i++ )
+ {
+ PR_EnterMonitor(tMon);
+ tt = PR_CreateThread(PR_USER_THREAD,
+ StressThread,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ threadCount++;
+ PR_ExitMonitor(tMon);
+ }
+
+ /* Wait for all threads to exit */
+ PR_EnterMonitor(tMon);
+ while ( threadCount != 0 )
+ {
+ PR_Wait(tMon, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(tMon);
+ PR_DestroyMonitor(tMon);
+
+ return;
+} /* end Stress() */
+
+/*
+** EvaluateResults()
+** uses failed_already to display results and set program
+** exit code.
+*/
+static PRIntn EvaluateResults(void)
+{
+ PRIntn rc = 0;
+
+ if ( failed_already == PR_TRUE )
+ {
+ PR_LOG( tLM, PR_LOG_DEBUG, ("FAIL\n"));
+ rc =1;
+ }
+ else
+ {
+ PR_LOG( tLM, PR_LOG_DEBUG, ("PASS\n"));
+ }
+ return(rc);
+} /* EvaluateResults() */
+
+void Help( void )
+{
+ printf("arena [options]\n");
+ printf("where options are:\n");
+ printf("-p <n> minimum size of an arena pool. Default(%d)\n", poolMin);
+ printf("-P <n> maximum size of an arena pool. Default(%d)\n", poolMax);
+ printf("-a <n> minimum size of an arena allocation. Default(%d)\n", arenaMin);
+ printf("-A <n> maximum size of an arena allocation. Default(%d)\n", arenaMax);
+ printf("-i <n> number of iterations in a stress thread. Default(%d)\n", stressIterations);
+ printf("-s <n> maximum allocation for a single stress thread. Default(%d)\n", maxAlloc);
+ printf("-t <n> number of stress threads. Default(%d)\n", stressThreads );
+ printf("-d enable debug mode\n");
+ printf("\n");
+ exit(1);
+}
+
+PRIntn main(PRIntn argc, char *argv[])
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dhp:P:a:A:i:s:t:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option)
+ {
+ case 'a': /* arena Min size */
+ arenaMin = atol( opt->value );
+ break;
+ case 'A': /* arena Max size */
+ arenaMax = atol( opt->value );
+ break;
+ case 'p': /* pool Min size */
+ poolMin = atol( opt->value );
+ break;
+ case 'P': /* pool Max size */
+ poolMax = atol( opt->value );
+ break;
+ case 'i': /* Iterations in stress tests */
+ stressIterations = atol( opt->value );
+ break;
+ case 's': /* storage to get per iteration */
+ maxAlloc = atol( opt->value );
+ break;
+ case 't': /* Number of stress threads to create */
+ stressThreads = atol( opt->value );
+ break;
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'h': /* help */
+ default:
+ Help();
+ } /* end switch() */
+ } /* end while() */
+ PL_DestroyOptState(opt);
+
+ srand( (unsigned)time( NULL ) ); /* seed random number generator */
+ tLM = PR_NewLogModule("testcase");
+
+ MarkAndRelease();
+
+ Stress();
+
+ return(EvaluateResults());
+} /* end main() */
+
+/* arena.c */
index 57934998a127e5aaa6de709f6e928028a3f4f75d..f15a68a21d4c0a5b67922ed2c64b807c93405827
GIT binary patch
literal 85613
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
--- a/macbuild/NSPRConfig.h
+++ b/macbuild/NSPRConfig.h
@@ -11,16 +11,14 @@
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
-#define OLDROUTINELOCATIONS 0
+#include "DefinesMac.h"
+#include "DefinesMozilla.h"
-#define XP_MAC 1
#define _PR_NO_PREEMPT 1
#define _NO_FAST_STRING_INLINES_ 1
#define FORCE_PR_LOG 1
-#define NSPR20 1
-
--- a/pr/include/md/_dgux.h
+++ b/pr/include/md/_dgux.h
@@ -41,16 +41,18 @@
#define HAVE_NETCONFIG
#define HAVE_DLL
#define USE_DLFCN
#define NEED_STRFTIME_LOCK
#define NEED_TIME_R
#define _PR_NEED_STRCASECMP
#define _PR_POLL_AVAILABLE
#define _PR_USE_POLL
+#define _PR_NO_LARGE_FILES
+#define _PR_STAT_HAS_ONLY_ST_ATIME
#define USE_SETJMP
#include <setjmp.h>
#define _SETJMP setjmp
#define _LONGJMP longjmp
#define _PR_CONTEXT_TYPE jmp_buf
@@ -110,18 +112,54 @@ struct _MDSemaphore {
struct _MDCVar {
PRInt8 notused;
};
struct _MDSegment {
PRInt8 notused;
};
+/*
+ * md-specific cpu structure field
+ */
+#define _PR_MD_MAX_OSFD FD_SETSIZE
+
+struct _MDCPU_Unix {
+ PRCList ioQ;
+ PRUint32 ioq_timeout;
+ PRInt32 ioq_max_osfd;
+ PRInt32 ioq_osfd_cnt;
+#ifndef _PR_USE_POLL
+ fd_set fd_read_set, fd_write_set, fd_exception_set;
+ PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD],
+ fd_exception_cnt[_PR_MD_MAX_OSFD];
+#else
+ struct pollfd *ioq_pollfds;
+ int ioq_pollfds_size;
+#endif /* _PR_USE_POLL */
+};
+
+#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ)
+#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu))
+#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set)
+#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt)
+#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set)
+#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt)
+#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set)
+#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt)
+#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout)
+#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd)
+#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt)
+#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds)
+#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size)
+
+#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32
+
struct _MDCPU {
- struct _MDCPU_Unix md_unix;
+ struct _MDCPU_Unix md_unix;
};
#define _MD_INIT_LOCKS()
#define _MD_NEW_LOCK(lock) PR_SUCCESS
#define _MD_FREE_LOCK(lock)
#define _MD_LOCK(lock)
#define _MD_UNLOCK(lock)
#define _MD_INIT_IO()
--- a/pr/include/md/_linux.h
+++ b/pr/include/md/_linux.h
@@ -54,23 +54,21 @@
#undef HAVE_STACK_GROWING_UP
/*
* Elf linux supports dl* functions
*/
#define HAVE_DLL
#define USE_DLFCN
-#if !defined(MKLINUX) && !defined(NEED_TIME_R)
-#define NEED_TIME_R
+#define USE_SETJMP
+#if defined(__GLIBC__) && __GLIBC__ >= 2
+#define _PR_POLL_AVAILABLE
#endif
-
-#define USE_SETJMP
-#define _PR_POLL_AVAILABLE
-#define _PR_USE_POLL
+#undef _PR_USE_POLL
#define _PR_STAT_HAS_ONLY_ST_ATIME
#if defined(__alpha)
#define _PR_HAVE_LARGE_OFF_T
#else
#define _PR_NO_LARGE_FILES
#endif
#ifdef _PR_PTHREADS
@@ -82,18 +80,27 @@ extern void _MD_CleanupBeforeExit(void);
#include <setjmp.h>
#define PR_CONTEXT_TYPE sigjmp_buf
#define CONTEXT(_th) ((_th)->md.context)
#ifdef __powerpc__
-/* PowerPC based MkLinux */
+/*
+ * PowerPC based MkLinux
+ *
+ * On the PowerPC, the new style jmp_buf isn't used until glibc
+ * 2.1.
+ */
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_GPR1]
+#else
#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__misc[0]
+#endif /* __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 */
#define _MD_SET_FP(_t, val)
#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t))
#define _MD_GET_FP_PTR(_t) ((void *) 0)
/* aix = 64, macos = 70 */
#define PR_NUM_GCREGS 64
#elif defined(__alpha)
/* Alpha based Linux */
@@ -187,16 +194,28 @@ extern void _MD_CleanupBeforeExit(void);
#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[0].__fp = (val))
#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t))
#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[0].__fp)
#define _MD_SP_TYPE __ptr_t
#else
#error "Linux/MIPS pre-glibc2 not supported yet"
#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */
+#elif defined(__arm__)
+/* ARM/Linux */
+#if defined(__GLIBC__) && __GLIBC__ >= 2
+#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[20]
+#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[19] = (val))
+#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t))
+#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[19])
+#define _MD_SP_TYPE __ptr_t
+#else
+#error "ARM/Linux pre-glibc2 not supported yet"
+#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */
+
#else
#error "Unknown CPU architecture"
#endif /*__powerpc__*/
/*
** Initialize a thread context to run "_main()" when started
@@ -288,16 +307,17 @@ struct _MDCVar {
struct _MDSegment {
PRInt8 notused;
};
/*
* md-specific cpu structure field
*/
+#include <sys/time.h> /* for FD_SETSIZE */
#define _PR_MD_MAX_OSFD FD_SETSIZE
struct _MDCPU_Unix {
PRCList ioQ;
PRUint32 ioq_timeout;
PRInt32 ioq_max_osfd;
PRInt32 ioq_osfd_cnt;
#ifndef _PR_USE_POLL
--- a/pr/include/md/_macos.h
+++ b/pr/include/md/_macos.h
@@ -458,36 +458,30 @@ typedef int (*FARPROC)();
extern long gTimeSlicesOnNonPrimaryThread;
extern struct PRThread *gPrimaryThread;
typedef short PROSFD;
// Errors not found in the Mac StdCLib
#define EACCES 13 // Permission denied
#define ENOENT -43 // No such file or directory
-#define EMFILE 24 // Too many open files
#define _OS_INVALID_FD_VALUE -1
#define STDERR_FILENO 2
#if !defined(MAC_NSPR_STANDALONE)
-#define MAC_PATH_SEPARATOR ':'
#define PATH_SEPARATOR ':'
#define PATH_SEPARATOR_STR ":"
#define DIRECTORY_SEPARATOR '/'
#define DIRECTORY_SEPARATOR_STR "/"
#endif
#define UNIX_THIS_DIRECTORY_STR "./"
#define UNIX_PARENT_DIRECTORY_STR "../"
-#define MAX_PATH 512
-#define MAX_MAC_FILENAME 31
-#define MAXPATHLEN MAX_PATH
-
// Alias a few names
#define getenv PR_GetEnv
#define putenv _MD_PutEnv
#if defined(MAC_NSPR_STANDALONE)
typedef unsigned char (*MemoryCacheFlusherProc)(size_t size);
typedef void (*PreAllocationHookProc)(void);
@@ -529,20 +523,16 @@ extern FILE *_OS_FOPEN(const char *filen
extern void dprintf(const char *format, ...);
// Entry into the memory system's cache flushing
#if defined(MAC_NSPR_STANDALONE)
extern PRUint8 CallCacheFlushers(size_t blockSize);
#endif
-enum {
- kPrivateNSPREventType = 13
-};
-
#if defined(MAC_NSPR_STANDALONE)
extern void* reallocSmaller(void* block, size_t newSize);
#endif
/*
** PR_GetSystemInfo related definitions
*/
--- a/pr/include/md/_solaris.h
+++ b/pr/include/md/_solaris.h
@@ -335,17 +335,16 @@ struct _MDCPU {
struct _MDCPU_Unix md_unix;
};
/* The following defines the unwrapped versions of select() and poll(). */
extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
#define _MD_SELECT _select
-#include <stropts.h>
#include <poll.h>
#define _MD_POLL _poll
extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
PR_BEGIN_EXTERN_C
/*
** Missing function prototypes
--- a/pr/include/prinit.h
+++ b/pr/include/prinit.h
@@ -39,21 +39,21 @@ PR_BEGIN_EXTERN_C
/*
** NSPR's version is used to determine the likelihood that the version you
** used to build your component is anywhere close to being compatible with
** what is in the underlying library.
**
** The format of the version string is
** "<major version>.<minor version> <build date>"
*/
-#define PR_VERSION "3.0 yyyymmdd"
+#define PR_VERSION "3.0 19981002"
#define PR_VMAJOR 3
#define PR_VMINOR 0
#define PR_VPATCH 0
-#define PR_BETA PR_TRUE
+#define PR_BETA PR_FALSE
/*
** PRVersionCheck
**
** The basic signature of the function that is called to provide version
** checking. The result will be a boolean that indicates the likelihood
** that the underling library will perform as the caller expects.
**
--- a/pr/include/private/pprmwait.h
+++ b/pr/include/private/pprmwait.h
@@ -20,24 +20,29 @@
#else
#define _PPRMWAIT_H
#include "prlock.h"
#include "prcvar.h"
#include "prclist.h"
#include "prthread.h"
-#define _PR_HASH_OFFSET 75013
#define MAX_POLLING_INTERVAL 100
#define _PR_POLL_COUNT_FUDGE 64
#define MAX_POLLING_INTERVAL 100
#define _PR_DEFAULT_HASH_LENGTH 59
-#define _MW_REHASH(a, i, m) _MW_HASH((PRUptrdiff)(a) + (i) + _PR_HASH_OFFSET, m)
+/*
+ * Our hash table resolves collisions by open addressing with
+ * double hashing. See Cormen, Leiserson, and Rivest,
+ * Introduction to Algorithms, p. 232, The MIT Press, 1990.
+ */
+
#define _MW_HASH(a, m) ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m))
+#define _MW_HASH2(a, m) (1 + ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m - 2)))
#define _MW_ABORTED(_rv) \
((PR_FAILURE == (_rv)) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError()))
typedef enum {_prmw_success, _prmw_rehash, _prmw_error} _PR_HashStory;
typedef struct _PRWaiterHash
{
PRUint16 count; /* current number in hash table */
--- a/pr/include/prsystem.h
+++ b/pr/include/prsystem.h
@@ -27,16 +27,23 @@
PR_BEGIN_EXTERN_C
/*
** Get the host' directory separator.
** Pathnames are then assumed to be of the form:
** [<sep><root_component><sep>]*(<component><sep>)<leaf_name>
*/
+PR_EXTERN(char) PR_GetDirectorySeparator(void);
+
+/*
+** OBSOLETE -- the function name is misspelled.
+** Use PR_GetDirectorySeparator instead.
+*/
+
PR_EXTERN(char) PR_GetDirectorySepartor(void);
/* Types of information available via PR_GetSystemInfo(...) */
typedef enum {
PR_SI_HOSTNAME,
PR_SI_SYSNAME,
PR_SI_RELEASE,
--- a/pr/src/io/prfile.c
+++ b/pr/src/io/prfile.c
@@ -502,16 +502,18 @@ PR_IMPLEMENT(PRStatus) PR_CreatePipe(
#if defined(XP_MAC)
#pragma unused (readPipe, writePipe)
#endif
#ifdef WIN32
HANDLE readEnd, writeEnd;
SECURITY_ATTRIBUTES pipeAttributes;
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
ZeroMemory(&pipeAttributes, sizeof(pipeAttributes));
pipeAttributes.nLength = sizeof(pipeAttributes);
pipeAttributes.bInheritHandle = TRUE;
if (CreatePipe(&readEnd, &writeEnd, &pipeAttributes, 0) == 0) {
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
return PR_FAILURE;
}
*readPipe = PR_AllocFileDesc((PRInt32)readEnd, &_pr_fileMethods);
@@ -529,16 +531,18 @@ PR_IMPLEMENT(PRStatus) PR_CreatePipe(
#ifdef WINNT
(*readPipe)->secret->md.nonoverlapped = PR_TRUE;
(*writePipe)->secret->md.nonoverlapped = PR_TRUE;
#endif
return PR_SUCCESS;
#elif defined(XP_UNIX)
int pipefd[2];
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
if (pipe(pipefd) == -1) {
/* XXX map pipe error */
PR_SetError(PR_UNKNOWN_ERROR, errno);
return PR_FAILURE;
}
*readPipe = PR_AllocFileDesc(pipefd[0], &_pr_fileMethods);
if (NULL == *readPipe) {
close(pipefd[0]);
--- a/pr/src/io/prmwait.c
+++ b/pr/src/io/prmwait.c
@@ -263,16 +263,18 @@ static _PR_HashStory MW_AddHashInternal(
** We try to put the entry in by rehashing _MW_REHASH_MAX times. After
** that we declare defeat and force the table to be reconstructed.
** Since some fds might be added more than once, won't that cause
** collisions even in an empty table?
*/
PRIntn rehash = _MW_REHASH_MAX;
PRRecvWait **waiter;
PRUintn hidx = _MW_HASH(desc->fd, hash->length);
+ PRUintn hoffset = 0;
+
while (rehash-- > 0)
{
waiter = &hash->recv_wait;
if (NULL == waiter[hidx])
{
waiter[hidx] = desc;
hash->count += 1;
#if 0
@@ -289,74 +291,94 @@ static _PR_HashStory MW_AddHashInternal(
return _prmw_error;
}
#if 0
printf("Failing 0x%x->0x%x ", desc, desc->fd);
printf(
"table[*%u:%u:%u]: 0x%x->0x%x\n",
hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd);
#endif
- hidx = _MW_REHASH(desc->fd, hidx, hash->length);
+ if (0 == hoffset)
+ {
+ hoffset = _MW_HASH2(desc->fd, hash->length);
+ PR_ASSERT(0 != hoffset);
+ }
+ hidx = (hidx + hoffset) % (hash->length);
}
return _prmw_rehash;
} /* MW_AddHashInternal */
static _PR_HashStory MW_ExpandHashInternal(PRWaitGroup *group)
{
PRRecvWait **desc;
- PRUint32 pidx, length = 0;
+ PRUint32 pidx, length;
_PRWaiterHash *newHash, *oldHash = group->waiter;
-
+ PRBool retry;
+ _PR_HashStory hrv;
static const PRInt32 prime_number[] = {
_PR_DEFAULT_HASH_LENGTH, 179, 521, 907, 1427,
2711, 3917, 5021, 8219, 11549, 18911, 26711, 33749, 44771};
- PRUintn primes = (sizeof(prime_number) / sizeof(PRIntn));
+ PRUintn primes = (sizeof(prime_number) / sizeof(PRInt32));
/* look up the next size we'd like to use for the hash table */
for (pidx = 0; pidx < primes; ++pidx)
{
if (prime_number[pidx] == oldHash->length)
{
- length = prime_number[pidx + 1];
break;
}
}
- if (0 == length)
+ /* table size must be one of the prime numbers */
+ PR_ASSERT(pidx < primes);
+
+ /* if pidx == primes - 1, we can't expand the table any more */
+ while (pidx < primes - 1)
{
- PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
- return _prmw_error; /* we're hosed */
- }
+ /* next size */
+ ++pidx;
+ length = prime_number[pidx];
+
+ /* allocate the new hash table and fill it in with the old */
+ newHash = (_PRWaiterHash*)PR_CALLOC(
+ sizeof(_PRWaiterHash) + (length * sizeof(PRRecvWait*)));
+ if (NULL == newHash)
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return _prmw_error;
+ }
- /* allocate the new hash table and fill it in with the old */
- newHash = (_PRWaiterHash*)PR_CALLOC(
- sizeof(_PRWaiterHash) + (length * sizeof(PRRecvWait*)));
- if (NULL == newHash)
- {
- PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
- return _prmw_error;
+ newHash->length = length;
+ retry = PR_FALSE;
+ for (desc = &oldHash->recv_wait;
+ newHash->count < oldHash->count; ++desc)
+ {
+ PR_ASSERT(desc < &oldHash->recv_wait + oldHash->length);
+ if (NULL != *desc)
+ {
+ hrv = MW_AddHashInternal(*desc, newHash);
+ PR_ASSERT(_prmw_error != hrv);
+ if (_prmw_success != hrv)
+ {
+ PR_DELETE(newHash);
+ retry = PR_TRUE;
+ break;
+ }
+ }
+ }
+ if (retry) continue;
+
+ PR_DELETE(group->waiter);
+ group->waiter = newHash;
+ group->p_timestamp += 1;
+ return _prmw_success;
}
- newHash->length = length;
- for (desc = &oldHash->recv_wait; newHash->count < oldHash->count; ++desc)
- {
- if (NULL != *desc)
- {
- if (_prmw_success != MW_AddHashInternal(*desc, newHash))
- {
- PR_ASSERT(!"But, but, but ...");
- PR_DELETE(newHash);
- return _prmw_error;
- }
- }
- }
- PR_DELETE(group->waiter);
- group->waiter = newHash;
- group->p_timestamp += 1;
- return _prmw_success;
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return _prmw_error; /* we're hosed */
} /* MW_ExpandHashInternal */
#ifndef WINNT
static void _MW_DoneInternal(
PRWaitGroup *group, PRRecvWait **waiter, PRMWStatus outcome)
{
/*
** Add this receive wait object to the list of finished I/O
@@ -382,22 +404,28 @@ static PRRecvWait **_MW_LookupInternal(P
/*
** Find the receive wait object corresponding to the file descriptor.
** Only search the wait group specified.
*/
PRRecvWait **desc;
PRIntn rehash = _MW_REHASH_MAX;
_PRWaiterHash *hash = group->waiter;
PRUintn hidx = _MW_HASH(fd, hash->length);
+ PRUintn hoffset = 0;
while (rehash-- > 0)
{
desc = (&hash->recv_wait) + hidx;
if ((*desc != NULL) && ((*desc)->fd == fd)) return desc;
- hidx = _MW_REHASH(fd, hidx, hash->length);
+ if (0 == hoffset)
+ {
+ hoffset = _MW_HASH2(fd, hash->length);
+ PR_ASSERT(0 != hoffset);
+ }
+ hidx = (hidx + hoffset) % (hash->length);
}
return NULL;
} /* _MW_LookupInternal */
#ifndef WINNT
static PRStatus _MW_PollInternal(PRWaitGroup *group)
{
PRRecvWait **waiter;
@@ -844,16 +872,24 @@ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvRea
}
_PR_THREAD_UNLOCK(me);
_PR_MD_UNLOCK(&group->mdlock);
PR_Unlock(group->ml);
_PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
me->state = _PR_RUNNING;
PR_Lock(group->ml);
_PR_MD_LOCK(&group->mdlock);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ PR_REMOVE_LINK(&me->waitQLinks);
+ _PR_MD_UNLOCK(&group->mdlock);
+ me->flags &= ~_PR_INTERRUPT;
+ me->io_suspended = PR_FALSE;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ goto aborted;
+ }
}
io_ready = PR_LIST_HEAD(&group->io_ready);
PR_ASSERT(io_ready != NULL);
PR_REMOVE_LINK(io_ready);
_PR_MD_UNLOCK(&group->mdlock);
overlapped = (_MDOverlapped *)
((char *)io_ready - offsetof(_MDOverlapped, data));
io_ready = &overlapped->data.mw.desc->internal;
@@ -943,21 +979,22 @@ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvRea
PR_ASSERT(!PR_CLIST_IS_EMPTY(&group->io_ready));
}
io_ready = PR_LIST_HEAD(&group->io_ready);
PR_NotifyCondVar(group->io_taken);
PR_ASSERT(io_ready != NULL);
PR_REMOVE_LINK(io_ready);
} while (NULL == io_ready);
-aborted:
failed_poll:
#endif
+aborted:
+
group->waiting_threads -= 1;
invalid_state:
(void)MW_TestForShutdownInternal(group);
PR_Unlock(group->ml);
failed_init:
if (NULL != io_ready)
{
@@ -1179,16 +1216,28 @@ PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitG
else
{
PRCList *head = PR_LIST_HEAD(&group->io_ready);
PR_REMOVE_AND_INIT_LINK(head);
#ifdef WINNT
overlapped = (_MDOverlapped *)
((char *)head - offsetof(_MDOverlapped, data));
head = &overlapped->data.mw.desc->internal;
+ if (NULL != overlapped->data.mw.timer)
+ {
+ PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
+ != overlapped->data.mw.desc->timeout);
+ CancelTimer(overlapped->data.mw.timer);
+ }
+ else
+ {
+ PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
+ == overlapped->data.mw.desc->timeout);
+ }
+ PR_DELETE(overlapped);
#endif
recv_wait = (PRRecvWait*)head;
}
#ifdef WINNT
invalid_arg:
_PR_MD_UNLOCK(&group->mdlock);
#endif
PR_Unlock(group->ml);
--- a/pr/src/io/prprf.c
+++ b/pr/src/io/prprf.c
@@ -30,21 +30,21 @@
#include "prlong.h"
#include "prlog.h"
#include "prmem.h"
/*
** Note: on some platforms va_list is defined as an array,
** and requires array notation.
*/
-#if defined(MKLINUX) || defined(WIN16)
+#if (defined(LINUX) && defined(__powerpc__)) || defined(WIN16)
#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
#else
#define VARARGS_ASSIGN(foo, bar) (foo) = (bar)
-#endif /*MKLINUX*/
+#endif
/*
** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it)
*/
/*
** XXX This needs to be internationalized!
*/
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -1111,16 +1111,18 @@ PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocke
return PR_Socket(domain, SOCK_DGRAM, 0);
}
PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
{
#ifdef XP_UNIX
PRInt32 rv, osfd[2];
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
if (rv == -1) {
return PR_FAILURE;
}
f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
if (!f[0]) {
_PR_MD_CLOSE_SOCKET(osfd[0]);
@@ -1351,17 +1353,16 @@ PRInt32 _PR_EmulateAcceptRead(
/* copy the new info out where caller can see it */
PRPtrdiff aligned = (PRPtrdiff)buf + amount + sizeof(void*) - 1;
*raddr = (PRNetAddr*)(aligned & ~(sizeof(void*) - 1));
memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
*nd = accepted;
return rv;
}
-failed:
PR_Close(accepted);
return rv;
}
/*
** Select compatibility
**
*/
--- a/pr/src/md/mac/macio.c
+++ b/pr/src/md/mac/macio.c
@@ -328,17 +328,17 @@ ErrorExit:
/* File I/O functions called by PR I/O routines */
PRInt32 _MD_Open(const char *path, PRIntn oflag, int mode)
{
// Macintosh doesn¹t really have mode bits, just drop them
#pragma unused (mode)
OSErr err;
- ParamBlockRec pb;
+ HParamBlockRec pb;
char *macFileName = NULL;
Str255 pascalName;
PRInt8 perm;
PRInt32 flags = oflag;
if (flags & PR_RDWR) {
oflag = O_RDWR;
} else if (flags & PR_WRONLY) {
@@ -370,23 +370,23 @@ open:
else if (perm == O_WRONLY)
perm = fsWrPerm;
else
perm = fsRdPerm;
pb.ioParam.ioPermssn = perm;
pb.ioParam.ioMisc = NULL;
- err = PBOpenSync(&pb);
+ err = PBHOpenSync(&pb);
if (err == noErr)
return pb.ioParam.ioRefNum;
else if ((err != fnfErr) || ((oflag & O_CREAT) == 0))
goto ErrorExit;
- err = PBCreateSync(&pb);
+ err = PBHCreateSync(&pb);
if (err == noErr)
goto open;
ErrorExit:
_PR_MD_CURRENT_THREAD()->md.osErrCode = err;
_MD_SetError(err);
return -1;
}
--- a/pr/src/md/unix/Makefile
+++ b/pr/src/md/unix/Makefile
@@ -190,17 +190,17 @@ ifeq ($(OS_ARCH), AIX)
endif
ifeq ($(OS_ARCH),SunOS)
ifeq ($(CPU_ARCH),x86)
ASFILES = os_$(OS_ARCH)_x86.s
else
ifneq ($(OS_RELEASE),4.1.3_U1)
ifneq ($(LOCAL_THREADS_ONLY),1)
- ASFILES = os_$(OS_ARCH).s
+ ASFILES += os_$(OS_ARCH).s
endif
endif
endif
endif
ifeq ($(OS_ARCH), SINIX)
ASFILES = os_ReliantUNIX.s
endif
@@ -221,22 +221,20 @@ ifneq ($(USE_PTHREADS), 1)
#TARGETS += $(OBJDIR)/aixwrap.$(OBJ_SUFFIX)
endif
endif
endif
ifeq ($(OS_ARCH),SunOS)
ifneq ($(OS_RELEASE),4.1.3_U1)
ifeq ($(OS_TEST),sun4u)
- LIBRARY_NAME = $(ULTRASPARC_LIBRARY)
- LIBRARY_VERSION = $(MOD_VERSION)
ULTRASPARC_ASFILES = os_$(OS_ARCH)_ultrasparc.s
+ ASFILES += $(ULTRASPARC_ASFILES)
+ CFLAGS += -D_PR_ULTRASPARC
ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX)))
- TARGETS += $(ULTRASPARC_ASOBJS) $(SHARED_LIBRARY)
- RELEASE_LIBS = $(SHARED_LIBRARY)
endif
endif
endif
INCLUDES = -I$(DIST)/include/private -I$(DIST)/include
include $(MOD_DEPTH)/config/rules.mk
@@ -247,19 +245,15 @@ export:: $(TARGETS)
# $(INSTALL) -m 444 $(OBJDIR)/aixwrap.$(OBJ_SUFFIX) $(DIST)/lib
#endif
#endif
#endif
ifeq ($(OS_ARCH),SunOS)
ifneq ($(OS_RELEASE),4.1.3_U1)
ifeq ($(OS_TEST),sun4u)
-$(SHARED_LIBRARY): $(ULTRASPARC_ASOBJS)
- $(LD) -G -z text -o $@ $(ULTRASPARC_ASOBJS)
- $(INSTALL) -m 444 $(SHARED_LIBRARY) $(DIST)/lib
-
$(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES)
/usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v8plus $<
endif
endif
endif
install:: export
--- a/pr/src/md/unix/irix.c
+++ b/pr/src/md/unix/irix.c
@@ -100,16 +100,17 @@ ulock_t _pr_heapLock;
usema_t *_pr_irix_exit_sem;
PRInt32 _pr_irix_exit_now = 0;
PRInt32 _pr_irix_process_exit_code = 0; /* exit code for PR_ProcessExit */
PRInt32 _pr_irix_process_exit = 0; /* process exiting due to call to
PR_ProcessExit */
int _pr_irix_primoridal_cpu_fd[2] = { -1, -1 };
static void (*libc_exit)(int) = NULL;
+static void *libc_handle = NULL;
#define _NSPR_DEF_INITUSERS 100 /* default value of CONF_INITUSERS */
#define _NSPR_DEF_INITSIZE (4 * 1024 * 1024) /* 4 MB */
int _irix_initusers = _NSPR_DEF_INITUSERS;
int _irix_initsize = _NSPR_DEF_INITSIZE;
PRIntn _pr_io_in_progress, _pr_clock_in_progress;
@@ -997,20 +998,30 @@ PRThread *me = _PR_MD_CURRENT_THREAD();
* The exit code of the process is the exit code of the primordial
* sproc.
*/
void exit(int status)
{
PRThread *me, *thr;
PRCList *qp;
-void __exit(int status);
+
+ if (!_pr_initialized) {
+ if (!libc_exit) {
- if (!_pr_initialized)
- __exit(status);
+ if (!libc_handle)
+ libc_handle = dlopen("libc.so",RTLD_NOW);
+ if (libc_handle)
+ libc_exit = (void (*)(int)) dlsym(libc_handle, "exit");
+ }
+ if (libc_exit)
+ (*libc_exit)(status);
+ else
+ _exit(status);
+ }
me = _PR_MD_CURRENT_THREAD();
if (me == NULL) /* detached thread */
(*libc_exit)(status);
PR_ASSERT(_PR_IS_NATIVE_THREAD(me) ||
(_PR_MD_CURRENT_CPU())->id == me->cpu->id);
@@ -1424,17 +1435,16 @@ void _MD_EarlyInit(void)
_MD_IrixIntervalInit();
} /* _MD_EarlyInit */
void _MD_IrixInit()
{
#if !defined(_PR_PTHREADS)
struct sigaction sigact;
PRThread *me = _PR_MD_CURRENT_THREAD();
- void *libc_handle;
int rv;
#ifndef IRIX5_3
/*
* enable user-level processing of sigprocmask(); this is an undocumented
* feature available in Irix 6.2, 6.3, 6.4 and 6.5
*/
__sgi_prda_procmask(USER_LEVEL);
--- a/pr/src/md/unix/objs.mk
+++ b/pr/src/md/unix/objs.mk
@@ -189,16 +189,24 @@ ifeq ($(OS_ARCH),SunOS)
ifneq ($(OS_RELEASE),4.1.3_U1)
ifneq ($(LOCAL_THREADS_ONLY),1)
ASFILES = os_$(OS_ARCH).s
endif
endif
endif
endif
+ifeq ($(OS_ARCH),SunOS)
+ ifneq ($(OS_RELEASE),4.1.3_U1)
+ ifeq ($(OS_TEST),sun4u)
+ ASFILES += os_$(OS_ARCH)_ultrasparc.s
+ endif
+ endif
+endif
+
ifeq ($(OS_ARCH), SINIX)
ASFILES = os_ReliantUNIX.s
endif
ifeq ($(OS_ARCH), IRIX)
ASFILES = os_Irix.s
endif
--- a/pr/src/md/unix/os_SunOS_ultrasparc.s
+++ b/pr/src/md/unix/os_SunOS_ultrasparc.s
@@ -44,30 +44,30 @@
!
! So, the registers used are:
! %o0 [input] - the address of the value to increment
! %o1 [local] - work register
! %o2 [local] - work register
! %o3 [local] - work register
! -----------------------
- ENTRY(PR_AtomicIncrement) ! standard assembler/ELF prologue
+ ENTRY(_pr_md_ultrasparc_inc) ! standard assembler/ELF prologue
retryAI:
ld [%o0], %o2 ! set o2 to the current value
add %o2, 0x1, %o3 ! calc the new value
mov %o3, %o1 ! save the return value
cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
cmp %o2, %o3 ! see if we set the value
bne retryAI ! if not, try again
nop ! empty out the branch pipeline
retl ! return back to the caller
mov %o1, %o0 ! set the return code to the new value
- SET_SIZE(PR_AtomicIncrement) ! standard assembler/ELF epilogue
+ SET_SIZE(_pr_md_ultrasparc_inc) ! standard assembler/ELF epilogue
!
! end
!
! ======================================================================
!
! ======================================================================
@@ -88,30 +88,30 @@ retryAI:
!
! So, the registers used are:
! %o0 [input] - the address of the value to increment
! %o1 [local] - work register
! %o2 [local] - work register
! %o3 [local] - work register
! -----------------------
- ENTRY(PR_AtomicDecrement) ! standard assembler/ELF prologue
+ ENTRY(_pr_md_ultrasparc_dec) ! standard assembler/ELF prologue
retryAD:
ld [%o0], %o2 ! set o2 to the current value
sub %o2, 0x1, %o3 ! calc the new value
mov %o3, %o1 ! save the return value
cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
cmp %o2, %o3 ! see if we set the value
bne retryAD ! if not, try again
nop ! empty out the branch pipeline
retl ! return back to the caller
mov %o1, %o0 ! set the return code to the new value
- SET_SIZE(PR_AtomicDecrement) ! standard assembler/ELF epilogue
+ SET_SIZE(_pr_md_ultrasparc_dec) ! standard assembler/ELF epilogue
!
! end
!
! ======================================================================
!
! ======================================================================
@@ -131,54 +131,54 @@ retryAD:
!
! So, the registers used are:
! %o0 [input] - the address of the value to increment
! %o1 [input] - the new value to set for [%o0]
! %o2 [local] - work register
! %o3 [local] - work register
! -----------------------
- ENTRY(PR_AtomicSet) ! standard assembler/ELF prologue
+ ENTRY(_pr_md_ultrasparc_set) ! standard assembler/ELF prologue
retryAS:
ld [%o0], %o2 ! set o2 to the current value
mov %o1, %o3 ! set up the new value
cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
cmp %o2, %o3 ! see if we set the value
bne retryAS ! if not, try again
nop ! empty out the branch pipeline
retl ! return back to the caller
mov %o3, %o0 ! set the return code to the prev value
- SET_SIZE(PR_AtomicSet) ! standard assembler/ELF epilogue
+ SET_SIZE(_pr_md_ultrasparc_set) ! standard assembler/ELF epilogue
!
! end
!
! ======================================================================
!
! ======================================================================
!
! Perform the sequence a = a + b atomically with respect to other
! fetch-and-adds to location a in a wait-free fashion.
!
! usage : newval = PR_AtomicAdd(address, val)
! return: the value after addition
!
- ENTRY(PR_AtomicAdd) ! standard assembler/ELF prologue
+ ENTRY(_pr_md_ultrasparc_add) ! standard assembler/ELF prologue
retryAA:
ld [%o0], %o2 ! set o2 to the current value
add %o2, %o1, %o3 ! calc the new value
mov %o3, %o4 ! save the return value
cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
cmp %o2, %o3 ! see if we set the value
bne retryAA ! if not, try again
nop ! empty out the branch pipeline
retl ! return back to the caller
mov %o4, %o0 ! set the return code to the new value
- SET_SIZE(PR_AtomicAdd) ! standard assembler/ELF epilogue
+ SET_SIZE(_pr_md_ultrasparc_add) ! standard assembler/ELF epilogue
!
! end
!
--- a/pr/src/md/unix/solaris.c
+++ b/pr/src/md/unix/solaris.c
@@ -14,16 +14,17 @@
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#undef _FILE_OFFSET_BITS
#include "primpl.h"
+#include <sys/systeminfo.h>
extern PRBool suspendAllOn;
extern PRThread *suspendAllThread;
extern void _MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri);
PRIntervalTime _MD_Solaris_TicksPerSecond(void)
@@ -53,18 +54,34 @@ PRIntervalTime _MD_Solaris_GetInterval(v
*/
LL_I2L(resolution, 10000);
LL_DIV(time.pr64, time.pr64, resolution);
LL_L2UI(ticks, time.pr64);
return ticks;
}
#ifdef _PR_PTHREADS
+
+static PRInt32 _md_ultrasparc = 0;
+
void _MD_EarlyInit(void)
{
+#define MACHINE_NAME_LEN 32
+#define ULTRASPARC "sun4u"
+char machine[MACHINE_NAME_LEN];
+int rv;
+
+ rv = sysinfo(SI_MACHINE, machine, MACHINE_NAME_LEN);
+ /*
+ * detect an ultrasparc (Sparc V9) system
+ */
+ if ((rv > 0) && (rv <= MACHINE_NAME_LEN)) {
+ if (!strncmp(machine,ULTRASPARC, strlen(ULTRASPARC)))
+ _md_ultrasparc = 1;
+ }
}
PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
{
*np = 0;
return NULL;
}
#endif /* _PR_PTHREADS */
@@ -85,70 +102,104 @@ PRWord *_MD_HomeGCRegisters(PRThread *t,
#include <synch.h>
static mutex_t _solaris_atomic = DEFAULTMUTEX;
PRInt32
_MD_AtomicIncrement(PRInt32 *val)
{
PRInt32 rv;
- if (mutex_lock(&_solaris_atomic) != 0)
- PR_ASSERT(0);
- rv = ++(*val);
+#ifdef _PR_ULTRASPARC
+ if (_md_ultrasparc) {
+ rv = _pr_md_ultrasparc_inc(val);
+ } else {
+#endif
+ if (mutex_lock(&_solaris_atomic) != 0)
+ PR_ASSERT(0);
- if (mutex_unlock(&_solaris_atomic) != 0)\
- PR_ASSERT(0);
+ rv = ++(*val);
+
+ if (mutex_unlock(&_solaris_atomic) != 0)\
+ PR_ASSERT(0);
+#ifdef _PR_ULTRASPARC
+ }
+#endif
return rv;
}
PRInt32
_MD_AtomicAdd(PRInt32 *ptr, PRInt32 val)
{
PRInt32 rv;
- if (mutex_lock(&_solaris_atomic) != 0)
- PR_ASSERT(0);
- rv = ((*ptr) += val);
+#ifdef _PR_ULTRASPARC
+ if (_md_ultrasparc) {
+ rv = _pr_md_ultrasparc_add(ptr, val);
+ } else {
+#endif
+ if (mutex_lock(&_solaris_atomic) != 0)
+ PR_ASSERT(0);
- if (mutex_unlock(&_solaris_atomic) != 0)\
- PR_ASSERT(0);
+ rv = ((*ptr) += val);
+
+ if (mutex_unlock(&_solaris_atomic) != 0)\
+ PR_ASSERT(0);
+#ifdef _PR_ULTRASPARC
+ }
+#endif
return rv;
}
PRInt32
_MD_AtomicDecrement(PRInt32 *val)
{
PRInt32 rv;
- if (mutex_lock(&_solaris_atomic) != 0)
- PR_ASSERT(0);
- rv = --(*val);
+#ifdef _PR_ULTRASPARC
+ if (_md_ultrasparc) {
+ rv = _pr_md_ultrasparc_dec(val);
+ } else {
+#endif
+ if (mutex_lock(&_solaris_atomic) != 0)
+ PR_ASSERT(0);
- if (mutex_unlock(&_solaris_atomic) != 0)\
- PR_ASSERT(0);
+ rv = --(*val);
+ if (mutex_unlock(&_solaris_atomic) != 0)\
+ PR_ASSERT(0);
+#ifdef _PR_ULTRASPARC
+ }
+#endif
return rv;
}
PRInt32
_MD_AtomicSet(PRInt32 *val, PRInt32 newval)
{
PRInt32 rv;
- if (mutex_lock(&_solaris_atomic) != 0)
- PR_ASSERT(0);
+
+#ifdef _PR_ULTRASPARC
+ if (_md_ultrasparc) {
+ rv = _pr_md_ultrasparc_set(val, newval);
+ } else {
+#endif
+ if (mutex_lock(&_solaris_atomic) != 0)
+ PR_ASSERT(0);
- rv = *val;
- *val = newval;
+ rv = *val;
+ *val = newval;
- if (mutex_unlock(&_solaris_atomic) != 0)\
- PR_ASSERT(0);
-
+ if (mutex_unlock(&_solaris_atomic) != 0)\
+ PR_ASSERT(0);
+#ifdef _PR_ULTRASPARC
+ }
+#endif
return rv;
}
#endif /* _PR_HAVE_ATOMIC_OPS */
#if defined(_PR_GLOBAL_THREADS_ONLY)
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
--- a/pr/src/md/unix/unix.c
+++ b/pr/src/md/unix/unix.c
@@ -25,17 +25,17 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#ifdef _PR_POLL_AVAILABLE
-#include <sys/poll.h>
+#include <poll.h>
#endif
/* To get FIONREAD */
#if defined(NCR) || defined(UNIXWARE) || defined(NEC) || defined(SNI) \
|| defined(SONY)
#include <sys/filio.h>
#endif
@@ -1424,26 +1424,25 @@ extern sigset_t ints_off;
#endif
}
/*
* if the cpu's pollfd array is not big enough, release it and allocate a new one
*/
if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) {
if (_PR_IOQ_POLLFDS(me->cpu) != NULL)
- PR_DELETE(pollfds);
+ PR_DELETE(_PR_IOQ_POLLFDS(me->cpu));
pollfds_size = PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds);
pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollfd));
_PR_IOQ_POLLFDS(me->cpu) = pollfds;
_PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size;
- pollfdPtr = pollfds;
} else {
pollfds = _PR_IOQ_POLLFDS(me->cpu);
- pollfdPtr = pollfds;
}
+ pollfdPtr = pollfds;
/*
* If we need to poll the pipe for waking up a native thread,
* the pipe's fd is the first element in the pollfds array.
*/
if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
pollfdPtr->fd = _pr_md_pipefd[0];
pollfdPtr->events = POLLIN;
@@ -2517,17 +2516,22 @@ static PRIntn _MD_solaris25_stat64(const
return rv;
} /* _MD_solaris25_stat64 */
#endif /* defined(SOLARIS2_5) */
#if defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5)
static PRIntn _MD_Unix_lockf64(PRIntn osfd, PRIntn function, PRInt64 size)
{
-#if defined(RHAPSODY) || defined(BSDI)
+#if defined(HAVE_BSD_FLOCK)
+ /*
+ * XXX: HAVE_BSD_FLOCK is not really the appropriate macro
+ * to test for here. We are trying to identify the platforms
+ * that don't have lockf, e.g., BSD/OS, FreeBSD, and Rhapsody.
+ */
/* No lockf */
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
return -1;
#else
PRInt64 desired, maxoff;
PRInt32 current = lseek(osfd, SEEK_CUR, 0);
LL_I2L(maxoff, 0x7fffffff);
--- a/pr/src/md/unix/unix_errors.c
+++ b/pr/src/md/unix/unix_errors.c
@@ -13,17 +13,17 @@
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "primpl.h"
#if defined(_PR_POLL_AVAILABLE)
-#include <sys/poll.h>
+#include <poll.h>
#endif
#include <errno.h>
void _MD_unix_map_opendir_error(int err)
{
switch (err) {
case ENOTDIR:
PR_SetError(PR_NOT_DIRECTORY_ERROR, err);
--- a/pr/src/md/unix/uxpoll.c
+++ b/pr/src/md/unix/uxpoll.c
@@ -20,17 +20,17 @@
#else /* defined(_PR_PTHREADS) */
#include "primpl.h"
#include <sys/time.h>
#include <fcntl.h>
#ifdef _PR_USE_POLL
-#include <sys/poll.h>
+#include <poll.h>
#endif
#if defined(_PR_USE_POLL)
static PRInt32 NativeThreadPoll(
PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
{
/*
* This function is mostly duplicated from ptio.s's PR_Poll().
--- a/pr/src/md/unix/uxwrap.c
+++ b/pr/src/md/unix/uxwrap.c
@@ -298,17 +298,17 @@ int select(int width, fd_set *rd, fd_set
* -1: fails, errno indicates the error.
* 0: timed out, the revents bitmasks are not set.
* positive value: the number of file descriptors for which poll()
* has set the revents bitmask.
*
*-----------------------------------------------------------------------
*/
-#include <sys/poll.h>
+#include <poll.h>
#if defined(AIX4_1)
int wrap_poll(void *listptr, unsigned long nfds, long timeout)
#elif (defined(AIX) && !defined(AIX4_1))
int poll(void *listptr, unsigned long nfds, long timeout)
#elif defined(OSF1) || (defined(HPUX) && !defined(HPUX9))
int poll(struct pollfd filedes[], unsigned int nfds, int timeout)
#elif defined(HPUX9)
--- a/pr/src/md/windows/ntdllmn.c
+++ b/pr/src/md/windows/ntdllmn.c
@@ -51,17 +51,19 @@ PRThread *me;
_pr_use_static_tls = FALSE;
} else {
_pr_use_static_tls = TRUE;
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
- me = _MD_GET_ATTACHED_THREAD();
- if ((me != NULL) && (me->flags & _PR_ATTACHED))
- _PRI_DetachThread();
+ if (_pr_initialized) {
+ me = _MD_GET_ATTACHED_THREAD();
+ if ((me != NULL) && (me->flags & _PR_ATTACHED))
+ _PRI_DetachThread();
+ }
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
--- a/pr/src/md/windows/ntio.c
+++ b/pr/src/md/windows/ntio.c
@@ -2096,18 +2096,17 @@ PRInt32
* assume that 0, 1, and 2 are console, because if someone closes
* System.out and then opens a file, they might get file descriptor
* 1. An error on *that* version of 1 should be reported, whereas
* an error on System.out (which was the original 1) should be
* ignored. So I use isatty() to ensure that such an error was
* because of this, and if it was, I ignore the error.
*/
- long handle = _get_osfhandle(fd->secret->md.osfd);
- BOOL ok = FlushFileBuffers((HANDLE)handle);
+ BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);
if (!ok) {
DWORD err = GetLastError();
if (err != ERROR_ACCESS_DENIED) { /* from winerror.h */
_PR_MD_MAP_FSYNC_ERROR(err);
return -1;
}
--- a/pr/src/md/windows/w95dllmain.c
+++ b/pr/src/md/windows/w95dllmain.c
@@ -34,17 +34,19 @@ BOOL WINAPI DllMain(
PRThread *me;
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
- me = _MD_GET_ATTACHED_THREAD();
- if ((me != NULL) && (me->flags & _PR_ATTACHED))
- _PRI_DetachThread();
+ if (_pr_initialized) {
+ me = _MD_GET_ATTACHED_THREAD();
+ if ((me != NULL) && (me->flags & _PR_ATTACHED))
+ _PRI_DetachThread();
+ }
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
--- a/pr/src/md/windows/w95io.c
+++ b/pr/src/md/windows/w95io.c
@@ -277,18 +277,17 @@ PRInt32
* assume that 0, 1, and 2 are console, because if someone closes
* System.out and then opens a file, they might get file descriptor
* 1. An error on *that* version of 1 should be reported, whereas
* an error on System.out (which was the original 1) should be
* ignored. So I use isatty() to ensure that such an error was due
* to this bogosity, and if it was, I ignore the error.
*/
- long handle = _get_osfhandle(fd->secret->md.osfd);
- BOOL ok = FlushFileBuffers((HANDLE)handle);
+ BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);
if (!ok) {
DWORD err = GetLastError();
if (err != ERROR_ACCESS_DENIED) { // from winerror.h
_PR_MD_MAP_FSYNC_ERROR(err);
return -1;
}
}
--- a/pr/src/misc/prinit.c
+++ b/pr/src/misc/prinit.c
@@ -350,16 +350,17 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup()
/*
* XXX: We are freeing the heap memory here so that Purify won't
* complain, but we should also free other kinds of resources
* that are allocated by the _PR_InitXXX() functions.
* Ideally, for each _PR_InitXXX(), there should be a corresponding
* _PR_XXXCleanup() that we can call here.
*/
_PR_CleanupBeforeExit();
+ _pr_initialized = PR_FALSE;
return PR_SUCCESS;
}
return PR_FAILURE;
}
#endif /* defined(_PR_PTHREADS) */
/*
*------------------------------------------------------------------------
--- a/pr/src/misc/prsystem.c
+++ b/pr/src/misc/prsystem.c
@@ -20,19 +20,34 @@
#include "prsystem.h"
#include "prprf.h"
#if defined(XP_UNIX)
#include <unistd.h>
#include <sys/utsname.h>
#endif
+PR_IMPLEMENT(char) PR_GetDirectorySeparator()
+{
+ return PR_DIRECTORY_SEPARATOR;
+} /* PR_GetDirectorySeparator */
+
+/*
+** OBSOLETE -- the function name is misspelled.
+*/
PR_IMPLEMENT(char) PR_GetDirectorySepartor()
{
- return PR_DIRECTORY_SEPARATOR;
+#if defined(DEBUG)
+ static PRBool warn = PR_TRUE;
+ if (warn) {
+ warn = _PR_Obsolete("PR_GetDirectorySepartor()",
+ "PR_GetDirectorySeparator()");
+ }
+#endif
+ return PR_GetDirectorySeparator();
} /* PR_GetDirectorySepartor */
PR_IMPLEMENT(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen)
{
PRUintn len = 0;
if (!_pr_initialized) _PR_ImplicitInitialization();
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -744,17 +744,20 @@ recycle:
PR_SetThreadPriority(pt_tq.thread, priority); /* reset back to caller's */
PR_ASSERT((NULL == pt_tq.head) == (0 == pt_tq.op_count));
PR_ASSERT((NULL == pt_tq.head) == (NULL == pt_tq.tail));
PR_ASSERT(pt_continuation_done == my_op->status);
if (NULL != pt_tq.tail)
{
- pt_tq.tail->status = pt_continuation_recycle;
+ if (pt_tq.tail->status != pt_continuation_abort)
+ {
+ pt_tq.tail->status = pt_continuation_recycle;
+ }
PR_NotifyCondVar(pt_tq.tail->complete);
#if defined(DEBUG)
pt_debug.recyclesNeeded += 1;
#endif
}
#if defined(DEBUG)
else pt_debug.quiescentIO += 1;
#endif
@@ -784,17 +787,17 @@ static PRIntn pt_Continue(pt_Continuatio
if (NULL == pt_tq.thread)
{
/*
** We're the one. Call the processing function with the lock
** held. It will return with it held as well, though there
** will certainly be times within the function when it gets
** released.
*/
- pt_tq.thread = PR_GetCurrentThread(); /* I'm taking control */
+ pt_tq.thread = self; /* I'm taking control */
pt_ContinuationThreadInternal(op); /* go slash and burn */
PR_ASSERT(pt_continuation_done == op->status);
pt_tq.thread = NULL; /* I'm abdicating my rule */
}
else
{
rv = PR_WaitCondVar(op->complete, PR_INTERVAL_NO_TIMEOUT);
/*
@@ -804,25 +807,46 @@ static PRIntn pt_Continue(pt_Continuatio
* from the list is still valid.
*
* Don't call interrupt on the continuation thread. That'll just
* irritate him. He's cycling around at least every mx_poll_ticks
* anyhow and should notice the request in there. When he does
* notice, this operation will be finished and the op's status
* marked as pt_continuation_done.
*/
- if ((PR_FAILURE == rv) /* the wait failed */
- && (pt_continuation_pending == op->status) /* but the op hasn't */
- && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) /* was interrupted */
+ if ((PR_FAILURE == rv) /* the wait was interrupted */
+ && (PR_PENDING_INTERRUPT_ERROR == PR_GetError()))
{
- op->status = pt_continuation_abort; /* go around the loop again */
+ if (pt_continuation_done == op->status)
+ {
+ /*
+ * The op is done and has been removed
+ * from the timed queue. We must not
+ * change op->status, otherwise this
+ * thread will go around the loop again.
+ *
+ * It's harsh to mark the op failed with
+ * interrupt error when the io is already
+ * done, but we should indicate the fact
+ * that the thread was interrupted. So
+ * we set the aborted flag to abort the
+ * thread's next blocking call. Is this
+ * the right thing to do?
+ */
+ self->state |= PT_THREAD_ABORTED;
+ }
+ else
+ {
+ /* go around the loop again */
+ op->status = pt_continuation_abort;
+ }
}
/*
* If we're to recycle, continue within this loop. This will
- * cause this thread to be come the continuation thread.
+ * cause this thread to become the continuation thread.
*/
}
} while (pt_continuation_done != op->status);
PR_Unlock(pt_tq.ml); /* we provided the locking */
--- a/pr/src/pthreads/ptthread.c
+++ b/pr/src/pthreads/ptthread.c
@@ -194,34 +194,25 @@ static PRThread* pt_AttachThread(void)
PRThread *thred = NULL;
void *privateData = NULL;
/*
* NSPR must have been initialized when PR_AttachThread is called.
* We cannot have PR_AttachThread call implicit initialization
* because if multiple threads call PR_AttachThread simultaneously,
* NSPR may be initialized more than once.
- * We can't call PR_SetError() either.
+ * We can't call any function that calls PR_GetCurrentThread()
+ * either (e.g., PR_SetError()) as that will result in infinite
+ * recursion.
*/
if (!_pr_initialized) return NULL;
- /*
- * If the thread is already known, it will have a non-NULL value
- * in its private data. If that's the case, simply suppress the
- * attach and note an error.
- */
- PTHREAD_GETSPECIFIC(pt_book.key, privateData);
- if (NULL != privateData)
- {
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
- return NULL;
- }
+ /* PR_NEWZAP must not call PR_GetCurrentThread() */
thred = PR_NEWZAP(PRThread);
- if (NULL == thred) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
- else
+ if (NULL != thred)
{
int rv;
thred->priority = PR_PRIORITY_NORMAL;
thred->id = pthread_self();
rv = pthread_setspecific(pt_book.key, thred);
PR_ASSERT(0 == rv);
@@ -712,16 +703,27 @@ PR_IMPLEMENT(PRStatus) PR_Sleep(PRInterv
PR_DestroyCondVar(cv);
}
return rv;
} /* PR_Sleep */
static void _pt_thread_death(void *arg)
{
PRThread *thred = (PRThread*)arg;
+
+ if (thred->state & PT_THREAD_FOREIGN)
+ {
+ PR_Lock(pt_book.ml);
+ thred->prev->next = thred->next;
+ if (NULL == thred->next)
+ pt_book.last = thred->prev;
+ else
+ thred->next->prev = thred->prev;
+ PR_Unlock(pt_book.ml);
+ }
_PR_DestroyThreadPrivate(thred);
if (NULL != thred->errorString)
PR_Free(thred->errorString);
if (NULL != thred->io_cv)
PR_DestroyCondVar(thred->io_cv);
PR_Free(thred->stack);
#if defined(DEBUG)
memset(thred, 0xaf, sizeof(PRThread));
@@ -830,16 +832,17 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup()
* problem.
*/
if (0 == pt_book.system)
{
PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
}
_pt_thread_death(me);
+ _pr_initialized = PR_FALSE;
return PR_SUCCESS;
}
return PR_FAILURE;
} /* PR_Cleanup */
PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
{
_exit(status);
--- a/pr/tests/Makefile
+++ b/pr/tests/Makefile
@@ -32,17 +32,16 @@ else
DIRS = dll
endif
ifeq ($(OS_TARGET),OS2)
OS_CFLAGS = $(OS_EXE_CFLAGS)
endif
CSRCS = \
- acceptread.c \
accept.c \
alarm.c \
atomic.c \
attach.c \
bigfile.c \
cleanup.c \
cltsrv.c \
concur.c \
@@ -58,16 +57,17 @@ CSRCS = \
fsync.c \
getproto.c \
i2l.c \
initclk.c \
inrval.c \
instrumt.c \
intrupt.c \
io_timeout.c \
+ ioconthr.c \
ipv6.c \
join.c \
joinkk.c \
joinku.c \
joinuk.c \
joinuu.c \
layer.c \
lazyinit.c \
--- a/pr/tests/accept.c
+++ b/pr/tests/accept.c
@@ -43,30 +43,32 @@
#include "prpriv.h"
#include <stdlib.h>
#include <string.h>
#include "plgetopt.h"
#include "plerror.h"
-#define BASE_PORT 8001
+#define BASE_PORT 10000
#define CLIENT_DATA 128
#define ACCEPT_NORMAL 0x1
#define ACCEPT_FAST 0x2
#define ACCEPT_READ 0x3
#define ACCEPT_READ_FAST 0x4
#define ACCEPT_READ_FAST_CB 0x5
#define CLIENT_NORMAL 0x1
#define CLIENT_TIMEOUT_ACCEPT 0x2
#define CLIENT_TIMEOUT_SEND 0x3
+#define SERVER_MAX_BIND_COUNT 100
+
#if defined(XP_MAC) || defined(XP_OS2)
#define TIMEOUTSECS 10
#else
#define TIMEOUTSECS 2
#endif
PRIntervalTime timeoutTime;
static PRInt32 count = 1;
@@ -180,36 +182,48 @@ static PRThread *clientThread;
static PRNetAddr *raddr;
static char buf[4096 + 64];
static PRInt32 status;
static PRInt32 bytesRead;
static void
RunTest(PRInt32 acceptType, PRInt32 clientAction)
{
+int i;
/* First bind to the socket */
listenSock = PR_NewTCPSocket();
if (!listenSock) {
failed_already=1;
if (debug_mode)
PR_fprintf(output, "unable to create listen socket\n");
return;
}
+ memset(&listenAddr, 0 , sizeof(listenAddr));
listenAddr.inet.family = PR_AF_INET;
listenAddr.inet.port = PR_htons(BASE_PORT);
listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
- rv = PR_Bind(listenSock, &listenAddr);
- if (rv == PR_FAILURE) {
+ /*
+ * try a few times to bind server's address, if addresses are in
+ * use
+ */
+ i = 0;
+ while (PR_Bind(listenSock, &listenAddr) == PR_FAILURE) {
+ if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+ listenAddr.inet.port += 2;
+ if (i++ < SERVER_MAX_BIND_COUNT)
+ continue;
+ }
failed_already=1;
if (debug_mode)
- PR_fprintf(output, "unable to bind\n");
- return;
+ PR_fprintf(output,"accept: ERROR - PR_Bind failed\n");
+ return;
}
+
rv = PR_Listen(listenSock, 100);
if (rv == PR_FAILURE) {
failed_already=1;
if (debug_mode)
PR_fprintf(output, "unable to listen\n");
return;
}
@@ -303,17 +317,17 @@ RunTest(PRInt32 acceptType, PRInt32 clie
/* Invalid test case */
TEST_ASSERT(0);
break;
case CLIENT_NORMAL:
TEST_ASSERT(clientSock);
TEST_ASSERT(status == CLIENT_DATA);
break;
case CLIENT_TIMEOUT_SEND:
- TEST_ASSERT(clientSock);
+ TEST_ASSERT(clientSock == NULL);
TEST_ASSERT(status == -1);
TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
break;
}
break;
case ACCEPT_READ_FAST_CB:
status = PR_NTFast_AcceptRead_WithTimeoutCallback(
listenSock, &clientSock, &raddr, buf, 4096,
@@ -325,17 +339,17 @@ RunTest(PRInt32 acceptType, PRInt32 clie
break;
case CLIENT_NORMAL:
TEST_ASSERT(clientSock);
TEST_ASSERT(status == CLIENT_DATA);
break;
case CLIENT_TIMEOUT_SEND:
if (debug_mode)
PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock);
- TEST_ASSERT(clientSock);
+ TEST_ASSERT(clientSock == NULL);
TEST_ASSERT(status == -1);
TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
break;
}
break;
#endif
}
if (clientSock != NULL) {
--- a/pr/tests/bigfile.c
+++ b/pr/tests/bigfile.c
@@ -160,17 +160,17 @@ PRIntn main(PRIntn argc, char **argv)
}
PL_DestroyOptState(opt);
if (0 == count) count = DEFAULT_COUNT;
if (0 == filesize) filesize = DEFAULT_FILESIZE;
if (NULL == filename)
{
if (DEFAULT_FILESIZE != filesize) return Usage();
- else filename = "/usr/tmp/bigfile.dat";
+ else filename = "bigfile.dat";
}
if (PR_FAILURE == DeleteIfFound(filename)) return 1;
test_result = 0;
LL_I2L(zero_meg, 0);
LL_I2L(one_meg, 1000000);
--- a/pr/tests/cltsrv.c
+++ b/pr/tests/cltsrv.c
@@ -508,19 +508,20 @@ static PRStatus ProcessRequest(PRFileDes
TEST_ASSERT(bytes > 0);
}
PR_Lock(server->ml);
server->operations += 1;
server->bytesTransferred += filebytes;
PR_Unlock(server->ml);
- rv = PR_Close(file); file = NULL;
+ rv = PR_Close(file);
if (Aborted(rv)) goto aborted;
TEST_ASSERT(PR_SUCCESS == rv);
+ file = NULL;
TEST_LOG(
cltsrv_log_file, TEST_LOG_VERBOSE,
("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
file = PR_Open(descriptor->filename, PR_RDONLY, 0);
if (NULL == file)
{
rv = PR_FAILURE;
@@ -591,19 +592,20 @@ static PRStatus ProcessRequest(PRFileDes
PR_Lock(server->ml);
server->bytesTransferred += filebytes;
PR_Unlock(server->ml);
rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
if (Aborted(rv)) goto aborted;
- rv = PR_Close(file); file = NULL;
+ rv = PR_Close(file);
if (Aborted(rv)) goto aborted;
TEST_ASSERT(PR_SUCCESS == rv);
+ file = NULL;
aborted:
PR_ClearInterrupt();
if (NULL != file) PR_Close(file);
drv = PR_Delete(descriptor->filename);
TEST_ASSERT(PR_SUCCESS == drv);
exit:
TEST_LOG(
--- a/pr/tests/foreign.c
+++ b/pr/tests/foreign.c
@@ -207,64 +207,72 @@ static void PR_CALLBACK lazyEntry(void *
{
PR_ASSERT(NULL == arg);
} /* lazyEntry */
static void OneShot(void *arg)
{
PRUintn pdkey;
+ PRLock *lock;
+ PRFileDesc *fd;
+ PRDir *dir;
PRFileDesc *pair[2];
PRIntn test = (PRIntn)arg;
for (test = 0; test < 11; ++test) {
switch (test)
{
case 0:
- (void)PR_NewLock();
+ lock = PR_NewLock();
DPRINTF((output,"Thread[0x%x] called PR_NewLock\n",
PR_GetCurrentThread()));
+ PR_DestroyLock(lock);
break;
case 1:
(void)PR_SecondsToInterval(1);
DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n",
PR_GetCurrentThread()));
break;
case 2: (void)PR_CreateThread(
PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL,
PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n",
PR_GetCurrentThread()));
break;
case 3:
- (void)PR_Open("/usr/tmp/", PR_RDONLY, 0);
+ fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666);
DPRINTF((output,"Thread[0x%x] called PR_Open\n",
PR_GetCurrentThread()));
+ PR_Close(fd);
break;
case 4:
- (void)PR_NewUDPSocket();
+ fd = PR_NewUDPSocket();
DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n",
PR_GetCurrentThread()));
+ PR_Close(fd);
break;
case 5:
- (void)PR_NewTCPSocket();
+ fd = PR_NewTCPSocket();
DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n",
PR_GetCurrentThread()));
+ PR_Close(fd);
break;
case 6:
- (void)PR_OpenDir("/usr/tmp/");
+ dir = PR_OpenDir("/usr/tmp/");
DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n",
PR_GetCurrentThread()));
+ PR_CloseDir(dir);
break;
case 7:
(void)PR_NewThreadPrivateIndex(&pdkey, NULL);
DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n",
PR_GetCurrentThread()));
break;
@@ -273,16 +281,18 @@ static void OneShot(void *arg)
DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n",
PR_GetCurrentThread()));
break;
case 9:
(void)PR_NewTCPSocketPair(pair);
DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n",
PR_GetCurrentThread()));
+ PR_Close(pair[0]);
+ PR_Close(pair[1]);
break;
case 10:
PR_SetConcurrency(2);
DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n",
PR_GetCurrentThread()));
break;
--- a/pr/tests/fsync.c
+++ b/pr/tests/fsync.c
@@ -37,17 +37,17 @@ static void Help(void)
} /* Help */
PRIntn main(PRIntn argc, char **argv)
{
PRStatus rv;
PLOptStatus os;
PRUint8 *buffer;
PRFileDesc *file = NULL;
- const char *filename = "/usr/tmp/sync.dat";
+ const char *filename = "sync.dat";
PRUint32 index, loops, iterations = 10, filesize = 10;
PRIntn flags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
PLOptState *opt = PL_CreateOptState(argc, argv, "hSK:c:");
PRIntervalTime time, total = 0, shortest = 0x7fffffff, longest = 0;
err = PR_GetSpecialFD(PR_StandardError);
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
--- a/pr/tests/instrumt.c
+++ b/pr/tests/instrumt.c
@@ -329,17 +329,16 @@ static void TraceTest( void )
PRThread *t1, *t2;
PR_LOG( lm, msgLevel,
("Begin TraceTest"));
size = SMALL_TRACE_BUFSIZE;
PR_SET_TRACE_OPTION( PRTraceBufSize, &size );
PR_GET_TRACE_OPTION( PRTraceBufSize, &i );
- PR_ASSERT( i == size );
PR_CREATE_TRACE( th, "TraceTest", "tt2", "A description for the trace test" );
PR_CREATE_TRACE( th, "TraceTest", "tt3", "A description for the trace test" );
PR_CREATE_TRACE( th, "TraceTest", "tt4", "A description for the trace test" );
PR_CREATE_TRACE( th, "TraceTest", "tt5", "A description for the trace test" );
PR_CREATE_TRACE( th, "TraceTest", "tt6", "A description for the trace test" );
PR_CREATE_TRACE( th, "TraceTest", "tt7", "A description for the trace test" );
PR_CREATE_TRACE( th, "TraceTest", "tt8", "A description for the trace test" );
new file mode 100644
--- /dev/null
+++ b/pr/tests/ioconthr.c
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * This is a test for the io continuation thread machinery
+ * in pthreads.
+ */
+
+#include "nspr.h"
+#include <stdio.h>
+
+int num_threads = 10; /* must be an even number */
+PRThreadScope thread_scope = PR_GLOBAL_THREAD;
+
+void ThreadFunc(void *arg)
+{
+ PRFileDesc *fd = (PRFileDesc *) arg;
+ char buf[1024];
+ PRInt32 nbytes;
+ PRErrorCode err;
+
+ nbytes = PR_Recv(fd, buf, sizeof(buf), 0, PR_SecondsToInterval(20));
+ if (nbytes == -1) {
+ err = PR_GetError();
+ if (err != PR_PENDING_INTERRUPT_ERROR) {
+ fprintf(stderr, "PR_Recv failed: (%d, %d)\n",
+ err, PR_GetOSError());
+ PR_ProcessExit(1);
+ }
+ if (PR_Close(fd) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ PR_ProcessExit(1);
+ }
+ } else {
+ fprintf(stderr, "PR_Recv received %d bytes!?\n", nbytes);
+ PR_ProcessExit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc **fds;
+ PRThread **threads;
+ PRIntervalTime start, elapsed;
+ int index;
+
+ fds = (PRFileDesc **) PR_MALLOC(num_threads * sizeof(PRFileDesc *));
+ PR_ASSERT(fds != NULL);
+ threads = (PRThread **) PR_MALLOC(num_threads * sizeof(PRThread *));
+ PR_ASSERT(threads != NULL);
+
+ for (index = 0; index < (num_threads / 2); index++) {
+ if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ PR_ProcessExit(1);
+ }
+
+ threads[2 * index] = PR_CreateThread(
+ PR_USER_THREAD, ThreadFunc, fds[2 * index],
+ PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == threads[2 * index]) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ PR_ProcessExit(1);
+ }
+ threads[2 * index + 1] = PR_CreateThread(
+ PR_USER_THREAD, ThreadFunc, fds[2 * index + 1],
+ PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == threads[2 * index + 1]) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ PR_ProcessExit(1);
+ }
+ }
+
+ /* Let the threads block in PR_Recv */
+ PR_Sleep(PR_SecondsToInterval(2));
+
+ printf("Interrupting the threads\n");
+ fflush(stdout);
+ start = PR_IntervalNow();
+ for (index = 0; index < num_threads; index++) {
+ if (PR_Interrupt(threads[index]) == PR_FAILURE) {
+ fprintf(stderr, "PR_Interrupt failed\n");
+ PR_ProcessExit(1);
+ }
+ }
+ for (index = 0; index < num_threads; index++) {
+ if (PR_JoinThread(threads[index]) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ PR_ProcessExit(1);
+ }
+ }
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
+ printf("Threads terminated in %d milliseconds\n",
+ PR_IntervalToMilliseconds(elapsed));
+ fflush(stdout);
+
+ /* We are being very generous and allow 10 seconds. */
+ if (elapsed >= PR_SecondsToInterval(10)) {
+ fprintf(stderr, "Interrupting threads took longer than 10 seconds!!\n");
+ PR_ProcessExit(1);
+ }
+
+ PR_DELETE(threads);
+ PR_DELETE(fds);
+ printf("PASS\n");
+ PR_Cleanup();
+ return 0;
+}
--- a/pr/tests/layer.c
+++ b/pr/tests/layer.c
@@ -79,16 +79,19 @@ static PRFileDesc *PopLayer(PRFileDesc *
static void PR_CALLBACK Client(void *arg)
{
PRStatus rv;
PRUint8 buffer[100];
PRIntn empty_flags = 0;
PRIntn bytes_read, bytes_sent;
PRFileDesc *stack = (PRFileDesc*)arg;
+ /* Initialize the buffer so that Purify won't complain */
+ memset(buffer, 0, sizeof(buffer));
+
rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
PR_ASSERT(PR_SUCCESS == rv);
while (minor_iterations-- > 0)
{
bytes_sent = PR_Send(
stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
PR_ASSERT(sizeof(buffer) == bytes_sent);
if (verbosity > chatty)
@@ -152,17 +155,17 @@ static void PR_CALLBACK Server(void *arg
} /* Server */
static PRInt32 PR_CALLBACK MyRecv(
PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, PRIntervalTime timeout)
{
char *b = (char*)buf;
PRFileDesc *lo = fd->lower;
- PRInt32 rv, readin = 0, request;
+ PRInt32 rv, readin = 0, request = 0;
rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout);
if (verbosity > chatty) PR_fprintf(
logFile, "MyRecv sending permission for %d bytes\n", request);
if (0 < rv)
{
if (verbosity > chatty) PR_fprintf(
logFile, "MyRecv received permission request for %d bytes\n", request);
rv = lo->methods->send(
--- a/pr/tests/multiwait.c
+++ b/pr/tests/multiwait.c
@@ -151,16 +151,19 @@ static void PR_CALLBACK ClientThread(voi
PRFileDesc *server = PR_NewTCPSocket();
if ((NULL == server)
&& (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) return;
MW_ASSERT(NULL != server);
if (verbosity > chatty)
PR_fprintf(debug, "%s: Server socket @0x%x\n", shared->title, server);
+ /* Initialize the buffer so that Purify won't complain */
+ memset(buffer, 0, sizeof(buffer));
+
rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address);
MW_ASSERT(PR_SUCCESS == rv);
if (verbosity > quiet)
PR_fprintf(debug, "%s: Client opening connection\n", shared->title);
rv = PR_Connect(server, &server_address, PR_INTERVAL_NO_TIMEOUT);
if (PR_FAILURE == rv)
@@ -254,18 +257,16 @@ static void OneOpOneThread(Shared *share
static void ManyOpOneThread(Shared *shared)
{
PRStatus rv;
PRIntn index;
PRRecvWait *desc_in;
PRRecvWait *desc_out;
- desc_in = (PRRecvWait*)PR_CALLOC(sizeof(PRRecvWait*) * wait_objects);
-
if (verbosity > quiet)
PR_fprintf(debug, "%s: adding %d descs\n", shared->title, wait_objects);
for (index = 0; index < wait_objects; ++index)
{
desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout);
rv = PR_AddWaitFileDesc(shared->group, desc_in);
@@ -599,16 +600,17 @@ static void RealOneGroupIO(Shared *share
PR_fprintf(debug, "%s: interrupting/joining client_threads\n", shared->title);
for (index = 0; index < client_threads; ++index)
{
rv = PR_Interrupt(client_thread[index]);
MW_ASSERT(PR_SUCCESS == rv);
rv = PR_JoinThread(client_thread[index]);
MW_ASSERT(PR_SUCCESS == rv);
}
+ PR_DELETE(client_thread);
if (verbosity > quiet)
PR_fprintf(debug, "%s: interrupting/joining enumeration_thread\n", shared->title);
rv = PR_Interrupt(enumeration_thread);
MW_ASSERT(PR_SUCCESS == rv);
rv = PR_JoinThread(enumeration_thread);
MW_ASSERT(PR_SUCCESS == rv);
--- a/pr/tests/nbconn.c
+++ b/pr/tests/nbconn.c
@@ -45,16 +45,17 @@
#define printf PR_LogPrint
extern void SetupMacPrintfLog(char *logFile);
static char *hosts[4] = {"cynic", "warp", "gandalf", "neon"};
#endif
#define SERVER_MAX_BIND_COUNT 100
#define DATA_BUF_SIZE 256
#define TCP_SERVER_PORT 10000
+#define TCP_UNUSED_PORT 211
typedef struct Server_Param {
PRFileDesc *sp_fd; /* server port */
} Server_Param;
static void PR_CALLBACK TCP_Server(void *arg);
int _debug_on;
#define DPRINTF(arg) if (_debug_on) printf arg
@@ -65,17 +66,17 @@ static PRIntn connection_failure_test();
int main(int argc, char **argv)
{
PRHostEnt he;
char buf[1024];
PRNetAddr addr;
PRPollDesc pd;
PRStatus rv;
PRSocketOptionData optData;
- const char *hostname;
+ const char *hostname = NULL;
PRIntn default_case, n, bytes_read, bytes_sent;
PRInt32 failed_already = 0;
#ifdef XP_MAC
int index;
PRIntervalTime timeout;
#endif
/*
@@ -274,17 +275,17 @@ connection_success_test()
PRNetAddr netaddr;
PRInt32 i, rv;
PRPollDesc pd;
PRSocketOptionData optData;
PRThread *thr = NULL;
Server_Param sp;
char send_buf[DATA_BUF_SIZE], recv_buf[DATA_BUF_SIZE];
PRIntn default_case, n, bytes_read, bytes_sent;
- PRIntn failed_already;
+ PRIntn failed_already = 0;
/*
* Create a tcp socket
*/
if ((sockfd = PR_NewTCPSocket()) == NULL) {
fprintf(stderr,"Error - PR_NewTCPSocket failed\n");
failed_already=1;
goto def_exit;
@@ -336,21 +337,16 @@ connection_success_test()
if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
DPRINTF(("Connect in progress\n"));
} else {
fprintf(stderr,"Error - PR_Connect failed: (%d, %d)\n",
PR_GetError(), PR_GetOSError());
failed_already=1;
goto def_exit;
}
- } else {
- PR_ASSERT(rv == PR_SUCCESS);
- fprintf(stderr,"Error - PR_Connect succeeded, expected to fail\n");
- failed_already=1;
- goto def_exit;
}
/*
* Now create a thread to accept a connection
*/
sp.sp_fd = sockfd;
thr = PR_CreateThread(PR_USER_THREAD, TCP_Server, (void *)&sp,
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
if (thr == NULL) {
@@ -368,22 +364,16 @@ connection_success_test()
n = PR_Poll(&pd, 1, timeout);
#endif
if (n == -1) {
fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n",
PR_GetError(), PR_GetOSError());
failed_already=1;
goto def_exit;
}
- if (pd.out_flags != PR_POLL_WRITE) {
- fprintf(stderr,"Error - PR_Poll returned invalid outflags: 0x%x\n",
- pd.out_flags);
- failed_already=1;
- goto def_exit;
- }
if (PR_GetConnectStatus(&pd) == PR_SUCCESS) {
PRInt32 rv;
DPRINTF(("Connection successful\n"));
/*
* Write some data, read it back and check data integrity to
* make sure the connection is good
@@ -515,16 +505,22 @@ connection_failure_test()
}
if (PR_GetSockName(sockfd, &netaddr) < 0) {
fprintf(stderr,"ERROR - PR_GetSockName failed: (%d,%d)\n",
PR_GetError(), PR_GetOSError());
failed_already=1;
goto def_exit;
}
+#ifdef AIX
+ /*
+ * On AIX, set to unused/reserved port
+ */
+ netaddr.inet.port = PR_htons(TCP_UNUSED_PORT);
+#endif
if ((conn_fd = PR_NewTCPSocket()) == NULL) {
fprintf(stderr,"Error - PR_NewTCPSocket failed\n");
failed_already=1;
goto def_exit;
}
optData.option = PR_SockOpt_Nonblocking;
optData.value.non_blocking = PR_TRUE;
PR_SetSocketOption(conn_fd, &optData);
@@ -546,22 +542,16 @@ connection_failure_test()
n = PR_Poll(&pd, 1, timeout);
#endif
if (n == -1) {
fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n",
PR_GetError(), PR_GetOSError());
failed_already=1;
goto def_exit;
}
- if (pd.out_flags != PR_POLL_WRITE) {
- fprintf(stderr,"Error - PR_Poll returned invalid outflags: 0x%x\n",
- pd.out_flags);
- failed_already=1;
- goto def_exit;
- }
if (PR_GetConnectStatus(&pd) == PR_SUCCESS) {
PRInt32 rv;
fprintf(stderr,"PR_GetConnectStatus succeeded, expected to fail\n");
failed_already = 1;
goto def_exit;
}
rv = PR_GetError();
DPRINTF(("Connection failed, successfully with PR_Error %d\n",rv));
--- a/pr/tests/nblayer.c
+++ b/pr/tests/nblayer.c
@@ -95,16 +95,19 @@ static void PR_CALLBACK Client(void *arg
PRIntn mits;
PRInt32 ready;
PRUint8 buffer[100];
PRPollDesc polldesc;
PRIntn empty_flags = 0;
PRIntn bytes_read, bytes_sent;
PRFileDesc *stack = (PRFileDesc*)arg;
+ /* Initialize the buffer so that Purify won't complain */
+ memset(buffer, 0, sizeof(buffer));
+
rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError()))
{
if (verbosity > quiet)
PR_fprintf(logFile, "Client connect 'in progress'\n");
do
{
polldesc.fd = stack;
@@ -294,19 +297,18 @@ static void PR_CALLBACK Server(void *arg
} while (bytes_sent < bytes_read);
PR_ASSERT(bytes_read == bytes_sent);
if (verbosity > chatty)
PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent);
}
} while (0 != bytes_read);
if (verbosity > quiet)
- PR_fprintf(logFile, "Server shutting down and closing stack\n");
+ PR_fprintf(logFile, "Server shutting down stack\n");
rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
- rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
} /* Server */
static PRStatus PR_CALLBACK MyClose(PRFileDesc *fd)
{
PR_DELETE(fd->secret); /* manage my secret file object */
return (PR_GetDefaultIOMethods())->close(fd); /* let him do all the work */
} /* MyClose */
@@ -625,9 +627,9 @@ PRIntn main(PRIntn argc, char **argv)
rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv);
rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv);
if (verbosity > silent)
PR_fprintf(logFile, "Ending layered test\n");
}
return 0;
} /* main */
-/* layer.c */
+/* nblayer.c */
--- a/pr/tests/nonblock.c
+++ b/pr/tests/nonblock.c
@@ -69,16 +69,19 @@ clientThreadFunc(void *arg)
PRNetAddr addr;
char buf[CHUNK_SIZE];
int i;
PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
PRIntn optval = 1;
PRStatus retVal;
PRInt32 nBytes;
+ /* Initialize the buffer so that Purify won't complain */
+ memset(buf, 0, sizeof(buf));
+
addr.inet.family = PR_AF_INET;
addr.inet.port = PR_htons((PRUint16)port);
addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip);
/* time 1 */
PR_Sleep(unitTime);
sock = PR_NewTCPSocket();
--- a/pr/tests/provider.c
+++ b/pr/tests/provider.c
@@ -76,17 +76,17 @@
/*
** This is the beginning of the test
*/
#define RECV_FLAGS 0
#define SEND_FLAGS 0
#define BUFFER_SIZE 1024
#define DEFAULT_BACKLOG 5
-#define DEFAULT_PORT 12848
+#define DEFAULT_PORT 13000
#define DEFAULT_CLIENTS 1
#define ALLOWED_IN_ACCEPT 1
#define DEFAULT_CLIPPING 1000
#define DEFAULT_WORKERS_MIN 1
#define DEFAULT_WORKERS_MAX 1
#define DEFAULT_SERVER "localhost"
#define DEFAULT_EXECUTION_TIME 10
#define DEFAULT_CLIENT_TIMEOUT 4000
@@ -701,17 +701,17 @@ static PRStatus NewThread(
switch (thread_provider)
{
case thread_nspr:
{
PRThread *thread = PR_CreateThread(
PR_USER_THREAD, start, arg,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
- PR_UNJOINABLE_THREAD, 0);
+ PR_JOINABLE_THREAD, 0);
rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
}
break;
case thread_pthread:
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
{
int rv;
pthread_t id;
@@ -1065,16 +1065,17 @@ static Verbosity IncrementVerbosity(void
PRIntn main(PRIntn argc, char** argv)
{
PRUintn index;
PRBool boolean;
CSClient_t *client;
PRStatus rv, joinStatus;
CSServer_t *server = NULL;
+ char *thread_type;
PRUintn backlog = DEFAULT_BACKLOG;
PRUintn clients = DEFAULT_CLIENTS;
const char *serverName = DEFAULT_SERVER;
PRBool serverIsLocal = PR_TRUE;
PRUintn accepting = ALLOWED_IN_ACCEPT;
PRUintn workersMin = DEFAULT_WORKERS_MIN;
PRUintn workersMax = DEFAULT_WORKERS_MAX;
@@ -1090,16 +1091,26 @@ PRIntn main(PRIntn argc, char** argv)
* -e <seconds> duration of the test in seconds
* -s <string> dsn name of server (implies no server here)
* -v verbosity
*/
PLOptStatus os;
PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:T:vdhp");
+#if defined(WIN32)
+ thread_provider = thread_win32;
+#elif defined(_PR_PTHREADS)
+ thread_provider = thread_pthread;
+#elif defined(IRIX)
+ thread_provider = thread_sproc;
+#else
+ thread_provider = thread_nspr;
+#endif
+
debug_out = PR_GetSpecialFD(PR_StandardError);
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
{
if (PL_OPT_BAD == os) continue;
switch (opt->option)
{
case 'G': /* use global threads */
@@ -1342,15 +1353,26 @@ PRIntn main(PRIntn argc, char** argv)
PR_DestroyLock(server->ml);
PR_DELETE(server);
}
TEST_LOG(
cltsrv_log_file, TEST_LOG_ALWAYS,
("main(0x%p): test complete\n", PR_CurrentThread()));
- PT_FPrintStats(debug_out, "\nPThread Statistics\n");
+ if (thread_provider == thread_win32)
+ thread_type = "\nWin32 Thread Statistics\n";
+ else if (thread_provider == thread_pthread)
+ thread_type = "\npthread Statistics\n";
+ else if (thread_provider == thread_sproc)
+ thread_type = "\nsproc Statistics\n";
+ else {
+ PR_ASSERT(thread_provider == thread_nspr);
+ thread_type = "\nPRThread Statistics\nn";
+ }
+
+ PT_FPrintStats(debug_out, thread_type);
TimeOfDayMessage("Test exiting at", PR_CurrentThread());
return 0;
} /* main */
/* cltsrv.c */
--- a/pr/tests/socket.c
+++ b/pr/tests/socket.c
@@ -53,17 +53,17 @@ extern void SetupMacPrintfLog(char *logF
#ifdef XP_PC
#define mode_t int
#endif
#define DPRINTF(arg) if (_debug_on) printf arg
#ifdef XP_PC
-char *TEST_DIR = "C:\\tmp\\prdir";
+char *TEST_DIR = "prdir";
char *SMALL_FILE_NAME = "prsmallf";
char *LARGE_FILE_NAME = "prlargef";
#else
char *TEST_DIR = "/tmp/prsocket_test_dir";
char *SMALL_FILE_NAME = "/tmp/prsocket_test_dir/small_file";
char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file";
#endif
#define SMALL_FILE_SIZE (8 * 1024) /* 8 KB */
--- a/pr/tests/sockopt.c
+++ b/pr/tests/sockopt.c
@@ -124,18 +124,20 @@ PRIntn main(PRIntn argc, char *argv)
break;
case PR_SockOpt_NoDelay: /* don't delay send to coalesce packets */
case PR_SockOpt_Keepalive: /* keep connections alive */
socket = tcp;
case PR_SockOpt_Reuseaddr: /* allow local address reuse */
value = &boolean;
size = &booleansize;
break;
+#ifndef WIN32
case PR_SockOpt_MaxSegment: /* maximum segment size */
socket = tcp;
+#endif
case PR_SockOpt_RecvBufferSize: /* send buffer size */
case PR_SockOpt_SendBufferSize: /* receive buffer size */
value = &segment;
size = &segmentsize;
break;
case PR_SockOpt_IpTimeToLive: /* time to live */
value = &ttl;
@@ -145,19 +147,30 @@ PRIntn main(PRIntn argc, char *argv)
case PR_SockOpt_AddMember: /* add an IP group membership */
case PR_SockOpt_DropMember: /* drop an IP group membership */
case PR_SockOpt_McastInterface: /* multicast interface address */
case PR_SockOpt_McastTimeToLive: /* multicast timetolive */
case PR_SockOpt_McastLoopback: /* multicast loopback */
default:
continue;
}
-
- rv = PR_SetSockOpt(socket, option, value, *size);
- if (PR_FAILURE == rv) Failed("PR_SetSockOpt()", tag[option]);
+ /*
+ * TCP_MAXSEG can only be read, not set
+ */
+ if (option != PR_SockOpt_MaxSegment) {
+#ifdef WIN32
+ if ((option != PR_SockOpt_McastTimeToLive) &&
+ (option != PR_SockOpt_McastLoopback))
+#endif
+ {
+ rv = PR_SetSockOpt(socket, option, value, *size);
+ if (PR_FAILURE == rv) Failed("PR_SetSockOpt()",
+ tag[option]);
+ }
+ }
rv = PR_GetSockOpt(socket, option, &value, size);
if (PR_FAILURE == rv) Failed("PR_GetSockOpt()", tag[option]);
}
for(option = PR_SockOpt_Linger; option < PR_SockOpt_Last; Incr(&option))
{
PRSocketOptionData data;
PRFileDesc *fd = tcp;
@@ -195,24 +208,38 @@ PRIntn main(PRIntn argc, char *argv)
break;
case PR_SockOpt_McastLoopback:
fd = udp;
data.value.mcast_loopback = PR_TRUE;
break;
case PR_SockOpt_NoDelay:
data.value.no_delay = PR_TRUE;
break;
+#ifndef WIN32
case PR_SockOpt_MaxSegment:
data.value.max_segment = segment;
break;
+#endif
default: continue;
}
- rv = PR_SetSocketOption(fd, &data);
- if (PR_FAILURE == rv) Failed("PR_SetSocketOption()", tag[option]);
+ /*
+ * TCP_MAXSEG can only be read, not set
+ */
+ if (option != PR_SockOpt_MaxSegment) {
+#ifdef WIN32
+ if ((option != PR_SockOpt_McastTimeToLive) &&
+ (option != PR_SockOpt_McastLoopback))
+#endif
+ {
+ rv = PR_SetSocketOption(fd, &data);
+ if (PR_FAILURE == rv)
+ Failed("PR_SetSocketOption()", tag[option]);
+ }
+ }
rv = PR_GetSocketOption(fd, &data);
if (PR_FAILURE == rv) Failed("PR_GetSocketOption()", tag[option]);
}
}
#ifndef XP_MAC
PR_fprintf(err, "%s\n", (failed) ? "FAILED" : "PASSED");
#else
--- a/pr/tests/tmocon.c
+++ b/pr/tests/tmocon.c
@@ -420,17 +420,17 @@ int Tmocon(int argc, char **argv)
for (index = 0; index < threads; ++index)
rv = PR_JoinThread(thread[index]);
PR_DELETE(thread);
PR_fprintf(
PR_GetSpecialFD(PR_StandardError), "%s\n",
((shared->failed) ? "FAILED" : "PASSED"));
- return (shared->failed) ? 0 : 1;
+ return (shared->failed) ? 1 : 0;
}
int main(int argc, char **argv)
{
return (PR_VersionCheck(PR_VERSION)) ?
PR_Initialize(Tmocon, argc, argv, 4) : -1;
} /* main */