Bug 758837: add the PR_SetThreadName and PR_GetThreadName functions for
authorwtc%google.com
Sat, 26 May 2012 00:15:24 +0000
changeset 4392 7245464a5a6598fdb73ff7cdbd29267fad5a7fc9
parent 4391 66ead64ab2e6ba807210b2bda4a7a2d59cdbc161
child 4393 94ad5c41550ed6549d1f9994abaaa50d3713eb6b
push idunknown
push userunknown
push dateunknown
bugs758837
Bug 758837: add the PR_SetThreadName and PR_GetThreadName functions for setting and getting the name of the current thread. The patch is contributed by Honza Bambas <<honzab.moz@firemni.cz>. r=wtc. Modified Files: prthread.h _win95.h _winnt.h primpl.h nspr.def ntthread.c w95thred.c ptthread.c prcthr.c pruthr.c
pr/include/md/_win95.h
pr/include/md/_winnt.h
pr/include/private/primpl.h
pr/include/prthread.h
pr/src/md/windows/ntthread.c
pr/src/md/windows/w95thred.c
pr/src/nspr.def
pr/src/pthreads/ptthread.c
pr/src/threads/combined/pruthr.c
pr/src/threads/prcthr.c
--- a/pr/include/md/_win95.h
+++ b/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/pr/include/md/_winnt.h
+++ b/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/pr/include/private/primpl.h
+++ b/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/pr/include/prthread.h
+++ b/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 thread name, which will be visible in a debugger and accessible
+** via a call to PR_GetThreadName().
+*/
+NSPR_API(PRStatus) PR_SetThreadName(const char *name);
+
+/*
+** Return the current thread name, if set.  Otherwise return NULL.
+*/
+NSPR_API(const char *) PR_GetThreadName();
+
+/*
 ** 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/pr/src/md/windows/ntthread.c
+++ b/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/pr/src/md/windows/w95thred.c
+++ b/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/pr/src/nspr.def
+++ b/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.1 {
+;+      global:
+		PR_GetThreadName;
+		PR_SetThreadName;
+;+} NSPR_4.8.9;
--- a/pr/src/pthreads/ptthread.c
+++ b/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,84 @@ 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_SetThreadName(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()
+{
+    PRThread *thread;
+
+    thread = PR_GetCurrentThread();
+    if (!thread)
+        return NULL;
+    return thread->name;
+}
+
 #endif  /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */
 
 /* ptthread.c */
--- a/pr/src/threads/combined/pruthr.c
+++ b/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,50 @@ 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_SetThreadName(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()
+{
+    PRThread *thread;
+
+    thread = PR_GetCurrentThread();
+    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/pr/src/threads/prcthr.c
+++ b/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()
 {