diff --git a/mozilla/nsprpub/pr/include/md/_win95.h b/mozilla/nsprpub/pr/include/md/_win95.h index b3b88bd3d6b..a919e3a02e6 100644 --- a/mozilla/nsprpub/pr/include/md/_win95.h +++ b/mozilla/nsprpub/pr/include/md/_win95.h @@ -362,6 +362,7 @@ extern PROsfd _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, #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 diff --git a/mozilla/nsprpub/pr/include/md/_winnt.h b/mozilla/nsprpub/pr/include/md/_winnt.h index 57423eacd9a..4d4d2c12709 100644 --- a/mozilla/nsprpub/pr/include/md/_winnt.h +++ b/mozilla/nsprpub/pr/include/md/_winnt.h @@ -376,6 +376,7 @@ extern int _PR_NTFiberSafeSelect(int, fd_set *, fd_set *, fd_set *, #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 diff --git a/mozilla/nsprpub/pr/include/private/primpl.h b/mozilla/nsprpub/pr/include/private/primpl.h index d86f66f71b3..e9217f29db7 100644 --- a/mozilla/nsprpub/pr/include/private/primpl.h +++ b/mozilla/nsprpub/pr/include/private/primpl.h @@ -977,6 +977,9 @@ extern void _PR_MD_YIELD(void); 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 @@ -1533,6 +1536,7 @@ struct PRThread { 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 */ diff --git a/mozilla/nsprpub/pr/include/prthread.h b/mozilla/nsprpub/pr/include/prthread.h index f38ff69c8d9..60414f001d5 100644 --- a/mozilla/nsprpub/pr/include/prthread.h +++ b/mozilla/nsprpub/pr/include/prthread.h @@ -144,6 +144,17 @@ NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); */ 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 diff --git a/mozilla/nsprpub/pr/src/md/windows/ntthread.c b/mozilla/nsprpub/pr/src/md/windows/ntthread.c index 5f9e646377e..d695fe40e85 100644 --- a/mozilla/nsprpub/pr/src/md/windows/ntthread.c +++ b/mozilla/nsprpub/pr/src/md/windows/ntthread.c @@ -276,6 +276,40 @@ _PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) 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) { diff --git a/mozilla/nsprpub/pr/src/md/windows/w95thred.c b/mozilla/nsprpub/pr/src/md/windows/w95thred.c index dc0eac31bcf..21b4a6eac25 100644 --- a/mozilla/nsprpub/pr/src/md/windows/w95thred.c +++ b/mozilla/nsprpub/pr/src/md/windows/w95thred.c @@ -168,6 +168,40 @@ _PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) 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) { diff --git a/mozilla/nsprpub/pr/src/nspr.def b/mozilla/nsprpub/pr/src/nspr.def index c6618a8d444..aac2f3a6070 100644 --- a/mozilla/nsprpub/pr/src/nspr.def +++ b/mozilla/nsprpub/pr/src/nspr.def @@ -446,3 +446,8 @@ EXPORTS ;- ;+ global: PR_GetVersion; ;+} NSPR_4.8; +;+NSPR_4.9.1 { +;+ global: + PR_GetThreadName; + PR_SetThreadName; +;+} NSPR_4.8.9; diff --git a/mozilla/nsprpub/pr/src/pthreads/ptthread.c b/mozilla/nsprpub/pr/src/pthreads/ptthread.c index c3223bbedab..0b8ee9878ff 100644 --- a/mozilla/nsprpub/pr/src/pthreads/ptthread.c +++ b/mozilla/nsprpub/pr/src/pthreads/ptthread.c @@ -19,6 +19,7 @@ #include #include #include +#include #ifdef SYMBIAN /* In Open C sched_get_priority_min/max do not work properly, so we undefine @@ -794,6 +795,8 @@ static void _pt_thread_death_internal(void *arg, PRBool callDestructors) 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); @@ -1612,6 +1615,79 @@ PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred) #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 */ diff --git a/mozilla/nsprpub/pr/src/threads/combined/pruthr.c b/mozilla/nsprpub/pr/src/threads/combined/pruthr.c index 53eea1fc488..1f89a588905 100644 --- a/mozilla/nsprpub/pr/src/threads/combined/pruthr.c +++ b/mozilla/nsprpub/pr/src/threads/combined/pruthr.c @@ -237,6 +237,7 @@ static void _PR_InitializeRecycledThread(PRThread *thread) 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; @@ -1581,6 +1582,40 @@ PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thread, } 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 diff --git a/mozilla/nsprpub/pr/src/threads/prcthr.c b/mozilla/nsprpub/pr/src/threads/prcthr.c index 4f9a3beb446..268814473e1 100644 --- a/mozilla/nsprpub/pr/src/threads/prcthr.c +++ b/mozilla/nsprpub/pr/src/threads/prcthr.c @@ -35,6 +35,7 @@ void _PR_CleanupThread(PRThread *thread) } thread->dump = 0; + PR_DELETE(thread->name); PR_DELETE(thread->errorString); thread->errorStringSize = 0; thread->errorStringLength = 0;