Implement pthread_setname_np and pthread_getname_np

These should be compatible with Linux, pthreads-win32 (Linux mode) and Cygwin
implementations (but not OSX, BSD or pthreads-win32 (BSD mode)).

Based on MSDN code[1].

[1] https://msdn.microsoft.com/en-us/library/xcb2z8hs%28v=vs.71%29.aspx
diff --git a/mingw-w64-libraries/winpthreads/include/pthread.h b/mingw-w64-libraries/winpthreads/include/pthread.h
index f63d328..355bdae 100644
--- a/mingw-w64-libraries/winpthreads/include/pthread.h
+++ b/mingw-w64-libraries/winpthreads/include/pthread.h
@@ -314,6 +314,9 @@
 int       WINPTHREAD_API pthread_create(pthread_t *th, const pthread_attr_t *attr, void *(* func)(void *), void *arg);
 int       WINPTHREAD_API pthread_join(pthread_t t, void **res);
 int       WINPTHREAD_API pthread_detach(pthread_t t);
+int       WINPTHREAD_API pthread_setname_np(pthread_t thread, const char *name);
+int       WINPTHREAD_API pthread_getname_np(pthread_t thread, char *name, size_t len);
+
 
 int WINPTHREAD_API pthread_rwlock_init(pthread_rwlock_t *rwlock_, const pthread_rwlockattr_t *attr);
 int WINPTHREAD_API pthread_rwlock_wrlock(pthread_rwlock_t *l);
diff --git a/mingw-w64-libraries/winpthreads/src/thread.c b/mingw-w64-libraries/winpthreads/src/thread.c
index 141faf0..5c40f12 100644
--- a/mingw-w64-libraries/winpthreads/src/thread.c
+++ b/mingw-w64-libraries/winpthreads/src/thread.c
@@ -21,6 +21,7 @@
 */
 
 #include <windows.h>
+#include <strsafe.h>
 #include <stdio.h>
 #include <malloc.h>
 #include <signal.h>
@@ -52,6 +53,60 @@
 static size_t idListMax = 0;
 static pthread_t idListNextId = 0;
 
+#if !defined(_MSC_VER) || defined (USE_VEH_FOR_MSC_SETTHREADNAME)
+static void *SetThreadName_VEH_handle = NULL;
+
+static LONG __stdcall
+SetThreadName_VEH (PEXCEPTION_POINTERS ExceptionInfo)
+{
+  if (ExceptionInfo->ExceptionRecord != NULL &&
+      ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SET_THREAD_NAME)
+    return EXCEPTION_CONTINUE_EXECUTION;
+
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif
+
+typedef struct _THREADNAME_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;
+
+static void
+SetThreadName (DWORD dwThreadID, LPCSTR szThreadName)
+{
+   THREADNAME_INFO info;
+   DWORD infosize;
+
+   info.dwType = 0x1000;
+   info.szName = szThreadName;
+   info.dwThreadID = dwThreadID;
+   info.dwFlags = 0;
+
+   infosize = sizeof (info) / sizeof (DWORD);
+
+#if defined(_MSC_VER) && !defined (USE_VEH_FOR_MSC_SETTHREADNAME)
+   __try
+     {
+       RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *) &info);
+     }
+   __except (EXCEPTION_EXECUTE_HANDLER)
+     {
+     }
+#else
+   /* Without a debugger we *must* have an exception handler,
+    * otherwise raising an exception will crash the process.
+    */
+   if ((!IsDebuggerPresent ()) && (SetThreadName_VEH_handle == NULL))
+     return;
+
+   RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *) &info);
+#endif
+}
+
 /* Search the list idList for an element with identifier ID.  If
    found, its associated _pthread_v pointer is returned, otherwise
    NULL.
@@ -234,6 +289,8 @@
     free (sv->keyval);
   if (sv->keyval_set)
     free (sv->keyval_set);
+  if (sv->thread_name)
+    free (sv->thread_name);
   memset (sv, 0, sizeof(struct _pthread_v));
   if (pthr_last == NULL)
     pthr_root = pthr_last = sv;
@@ -326,8 +383,22 @@
 
   if (dwReason == DLL_PROCESS_DETACH)
     {
+#if !defined(_MSC_VER) || defined (USE_VEH_FOR_MSC_SETTHREADNAME)
+      if (lpreserved == NULL && SetThreadName_VEH_handle != NULL)
+        {
+          RemoveVectoredExceptionHandler (SetThreadName_VEH_handle);
+          SetThreadName_VEH_handle = NULL;
+        }
+#endif
       free_pthread_mem ();
     }
+  else if (dwReason == DLL_PROCESS_ATTACH)
+    {
+#if !defined(_MSC_VER) || defined (USE_VEH_FOR_MSC_SETTHREADNAME)
+      SetThreadName_VEH_handle = AddVectoredExceptionHandler (1, &SetThreadName_VEH);
+      /* Can't do anything on error anyway, check for NULL later */
+#endif
+    }
   else if (dwReason == DLL_THREAD_DETACH)
     {
       if (_pthread_tls != 0xffffffff)
@@ -1667,3 +1738,61 @@
   return 0;
 }
 
+int
+pthread_setname_np (pthread_t thread, const char *name)
+{
+  struct _pthread_v *tv;
+  char *stored_name;
+
+  if (name == NULL)
+    return EINVAL;
+
+  tv = __pth_gpointer_locked (thread);
+  if (!tv || thread != tv->x || tv->in_cancel || tv->ended || tv->h == NULL
+      || tv->h == INVALID_HANDLE_VALUE)
+    return ESRCH;
+
+  stored_name = strdup (name);
+  if (stored_name == NULL)
+    return ENOMEM;
+
+  if (tv->thread_name != NULL)
+    free (tv->thread_name);
+
+  tv->thread_name = stored_name;
+  SetThreadName (tv->tid, name);
+  return 0;
+}
+
+int
+pthread_getname_np (pthread_t thread, char *name, size_t len)
+{
+  HRESULT result;
+  struct _pthread_v *tv;
+
+  if (name == NULL)
+    return EINVAL;
+
+  tv = __pth_gpointer_locked (thread);
+  if (!tv || thread != tv->x || tv->in_cancel || tv->ended || tv->h == NULL
+      || tv->h == INVALID_HANDLE_VALUE)
+    return ESRCH;
+
+  if (len < 1)
+    return ERANGE;
+
+  if (tv->thread_name == NULL)
+    {
+      name[0] = '\0';
+      return 0;
+    }
+
+  if (strlen (tv->thread_name) >= len)
+    return ERANGE;
+
+  result = StringCchCopyNA (name, len, tv->thread_name, len - 1);
+  if (SUCCEEDED (result))
+    return 0;
+
+  return ERANGE;
+}
diff --git a/mingw-w64-libraries/winpthreads/src/thread.h b/mingw-w64-libraries/winpthreads/src/thread.h
index 07cfc24..caaf058 100644
--- a/mingw-w64-libraries/winpthreads/src/thread.h
+++ b/mingw-w64-libraries/winpthreads/src/thread.h
@@ -29,6 +29,7 @@
 
 #define LIFE_THREAD 0xBAB1F00D
 #define DEAD_THREAD 0xDEADBEEF
+#define EXCEPTION_SET_THREAD_NAME ((DWORD) 0x406D1388)
 
 typedef struct _pthread_v _pthread_v;
 struct _pthread_v
@@ -48,6 +49,7 @@
     unsigned int keymax;
     void **keyval;
     unsigned char *keyval_set;
+    char *thread_name;
     pthread_spinlock_t spin_keys;
     DWORD tid;
     int rwlc;