This patchset adds pthread_getname_np and pthread_setname_np.  These
were added to glibc in 2.12[1] and are also present in some form on
NetBSD and several UNIXes.  IIUC recent versions of GDB can benefit from
this support.

The code is based on NetBSD's implementation with changes to better
match Linux behaviour.  It does differ from Linux in two points:

* The thread name is not affected by changing __progname (or
program_invocation_short_name on Linux).  I used the latter because it
is cheaper than the pinfo->progname dance (e.g. in
format_process_stat()).

* pthread_setname_np(thr, NULL) segfaults on Linux (and NetBSD), but our
snprintf is apparently more robust and treats it as an empty string.

I'll leave it up to you to decide if either of these matter.

I implemented this via class pthread_attr to make it easier to add
pthread_attr_[gs]etname_np (present in NetBSD and some UNIXes) should it
ever be added to Linux (or we decide we want it anyway).

Patches and test code attached.


Yaakov

[1] http://sourceware.org/git/?p=glibc.git;a=blob;f=NEWS
2012-02-??  Yaakov Selkowitz  <yselkowitz@...>

	* cygwin.din (pthread_getname_np): Export.
	(pthread_setname_np): Export.
	* posix.sgml (std-gnu): Add pthread_getname_np and pthread_setname_np.
	* thread.cc (pthread_attr::pthread_attr): Initialize name element.
	(pthread_getname_np): New function.
	(pthread_setname_np): New function.
	* thread.h (class pthread_attr): Add name element.
	* include/pthread.h (pthread_getname_np): Declare.
	(pthread_setname_np): Declare.
	* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.

Index: cygwin.din
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygwin.din,v
retrieving revision 1.254
diff -u -p -r1.254 cygwin.din
--- cygwin.din	22 Feb 2012 01:58:24 -0000	1.254
+++ cygwin.din	23 Feb 2012 06:27:21 -0000
@@ -1226,6 +1226,7 @@ pthread_exit SIGFE
 pthread_getattr_np SIGFE
 pthread_getconcurrency SIGFE
 pthread_getcpuclockid SIGFE
+pthread_getname_np SIGFE
 pthread_getschedparam SIGFE
 pthread_getsequence_np SIGFE
 pthread_getspecific SIGFE
@@ -1266,6 +1267,7 @@ pthread_self SIGFE
 pthread_setcancelstate SIGFE
 pthread_setcanceltype SIGFE
 pthread_setconcurrency SIGFE
+pthread_setname_np SIGFE
 pthread_setschedparam SIGFE
 pthread_setschedprio SIGFE
 pthread_setspecific SIGFE
Index: posix.sgml
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/posix.sgml,v
retrieving revision 1.76
diff -u -p -r1.76 posix.sgml
--- posix.sgml	22 Feb 2012 01:58:24 -0000	1.76
+++ posix.sgml	23 Feb 2012 06:27:21 -0000
@@ -1133,6 +1133,8 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008)
     pow10f
     ppoll
     pthread_getattr_np
+    pthread_getname_np
+    pthread_setname_np
     pthread_sigqueue
     ptsname_r
     removexattr
Index: thread.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.cc,v
retrieving revision 1.256
diff -u -p -r1.256 thread.cc
--- thread.cc	14 Feb 2012 09:45:21 -0000	1.256
+++ thread.cc	23 Feb 2012 06:27:22 -0000
@@ -27,6 +27,7 @@ details. */
 #include "miscfuncs.h"
 #include "path.h"
 #include <stdlib.h>
+#include <stdio.h>
 #include "sigproc.h"
 #include "fhandler.h"
 #include "dtable.h"
@@ -1124,7 +1125,8 @@ pthread::resume ()
 pthread_attr::pthread_attr ():verifyable_object (PTHREAD_ATTR_MAGIC),
 joinable (PTHREAD_CREATE_JOINABLE), contentionscope (PTHREAD_SCOPE_PROCESS),
 inheritsched (PTHREAD_INHERIT_SCHED), stackaddr (NULL),
-stacksize (PTHREAD_DEFAULT_STACKSIZE), guardsize (PTHREAD_DEFAULT_GUARDSIZE)
+stacksize (PTHREAD_DEFAULT_STACKSIZE), guardsize (PTHREAD_DEFAULT_GUARDSIZE),
+name (NULL)
 {
   schedparam.sched_priority = 0;
 }
@@ -2547,6 +2549,55 @@ pthread_getattr_np (pthread_t thread, pt
   return 0;
 }
 
+#define NAMELEN 16
+
+extern "C" int
+pthread_getname_np (pthread_t thread, char *buf, size_t buflen)
+{
+  if (!pthread::is_good_object (&thread))
+    return ESRCH;
+  if (buflen < NAMELEN)
+    return ERANGE;
+
+  myfault efault;
+  if (efault.faulted ())
+    return EFAULT;
+
+  if (!thread->attr.name)
+    strlcpy (buf, program_invocation_short_name, NAMELEN);
+  else
+    strlcpy (buf, thread->attr.name, NAMELEN);
+  return 0;
+}
+
+extern "C" int
+pthread_setname_np (pthread_t thread, const char *name)
+{
+  int namelen;
+  char *oldname, *cp, newname[NAMELEN];
+
+  if (!pthread::is_good_object (&thread))
+    return ESRCH;
+
+  namelen = snprintf(newname, NAMELEN, name);
+  if (namelen >= NAMELEN)
+    return ERANGE;
+
+  cp = strdup(newname);
+  if (!cp)
+    return ENOMEM;
+
+  oldname = thread->attr.name;
+  thread->attr.name = cp;
+
+  if (oldname)
+    free(oldname);
+
+  return 0;
+}
+
+#undef NAMELEN
+
 /* provided for source level compatability.
    See http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.html
 */
Index: thread.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.h,v
retrieving revision 1.127
diff -u -p -r1.127 thread.h
--- thread.h	13 Feb 2012 13:12:37 -0000	1.127
+++ thread.h	23 Feb 2012 06:27:22 -0000
@@ -261,6 +261,7 @@ public:
   void *stackaddr;
   size_t stacksize;
   size_t guardsize;
+  char *name;
 
   pthread_attr ();
   ~pthread_attr ();
Index: include/pthread.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/pthread.h,v
retrieving revision 1.36
diff -u -p -r1.36 pthread.h
--- include/pthread.h	13 Feb 2012 01:46:46 -0000	1.36
+++ include/pthread.h	23 Feb 2012 06:27:22 -0000
@@ -203,6 +199,8 @@ void pthread_testcancel (void);
 /* Non posix calls */
 
 int pthread_getattr_np (pthread_t, pthread_attr_t *);
+int pthread_getname_np (pthread_t, char *, size_t) __attribute__((nonnull(2)));
+int pthread_setname_np (pthread_t, const char *) __attribute__((nonnull(2)));
 int pthread_sigqueue (pthread_t *, int, const union sigval);
 int pthread_suspend (pthread_t);
 int pthread_continue (pthread_t);
Index: include/cygwin/version.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/version.h,v
retrieving revision 1.364
diff -u -p -r1.364 version.h
--- include/cygwin/version.h	22 Feb 2012 01:58:24 -0000	1.364
+++ include/cygwin/version.h	23 Feb 2012 06:27:22 -0000
@@ -429,12 +429,13 @@ details. */
       258: Export get_current_dir_name.
       259: Export pthread_sigqueue.
       260: Export scandirat.
+      261: Export pthread_getname_np, pthread_setname_np.
      */
 
      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 260
+#define CYGWIN_VERSION_API_MINOR 261
 
      /* There is also a compatibity version number associated with the
 	shared memory regions.  It is incremented when incompatible
Index: release/1.7.11
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/release/1.7.11,v
retrieving revision 1.3
diff -u -p -r1.3 1.7.11
--- release/1.7.11	22 Feb 2012 02:07:07 -0000	1.3
+++ release/1.7.11	24 Feb 2012 03:10:38 -0000
@@ -1,7 +1,7 @@
 What's new:
 -----------
 
-- New API: scandirat.
+- New API: pthread_getname_np, pthread_setname_np, scandirat.
 
 
 What changed:
2012-02-??  Yaakov Selkowitz  <yselkowitz@...>

	* new-features.sgml (ov-new1.7.11): Document pthread_getname_np
	and pthread_setname_np.

Index: new-features.sgml
===================================================================
RCS file: /cvs/src/src/winsup/doc/new-features.sgml,v
retrieving revision 1.102
diff -u -p -r1.102 new-features.sgml
--- new-features.sgml	22 Feb 2012 02:06:15 -0000	1.102
+++ new-features.sgml	24 Feb 2012 03:18:05 -0000
@@ -5,7 +5,7 @@
 <itemizedlist mark="bullet">
 
 <listitem><para>
-New API: scandirat.
+New API: pthread_getname_np, pthread_setname_np, scandirat.
 </para></listitem>
 
 </itemizedlist>
/*
 * The _np isn't a joke, this really isn't portable:
 * IBM i, MKS: both functions take two arguments
 * NetBSD, Tru64, VMS: both functions take three arguments
 * QNX, Linux: getname takes three arguments, setname takes two
 *
 * Obviously I could only test with Linux and NetBSD, and my patch
 * tries to follow Linux behaviour:
 * - default thread name: empty on NetBSD, exe name on Linux/Cygwin
 * - program_invocation_short_name and __progname have no effect on NetBSD
 *   or Linux, but does on Cygwin
 * - max name length: 32 on NetBSD (EINVAL), 16 on Linux/Cygwin (ERANGE)
 * - getname with NULL buffer: SEGV on NetBSD, EFAULT on Linux/Cygwin.
 * - setname with NULL string: SEGV on NetBSD/Linux, "" on Cygwin.
 *
 * cc -pthread -o pthread-getname-test pthread-getname-test.c
 */

#define _GNU_SOURCE
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __CYGWIN__
#include <dlfcn.h>
#include <cygwin/version.h>
#endif

extern char *__progname;

#ifdef __NetBSD__
/* setname takes three arguments */
#define THIRDARG , 0
#else
#define THIRDARG
#endif

#ifdef PTHREAD_MAX_NAMELEN_NP  // e.g. NetBSD
#define NAMELEN PTHREAD_MAX_NAMELEN_NP
#else
#define NAMELEN 16
#endif

int
main(void)
{
#if defined(__CYGWIN__) && CYGWIN_VERSION_API_MINOR < 261
  void *libc = dlopen ("cygwin1.dll", 0);
  int (*pthread_getname_np) (pthread_t, char *, size_t) = dlsym (libc, "pthread_getname_np");
  int (*pthread_setname_np) (pthread_t, const char *) = dlsym (libc, "pthread_setname_np");
#endif

  char *buf = (char *) malloc (NAMELEN);
  pthread_t thr = pthread_self ();
  int ret;

#ifndef __NetBSD__ // segfaults
  ret = pthread_getname_np (thr, NULL, NAMELEN-1); // null buffer and too short
  printf ("getname_np: %s\n", strerror (ret));

  ret = pthread_getname_np (thr, NULL, NAMELEN); // null buffer
  printf ("getname_np: %s\n", strerror (ret));
#endif

  ret = pthread_getname_np (thr, buf, NAMELEN-1); // too short
  printf ("getname_np: %s\n", strerror (ret));

  ret = pthread_getname_np (thr, buf, NAMELEN); // just right
  printf ("getname_np: %s: '%s'\n", strerror (ret), buf);

#ifndef __NetBSD__  // GNU extension
  program_invocation_short_name = "foobar";
  ret = pthread_getname_np (thr, buf, NAMELEN); // no effect
  printf ("getname_np: %s: '%s'\n", strerror (ret), buf);
#endif

  __progname = "foobar";
  ret = pthread_getname_np (thr, buf, NAMELEN); // no effect
  printf ("getname_np: %s: '%s'\n", strerror (ret), buf);

#if !defined(__GLIBC__) && !defined(__NetBSD__) // segfaults
  ret = pthread_setname_np (thr, NULL); // null string
  printf ("setname_np: %s\n", strerror (ret));
  ret = pthread_getname_np (thr, buf, NAMELEN);
  printf ("getname_np: %s: '%s'\n", strerror (ret), buf);
#endif

  ret = pthread_setname_np (thr, "" THIRDARG); // empty string
  printf ("setname_np: %s\n", strerror (ret));
  ret = pthread_getname_np (thr, buf, NAMELEN);
  printf ("getname_np: %s: '%s'\n", strerror (ret), buf);

  ret = pthread_setname_np (thr, "12345678901234567890123456789012" THIRDARG); // too long
  printf ("setname_np: %s\n", strerror (ret));
  ret = pthread_getname_np (thr, buf, NAMELEN);  // Linux: still empty
  printf ("getname_np: %s: '%s'\n", strerror (ret), buf);

  ret = pthread_setname_np (thr, "123456789012345" THIRDARG); // just right for all
  printf ("setname_np: %s\n", strerror (ret));
  ret = pthread_getname_np (thr, buf, NAMELEN);
  printf ("getname_np: %s: '%s'\n", strerror (ret), buf);

  return 0;
}

Reply via email to