On 'thread-name' branch: Merge changes from trunk.

git-svn-id: https://svn.apache.org/repos/asf/apr/apr/branches/thread-name@1902353 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/build/apr_threads.m4 b/build/apr_threads.m4
index 6895c3a..98e17de 100644
--- a/build/apr_threads.m4
+++ b/build/apr_threads.m4
@@ -312,3 +312,27 @@
              [Define if non-posix/portable cross-process robust mutexes are available])
 fi
 ])
+
+
+dnl Check for pthread_setname_np
+dnl Note: Only detects two-arg version
+AC_DEFUN([APR_CHECK_PTHREAD_SETNAME_NP], [
+AC_CACHE_CHECK([for pthread_setname_np support],
+[apr_cv_pthread_setname_np], [
+AC_TRY_COMPILE([
+#include <pthread.h>
+],[
+pthread_t td = pthread_self();
+pthread_setname_np(td, "name");
+],[
+    apr_cv_pthread_setname_np=yes
+],[
+    apr_cv_pthread_setname_np=no
+])])
+
+if test "$apr_cv_pthread_setname_np" = "yes"; then
+   AC_DEFINE([HAVE_PTHREAD_SETNAME_NP], 1,
+             [Define if pthread_setname_np is available])
+fi
+])dnl
+
diff --git a/configure.in b/configure.in
index 653d259..6c296f7 100644
--- a/configure.in
+++ b/configure.in
@@ -947,6 +947,7 @@
         APR_CHECK_PTHREAD_GETSPECIFIC_TWO_ARGS
         APR_CHECK_PTHREAD_ATTR_GETDETACHSTATE_ONE_ARG
         APR_CHECK_PTHREAD_RECURSIVE_MUTEX
+        APR_CHECK_PTHREAD_SETNAME_NP
         AC_CHECK_FUNCS([pthread_key_delete pthread_rwlock_init \
                         pthread_attr_setguardsize pthread_yield])
 
diff --git a/include/apr_thread_proc.h b/include/apr_thread_proc.h
index 952c76d..39dc258 100644
--- a/include/apr_thread_proc.h
+++ b/include/apr_thread_proc.h
@@ -331,6 +331,29 @@
                                           apr_thread_t *thd); 
 
 /**
+ * Get name of thread
+ * @param name The variable where is will be stored name of thread.
+ * @param thread The thread that name required to get.
+ * Current thread will be used if @param thread is NULL.
+ * @param cont The pool to use
+ */
+APR_DECLARE(apr_status_t) apr_thread_name_get(char **name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool);
+
+/**
+ * Set name of thread
+ * @param name The name of thread must be setted. If name is to long, then
+ * name stripped to max length supported by operation system.
+ * @param thread The thread that name will be changed.
+ * Current thread will be used if @param thread is NULL.
+ * @param cont The pool to use for temporary allocations
+ */
+APR_DECLARE(apr_status_t) apr_thread_name_set(const char *name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool);
+
+/**
  * force the current thread to yield the processor
  */
 APR_DECLARE(void) apr_thread_yield(void);
diff --git a/include/arch/win32/apr_arch_misc.h b/include/arch/win32/apr_arch_misc.h
index 057f4ad..53ef2ea 100644
--- a/include/arch/win32/apr_arch_misc.h
+++ b/include/arch/win32/apr_arch_misc.h
@@ -289,4 +289,14 @@
                           (LPCWSTR lpCmdLine, int *pNumArgs),
                           (lpCmdLine, pNumArgs));
 
+APR_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, BOOL, WINAPI, GetThreadDescription, 0, (
+                          HANDLE hThread,
+                          PWSTR *ppszThreadDescription),
+                          (hThread, ppszThreadDescription));
+
+APR_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, BOOL, WINAPI, SetThreadDescription, 0, (
+                          HANDLE hThread,
+                          PCWSTR lpThreadDescription),
+                          (hThread, lpThreadDescription));
+
 #endif  /* ! MISC_H */
diff --git a/test/testthread.c b/test/testthread.c
index e64bdd4..2f8b1cb 100644
--- a/test/testthread.c
+++ b/test/testthread.c
@@ -107,6 +107,36 @@
     ABTS_INT_EQUAL(tc, 1, value);
 }
 
+static void thread_name(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    char *name;
+
+    rv = apr_thread_name_set("thread-1", NULL, p);
+    if (rv == APR_ENOTIMPL) {
+        ABTS_NOT_IMPL(tc, "apr_thread_name_set is not implemented.")
+        return ;
+    }
+
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_thread_name_get(&name, NULL, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    ABTS_STR_EQUAL(tc, "thread-1", name);
+
+    rv = apr_thread_name_set("thread-1", NULL, p);
+    if (rv == APR_ENOTIMPL) {
+        ABTS_NOT_IMPL(tc, "apr_thread_name_set is not implemented.")
+        return ;
+    }
+
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_thread_name_get(&name, NULL, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    ABTS_STR_EQUAL(tc, "thread-1", name);
+}
+
 #else
 
 static void threads_not_impl(abts_case *tc, void *data)
@@ -128,6 +158,7 @@
     abts_run_test(suite, join_threads, NULL);
     abts_run_test(suite, check_locks, NULL);
     abts_run_test(suite, check_thread_once, NULL);
+    abts_run_test(suite, thread_name, NULL);
 #endif
 
     return suite;
diff --git a/threadproc/beos/thread.c b/threadproc/beos/thread.c
index f5752a8..9680315 100644
--- a/threadproc/beos/thread.c
+++ b/threadproc/beos/thread.c
@@ -343,3 +343,17 @@
 }
 
 APR_POOL_IMPLEMENT_ACCESSOR(thread)
+
+APR_DECLARE(apr_status_t) apr_thread_name_set(const char* name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{
+    return APR_ENOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_name_get(apr_thread_t *thread,
+                                              char **name,
+                                              apr_pool_t pool)
+{
+    return APR_ENOTIMPL;
+}
diff --git a/threadproc/netware/thread.c b/threadproc/netware/thread.c
index 2412211..404b42f 100644
--- a/threadproc/netware/thread.c
+++ b/threadproc/netware/thread.c
@@ -354,4 +354,16 @@
 
 APR_POOL_IMPLEMENT_ACCESSOR(thread)
 
+APR_DECLARE(apr_status_t) apr_thread_name_set(const char *name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{
+    return APR_ENOTIMPL;
+}
 
+APR_DECLARE(apr_status_t) apr_thread_name_get(char ** name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{
+    return APR_ENOTIMPL;
+}
\ No newline at end of file
diff --git a/threadproc/os2/thread.c b/threadproc/os2/thread.c
index e054018..9b4eb34 100644
--- a/threadproc/os2/thread.c
+++ b/threadproc/os2/thread.c
@@ -259,6 +259,20 @@
     return APR_SUCCESS;
 }
 
+APR_DECLARE(apr_status_t) apr_thread_name_set(const char *name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{
+    return APR_ENOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_name_get(char ** name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{ 
+    return APR_ENOTIMPL;
+}
+
 
 
 void apr_thread_yield()
diff --git a/threadproc/unix/thread.c b/threadproc/unix/thread.c
index 209fe7c..01d2417 100644
--- a/threadproc/unix/thread.c
+++ b/threadproc/unix/thread.c
@@ -22,6 +22,11 @@
 
 #if APR_HAVE_PTHREAD_H
 
+/* Unfortunately the kernel headers do not export the TASK_COMM_LEN
+   macro.  So we have to define it here. Used in apr_thread_name_get and
+   apr_thread_name_set functions */
+#define TASK_COMM_LEN 16
+
 /* Destroy the threadattr object */
 static apr_status_t threadattr_cleanup(void *data)
 {
@@ -277,6 +282,56 @@
 #endif
 }
 
+APR_DECLARE(apr_status_t) apr_thread_name_set(const char *name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{
+#if HAVE_PTHREAD_SETNAME_NP
+    pthread_t td;
+
+    size_t name_len;
+    if (!name) {
+        return APR_BADARG;
+    }
+
+    if (thread) {
+        td = *thread->td;
+    }
+    else {
+        td = pthread_self();
+    }
+
+    name_len = strlen(name);
+    if (name_len >= TASK_COMM_LEN) {
+        name = name + name_len - TASK_COMM_LEN + 1;
+    }
+
+    return pthread_setname_np(td, name);
+#else
+    return APR_ENOTIMPL;
+#endif
+}
+
+APR_DECLARE(apr_status_t) apr_thread_name_get(char **name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{
+#if HAVE_PTHREAD_SETNAME_NP
+    pthread_t td;
+    if (thread) {
+        td = *thread->td;
+    }
+    else {
+        td = pthread_self();
+    }
+
+    *name = apr_pcalloc(pool, TASK_COMM_LEN);
+    return pthread_getname_np(td, *name, TASK_COMM_LEN);
+#else
+    return APR_ENOTIMPL;
+#endif
+}
+
 APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void)
 {
     return pthread_self();
diff --git a/threadproc/win32/thread.c b/threadproc/win32/thread.c
index 0b672e6..90ee9f1 100644
--- a/threadproc/win32/thread.c
+++ b/threadproc/win32/thread.c
@@ -24,6 +24,7 @@
 #include <process.h>
 #endif
 #include "apr_arch_misc.h"   
+#include "apr_arch_utf8.h"
 
 /* Chosen for us by apr_initialize */
 DWORD tls_apr_thread = 0;
@@ -301,6 +302,77 @@
     return apr_pool_userdata_set(data, key, cleanup, thread->pool);
 }
 
+APR_DECLARE(apr_status_t) apr_thread_name_set(const char *name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{
+    apr_wchar_t *wname;
+    apr_size_t wname_len;
+    apr_size_t name_len;
+    apr_status_t rv;
+    HANDLE thread_handle;
+
+    if (!APR_HAVE_LATE_DLL_FUNC(SetThreadDescription)) {
+	    return APR_ENOTIMPL;
+    }
+
+    if (thread) {
+        thread_handle = thread->td;
+    }
+    else {
+        thread_handle = GetCurrentThread();
+    }
+
+    name_len = strlen(name) + 1;
+    wname_len = name_len;
+    wname = apr_palloc(pool, wname_len * sizeof(apr_wchar_t));
+    rv = apr_conv_utf8_to_ucs2(name, &name_len, wname, &wname_len);
+    if (rv) {
+        return rv;
+    }
+
+    if (!apr_winapi_SetThreadDescription(thread_handle, wname)) {
+        return apr_get_os_error();
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_name_get(char **name,
+                                              apr_thread_t *thread,
+                                              apr_pool_t *pool)
+{
+    apr_wchar_t *wname;
+    apr_size_t wname_len;
+    apr_size_t name_len;
+    apr_status_t rv;
+    HANDLE thread_handle;
+
+    if (!APR_HAVE_LATE_DLL_FUNC(GetThreadDescription)) {
+	    return APR_ENOTIMPL;
+    }
+
+    if (thread) {
+        thread_handle = thread->td;
+    }
+    else {
+        thread_handle = GetCurrentThread();
+    }
+
+    if (!apr_winapi_GetThreadDescription(thread_handle, &wname)) {
+        return apr_get_os_error();
+    }
+
+    wname_len = wcslen(wname) + 1;
+
+    name_len = wname_len * 3;
+    *name = apr_palloc(pool, name_len);
+
+    rv = apr_conv_ucs2_to_utf8(wname, &wname_len, *name, &name_len);
+    LocalFree(wname);
+ 
+    return rv;
+}
 
 APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void)
 {