Bug 758837: update NSPR to NSPR_4_9_2_BETA1 to pick up the new
authorWan-Teh Chang <wtc@google.com>
Thu, 07 Jun 2012 11:26:20 -0700
changeset 101382 838a1a9bad2bd917bc417bb9a0ab0160363781a8
parent 101380 d95dca51a83330c27f63ba7f16de3ebf9ec4cd2b
child 101383 3638e7addad9fb4de2f4cd67a9ab792ce0dac804
push id191
push userlsblakk@mozilla.com
push dateFri, 05 Oct 2012 17:12:53 +0000
treeherdermozilla-release@ddb22ac6c03b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs758837
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 758837: update NSPR to NSPR_4_9_2_BETA1 to pick up the new thread name functions. r=honzab.
nsprpub/TAG-INFO
nsprpub/admin/repackage.sh
nsprpub/config/prdepend.h
nsprpub/configure
nsprpub/configure.in
nsprpub/pr/include/md/_win95.h
nsprpub/pr/include/md/_winnt.h
nsprpub/pr/include/prinit.h
nsprpub/pr/include/private/primpl.h
nsprpub/pr/include/prthread.h
nsprpub/pr/src/md/windows/ntthread.c
nsprpub/pr/src/md/windows/w95thred.c
nsprpub/pr/src/nspr.def
nsprpub/pr/src/pthreads/ptthread.c
nsprpub/pr/src/threads/combined/pruthr.c
nsprpub/pr/src/threads/prcthr.c
nsprpub/pr/tests/vercheck.c
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_9_1_RTM
+NSPR_4_9_2_BETA1
--- a/nsprpub/admin/repackage.sh
+++ b/nsprpub/admin/repackage.sh
@@ -27,20 +27,20 @@
 # Note! Files written with Gnu tar are not readable by some non-Gnu
 # versions. Sun, in particular.
 # 
 # 
 # 
 # 
 # ------------------------------------------------------------------
 
-FROMTOP=/share/builds/components/nspr20/v4.9.1
-TOTOP=./v4.9.1
-NSPRDIR=nspr-4.9.1
-SOURCETAG=NSPR_4_9_1_RTM
+FROMTOP=/share/builds/components/nspr20/v4.9.2
+TOTOP=./v4.9.2
+NSPRDIR=nspr-4.9.2
+SOURCETAG=NSPR_4_9_2_RTM
 
 #
 # enumerate Unix object directories on /s/b/c
 UNIX_OBJDIRS="
 HP-UXB.11.11_64_DBG.OBJ
 HP-UXB.11.11_64_OPT.OBJ
 HP-UXB.11.11_DBG.OBJ
 HP-UXB.11.11_OPT.OBJ
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/nsprpub/configure
+++ b/nsprpub/configure
@@ -731,17 +731,17 @@ echo "$ac_t""$build" 1>&6
 test "$host_alias" != "$target_alias" &&
   test "$program_prefix$program_suffix$program_transform_name" = \
     NONENONEs,x,x, &&
   program_prefix=${target_alias}-
 
 
 MOD_MAJOR_VERSION=4
 MOD_MINOR_VERSION=9
-MOD_PATCH_VERSION=1
+MOD_PATCH_VERSION=2
 NSPR_MODNAME=nspr20
 _HAVE_PTHREADS=
 USE_PTHREADS=
 USE_USER_PTHREADS=
 USE_NSPR_THREADS=
 USE_N32=
 USE_64=
 USE_CPLUS=
--- a/nsprpub/configure.in
+++ b/nsprpub/configure.in
@@ -10,17 +10,17 @@ AC_INIT(config/libc_r.h)
 AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf)
 AC_CANONICAL_SYSTEM
 
 dnl ========================================================
 dnl = Defaults
 dnl ========================================================
 MOD_MAJOR_VERSION=4
 MOD_MINOR_VERSION=9
-MOD_PATCH_VERSION=1
+MOD_PATCH_VERSION=2
 NSPR_MODNAME=nspr20
 _HAVE_PTHREADS=
 USE_PTHREADS=
 USE_USER_PTHREADS=
 USE_NSPR_THREADS=
 USE_N32=
 USE_64=
 USE_CPLUS=
--- a/nsprpub/pr/include/md/_win95.h
+++ b/nsprpub/pr/include/md/_win95.h
@@ -357,16 +357,17 @@ extern PROsfd _MD_Accept(PRFileDesc *fd,
 
 /* --- Threading Stuff --- */
 #define _MD_DEFAULT_STACK_SIZE            0
 #define _MD_INIT_THREAD             _PR_MD_INIT_THREAD
 #define _MD_INIT_ATTACHED_THREAD    _PR_MD_INIT_THREAD
 #define _MD_CREATE_THREAD           _PR_MD_CREATE_THREAD
 #define _MD_YIELD                   _PR_MD_YIELD
 #define _MD_SET_PRIORITY            _PR_MD_SET_PRIORITY
+#define _MD_SET_CURRENT_THREAD_NAME _PR_MD_SET_CURRENT_THREAD_NAME
 #define _MD_CLEAN_THREAD            _PR_MD_CLEAN_THREAD
 #define _MD_SETTHREADAFFINITYMASK   _PR_MD_SETTHREADAFFINITYMASK
 #define _MD_GETTHREADAFFINITYMASK   _PR_MD_GETTHREADAFFINITYMASK
 #define _MD_EXIT_THREAD             _PR_MD_EXIT_THREAD
 #define _MD_EXIT                    _PR_MD_EXIT
 #define _MD_SUSPEND_THREAD          _PR_MD_SUSPEND_THREAD
 #define _MD_RESUME_THREAD           _PR_MD_RESUME_THREAD
 #define _MD_SUSPEND_CPU             _PR_MD_SUSPEND_CPU
--- a/nsprpub/pr/include/md/_winnt.h
+++ b/nsprpub/pr/include/md/_winnt.h
@@ -371,16 +371,17 @@ extern int _PR_NTFiberSafeSelect(int, fd
 #define _MD_DEFAULT_STACK_SIZE            0
 #define _MD_INIT_THREAD             _PR_MD_INIT_THREAD
 #define _MD_INIT_ATTACHED_THREAD    _PR_MD_INIT_THREAD
 #define _MD_CREATE_THREAD           _PR_MD_CREATE_THREAD
 #define _MD_JOIN_THREAD             _PR_MD_JOIN_THREAD
 #define _MD_END_THREAD              _PR_MD_END_THREAD
 #define _MD_YIELD                   _PR_MD_YIELD
 #define _MD_SET_PRIORITY            _PR_MD_SET_PRIORITY
+#define _MD_SET_CURRENT_THREAD_NAME _PR_MD_SET_CURRENT_THREAD_NAME
 #define _MD_CLEAN_THREAD            _PR_MD_CLEAN_THREAD
 #define _MD_SETTHREADAFFINITYMASK   _PR_MD_SETTHREADAFFINITYMASK
 #define _MD_GETTHREADAFFINITYMASK   _PR_MD_GETTHREADAFFINITYMASK
 #define _MD_EXIT_THREAD             _PR_MD_EXIT_THREAD
 #define _MD_SUSPEND_THREAD          _PR_MD_SUSPEND_THREAD
 #define _MD_RESUME_THREAD           _PR_MD_RESUME_THREAD
 #define _MD_SUSPEND_CPU             _PR_MD_SUSPEND_CPU
 #define _MD_RESUME_CPU              _PR_MD_RESUME_CPU
--- a/nsprpub/pr/include/prinit.h
+++ b/nsprpub/pr/include/prinit.h
@@ -26,21 +26,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>[.<patch level>] [<Beta>]"
 */
-#define PR_VERSION  "4.9.1"
+#define PR_VERSION  "4.9.2 Beta"
 #define PR_VMAJOR   4
 #define PR_VMINOR   9
-#define PR_VPATCH   1
-#define PR_BETA     PR_FALSE
+#define PR_VPATCH   2
+#define PR_BETA     PR_TRUE
 
 /*
 ** 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/nsprpub/pr/include/private/primpl.h
+++ b/nsprpub/pr/include/private/primpl.h
@@ -972,16 +972,19 @@ extern void _PR_MD_END_THREAD(void);
 #define    _PR_MD_END_THREAD _MD_END_THREAD
 
 extern void _PR_MD_YIELD(void);
 #define    _PR_MD_YIELD _MD_YIELD
 
 extern void _PR_MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri);
 #define    _PR_MD_SET_PRIORITY _MD_SET_PRIORITY
 
+extern void _PR_MD_SET_CURRENT_THREAD_NAME(const char *name);
+#define    _PR_MD_SET_CURRENT_THREAD_NAME _MD_SET_CURRENT_THREAD_NAME
+
 NSPR_API(void) _PR_MD_SUSPENDALL(void);
 #define    _PR_MD_SUSPENDALL _MD_SUSPENDALL
 
 NSPR_API(void) _PR_MD_RESUMEALL(void);
 #define    _PR_MD_RESUMEALL _MD_RESUMEALL
 
 extern void _PR_MD_INIT_CONTEXT(
     PRThread *thread, char *top, void (*start) (void), PRBool *status);
@@ -1528,16 +1531,17 @@ struct PRThread {
     */
     PRUint32 tpdLength;             /* thread's current vector length */
     void **privateData;             /* private data vector or NULL */
     PRErrorCode errorCode;          /* current NSPR error code | zero */
     PRInt32 osErrorCode;            /* mapping of errorCode | zero */
     PRIntn  errorStringLength;      /* textLength from last call to PR_SetErrorText() */
     PRInt32 errorStringSize;        /* malloc()'d size of buffer | zero */
     char *errorString;              /* current error string | NULL */
+    char *name;                     /* thread's name */
 
 #if defined(_PR_PTHREADS)
     pthread_t id;                   /* pthread identifier for the thread */
     PRBool okToDelete;              /* ok to delete the PRThread struct? */
     PRCondVar *waiting;             /* where the thread is waiting | NULL */
     void *sp;                       /* recorded sp for garbage collection */
     PRThread *next, *prev;          /* simple linked list of all threads */
     PRUint32 suspend;               /* used to store suspend and resume flags */
--- a/nsprpub/pr/include/prthread.h
+++ b/nsprpub/pr/include/prthread.h
@@ -140,16 +140,27 @@ NSPR_API(PRThread*) PR_GetCurrentThread(
 NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread);
 
 /*
 ** Change the priority of the "thread" to "priority".
 */
 NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority);
 
 /*
+** Set the name of the current thread, which will be visible in a debugger
+** and accessible via a call to PR_GetThreadName().
+*/
+NSPR_API(PRStatus) PR_SetCurrentThreadName(const char *name);
+
+/*
+** Return the name of "thread", if set.  Otherwise return NULL.
+*/
+NSPR_API(const char *) PR_GetThreadName(const PRThread *thread);
+
+/*
 ** This routine returns a new index for per-thread-private data table. 
 ** The index is visible to all threads within a process. This index can 
 ** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines 
 ** to save and retrieve data associated with the index for a thread.
 **
 ** Each index is associationed with a destructor function ('dtor'). The function
 ** may be specified as NULL when the index is created. If it is not NULL, the
 ** function will be called when:
--- a/nsprpub/pr/src/md/windows/ntthread.c
+++ b/nsprpub/pr/src/md/windows/ntthread.c
@@ -271,16 +271,50 @@ void
     PR_ASSERT(rv);
     if (!rv) {
 	PR_LOG(_pr_thread_lm, PR_LOG_MIN,
                 ("PR_SetThreadPriority: can't set thread priority\n"));
     }
     return;
 }
 
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+#pragma pack(push,8)
+typedef struct tagTHREADNAME_INFO
+{
+   DWORD dwType; // Must be 0x1000.
+   LPCSTR szName; // Pointer to name (in user addr space).
+   DWORD dwThreadID; // Thread ID (-1=caller thread).
+   DWORD dwFlags; // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+#pragma pack(pop)
+
+void
+_PR_MD_SET_CURRENT_THREAD_NAME(const char *name)
+{
+   THREADNAME_INFO info;
+
+   if (!IsDebuggerPresent())
+      return;
+
+   info.dwType = 0x1000;
+   info.szName = (char*) name;
+   info.dwThreadID = -1;
+   info.dwFlags = 0;
+
+   __try {
+      RaiseException(MS_VC_EXCEPTION,
+                     0,
+                     sizeof(info) / sizeof(ULONG_PTR),
+                     (ULONG_PTR*)&info);
+   } __except(EXCEPTION_CONTINUE_EXECUTION) {
+   }
+}
+
 void
 _PR_MD_CLEAN_THREAD(PRThread *thread)
 {
     BOOL rv;
 
     if (thread->md.acceptex_buf) {
         PR_DELETE(thread->md.acceptex_buf);
     }
--- a/nsprpub/pr/src/md/windows/w95thred.c
+++ b/nsprpub/pr/src/md/windows/w95thred.c
@@ -163,16 +163,50 @@ void
     PR_ASSERT(rv);
     if (!rv) {
 	PR_LOG(_pr_thread_lm, PR_LOG_MIN,
                 ("PR_SetThreadPriority: can't set thread priority\n"));
     }
     return;
 }
 
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+#pragma pack(push,8)
+typedef struct tagTHREADNAME_INFO
+{
+   DWORD dwType; // Must be 0x1000.
+   LPCSTR szName; // Pointer to name (in user addr space).
+   DWORD dwThreadID; // Thread ID (-1=caller thread).
+   DWORD dwFlags; // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+#pragma pack(pop)
+
+void
+_PR_MD_SET_CURRENT_THREAD_NAME(const char *name)
+{
+   THREADNAME_INFO info;
+
+   if (!IsDebuggerPresent())
+      return;
+
+   info.dwType = 0x1000;
+   info.szName = (char*) name;
+   info.dwThreadID = -1;
+   info.dwFlags = 0;
+
+   __try {
+      RaiseException(MS_VC_EXCEPTION,
+                     0,
+                     sizeof(info) / sizeof(ULONG_PTR),
+                     (ULONG_PTR*)&info);
+   } __except(EXCEPTION_CONTINUE_EXECUTION) {
+   }
+}
+
 void
 _PR_MD_CLEAN_THREAD(PRThread *thread)
 {
     BOOL rv;
 
     if (thread->md.blocked_sema) {
         rv = CloseHandle(thread->md.blocked_sema);
         PR_ASSERT(rv);
--- a/nsprpub/pr/src/nspr.def
+++ b/nsprpub/pr/src/nspr.def
@@ -441,8 +441,13 @@ EXPORTS ;-
 ;+	global:
 		PR_AssertCurrentThreadOwnsLock;
 		PR_AssertCurrentThreadInMonitor;
 ;+} NSPR_4.7;
 ;+NSPR_4.8.9 {
 ;+      global:
                 PR_GetVersion;
 ;+} NSPR_4.8;
+;+NSPR_4.9.2 {
+;+      global:
+		PR_GetThreadName;
+		PR_SetCurrentThreadName;
+;+} NSPR_4.8.9;
--- a/nsprpub/pr/src/pthreads/ptthread.c
+++ b/nsprpub/pr/src/pthreads/ptthread.c
@@ -14,16 +14,17 @@
 #include "prlog.h"
 #include "primpl.h"
 #include "prpdce.h"
 
 #include <pthread.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
+#include <dlfcn.h>
 
 #ifdef SYMBIAN
 /* In Open C sched_get_priority_min/max do not work properly, so we undefine
  * _POSIX_THREAD_PRIORITY_SCHEDULING here.
  */
 #undef _POSIX_THREAD_PRIORITY_SCHEDULING
 #endif
 
@@ -789,16 +790,18 @@ static void _pt_thread_death_internal(vo
             thred->next->prev = thred->prev;
         PR_Unlock(pt_book.ml);
     }
     if (callDestructors)
         _PR_DestroyThreadPrivate(thred);
     PR_Free(thred->privateData);
     if (NULL != thred->errorString)
         PR_Free(thred->errorString);
+    if (NULL != thred->name)
+        PR_Free(thred->name);
     PR_Free(thred->stack);
     if (NULL != thred->syspoll_list)
         PR_Free(thred->syspoll_list);
 #if defined(_PR_POLL_WITH_SELECT)
     if (NULL != thred->selectfd_list)
         PR_Free(thred->selectfd_list);
 #endif
 #if defined(DEBUG)
@@ -1607,11 +1610,81 @@ PR_IMPLEMENT(void*)PR_GetSP(PRThread *th
 	thread_tcb = (char*)tid.field1;
 	top_sp = *(char**)(thread_tcb + 128);
 	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %p \n", top_sp));
 	return top_sp;
 }  /* PR_GetSP */
 
 #endif /* !defined(_PR_DCETHREADS) */
 
+PR_IMPLEMENT(PRStatus) PR_SetCurrentThreadName(const char *name)
+{
+    PRThread *thread;
+    size_t nameLen;
+    int result;
+
+    if (!name) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    thread = PR_GetCurrentThread();
+    if (!thread)
+        return PR_FAILURE;
+
+    PR_Free(thread->name);
+    nameLen = strlen(name) + 1;
+    thread->name = (char *)PR_Malloc(nameLen);
+    if (!thread->name)
+        return PR_FAILURE;
+    memcpy(thread->name, name, nameLen);
+
+#if defined(OPENBSD) || defined(FREEBSD)
+    result = pthread_set_name_np(thread->id, name);
+#else /* not BSD */
+    /*
+     * On OSX, pthread_setname_np is only available in 10.6 or later, so test
+     * for it at runtime.  It also may not be available on all linux distros.
+     * The name length limit is 16 bytes.
+     */
+#if defined(DARWIN)
+    int (*dynamic_pthread_setname_np)(const char*);
+#else
+    int (*dynamic_pthread_setname_np)(pthread_t, const char*);
+#endif
+
+    *(void**)(&dynamic_pthread_setname_np) =
+        dlsym(RTLD_DEFAULT, "pthread_setname_np");
+    if (!dynamic_pthread_setname_np)
+        return PR_SUCCESS;
+
+#define SETNAME_LENGTH_CONSTRAINT 15
+    char name_dup[SETNAME_LENGTH_CONSTRAINT + 1];
+    if (nameLen > SETNAME_LENGTH_CONSTRAINT + 1) {
+        memcpy(name_dup, name, SETNAME_LENGTH_CONSTRAINT);
+        name_dup[SETNAME_LENGTH_CONSTRAINT] = '\0';
+        name = name_dup;
+    }
+
+#if defined(DARWIN)
+    result = dynamic_pthread_setname_np(name);
+#else
+    result = dynamic_pthread_setname_np(thread->id, name);
+#endif
+#endif /* not BSD */
+
+    if (result) {
+        PR_SetError(PR_UNKNOWN_ERROR, result);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread)
+{
+    if (!thread)
+        return NULL;
+    return thread->name;
+}
+
 #endif  /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */
 
 /* ptthread.c */
--- a/nsprpub/pr/src/threads/combined/pruthr.c
+++ b/nsprpub/pr/src/threads/combined/pruthr.c
@@ -232,16 +232,17 @@ static void _PR_InitializeRecycledThread
         for (i = 0; i < thread->tpdLength; i++) {
             PR_ASSERT(thread->privateData[i] == NULL);
         }
     }
 #endif
     PR_ASSERT(thread->dumpArg == 0 && thread->dump == 0);
     PR_ASSERT(thread->errorString == 0 && thread->errorStringSize == 0);
     PR_ASSERT(thread->errorStringLength == 0);
+    PR_ASSERT(thread->name == 0);
 
     /* Reset data members in thread structure */
     thread->errorCode = thread->osErrorCode = 0;
     thread->io_pending = thread->io_suspended = PR_FALSE;
     thread->environment = 0;
     PR_INIT_CLIST(&thread->lockList);
 }
 
@@ -1576,16 +1577,47 @@ PR_IMPLEMENT(void) PR_SetThreadPriority(
     }
         
     if ( _PR_IS_NATIVE_THREAD(thread) ) {
         thread->priority = newPri;
         _PR_MD_SET_PRIORITY(&(thread->md), newPri);
     } else _PR_SetThreadPriority(thread, newPri);
 }
 
+PR_IMPLEMENT(PRStatus) PR_SetCurrentThreadName(const char *name)
+{
+    PRThread *thread;
+    size_t nameLen;
+
+    if (!name) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    thread = PR_GetCurrentThread();
+    if (!thread)
+        return PR_FAILURE;
+
+    PR_Free(thread->name);
+    nameLen = strlen(name) + 1;
+    thread->name = (char *)PR_Malloc(nameLen);
+    if (!thread->name)
+        return PR_FAILURE;
+    memcpy(thread->name, name, nameLen);
+    _PR_MD_SET_CURRENT_THREAD_NAME(thread->name);
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread)
+{
+    if (!thread)
+        return NULL;
+    return thread->name;
+}
+
 
 /*
 ** This routine prevents all other threads from running. This call is needed by 
 ** the garbage collector.
 */
 PR_IMPLEMENT(void) PR_SuspendAll(void)
 {
     PRThread *me = _PR_MD_CURRENT_THREAD();
--- a/nsprpub/pr/src/threads/prcthr.c
+++ b/nsprpub/pr/src/threads/prcthr.c
@@ -30,16 +30,17 @@ void _PR_CleanupThread(PRThread *thread)
     _PR_DestroyThreadPrivate(thread);
 
     /* Free any thread dump procs */
     if (thread->dumpArg) {
         PR_DELETE(thread->dumpArg);
     }
     thread->dump = 0;
 
+    PR_DELETE(thread->name);
     PR_DELETE(thread->errorString);
     thread->errorStringSize = 0;
     thread->errorStringLength = 0;
     thread->environment = NULL;
 }
 
 PR_IMPLEMENT(PRStatus) PR_Yield()
 {
--- a/nsprpub/pr/tests/vercheck.c
+++ b/nsprpub/pr/tests/vercheck.c
@@ -15,46 +15,47 @@
  */
 
 #include "prinit.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 
 /*
- * This release (4.9.1) is backward compatible with the
+ * This release (4.9.2) is backward compatible with the
  * 4.0.x, 4.1.x, 4.2.x, 4.3.x, 4.4.x, 4.5.x, 4.6.x, 4.7.x,
- * 4.8.x, and 4.9 releases.  It, of course, is compatible with itself.
+ * 4.8.x, 4.9, and 4.9.1 releases.  It, of course,
+ * is compatible with itself.
  */
 static char *compatible_version[] = {
     "4.0", "4.0.1", "4.1", "4.1.1", "4.1.2", "4.1.3",
     "4.2", "4.2.1", "4.2.2", "4.3", "4.4", "4.4.1",
     "4.5", "4.5.1",
     "4.6", "4.6.1", "4.6.2", "4.6.3", "4.6.4", "4.6.5",
     "4.6.6", "4.6.7", "4.6.8",
     "4.7", "4.7.1", "4.7.2", "4.7.3", "4.7.4", "4.7.5",
     "4.7.6",
     "4.8", "4.8.1", "4.8.2", "4.8.3", "4.8.4", "4.8.5",
     "4.8.6", "4.8.7", "4.8.8", "4.8.9",
-    "4.9", PR_VERSION
+    "4.9", "4.9.1", PR_VERSION
 };
 
 /*
  * This release is not backward compatible with the old
  * NSPR 2.1 and 3.x releases.
  *
  * Any release is incompatible with future releases and
  * patches.
  */
 static char *incompatible_version[] = {
     "2.1 19980529",
     "3.0", "3.0.1",
     "3.1", "3.1.1", "3.1.2", "3.1.3",
     "3.5", "3.5.1",
-    "4.9.2",
+    "4.9.3",
     "4.10", "4.10.1",
     "10.0", "11.1", "12.14.20"
 };
 
 int main(int argc, char **argv)
 {
     int idx;
     int num_compatible = sizeof(compatible_version) / sizeof(char *);