Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section

@@ -19,11 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
  * Copyright (c) 2017 by Delphix. All rights reserved.
  */
 
 /*      Copyright (c) 1984,      1986, 1987, 1988, 1989 AT&T    */
 /*        All Rights Reserved   */

@@ -62,10 +62,11 @@
 #include <sys/atomic.h>
 #include <sys/cmn_err.h>
 #include <sys/contract_impl.h>
 #include <sys/ctfs.h>
 #include <sys/avl.h>
+#include <sys/ctype.h>
 #include <fs/fs_subr.h>
 #include <vm/rm.h>
 #include <vm/as.h>
 #include <vm/seg.h>
 #include <vm/seg_vn.h>

@@ -181,26 +182,28 @@
                 "." },
         { PR_LWPDIR,     2 * sizeof (prdirent_t), sizeof (prdirent_t),
                 ".." },
         { PR_LWPCTL,     3 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "lwpctl" },
-        { PR_LWPSTATUS,  4 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_LWPNAME,    4 * sizeof (prdirent_t), sizeof (prdirent_t),
+                "lwpname" },
+        { PR_LWPSTATUS,  5 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "lwpstatus" },
-        { PR_LWPSINFO,   5 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_LWPSINFO,   6 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "lwpsinfo" },
-        { PR_LWPUSAGE,   6 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_LWPUSAGE,   7 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "lwpusage" },
-        { PR_XREGS,      7 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_XREGS,      8 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "xregs" },
-        { PR_TMPLDIR,    8 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_TMPLDIR,    9 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "templates" },
-        { PR_SPYMASTER,  9 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_SPYMASTER,  10 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "spymaster" },
 #if defined(__sparc)
-        { PR_GWINDOWS,  10 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_GWINDOWS,  11 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "gwindows" },
-        { PR_ASRS,      11 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_ASRS,      12 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "asrs" },
 #endif
 };
 
 #define NLWPIDDIRFILES  (sizeof (lwpiddir) / sizeof (lwpiddir[0]) - 2)

@@ -585,11 +588,12 @@
 #if defined(__x86)
         pr_read_ldt(),
 #endif
         pr_read_usage(), pr_read_lusage(), pr_read_pagedata(),
         pr_read_watch(), pr_read_lwpstatus(), pr_read_lwpsinfo(),
-        pr_read_lwpusage(), pr_read_xregs(), pr_read_priv(),
+        pr_read_lwpusage(), pr_read_lwpname(),
+        pr_read_xregs(), pr_read_priv(),
         pr_read_spymaster(), pr_read_secflags(),
 #if defined(__sparc)
         pr_read_gwindows(), pr_read_asrs(),
 #endif
         pr_read_piddir(), pr_read_pidfile(), pr_read_opagedata();

@@ -624,10 +628,11 @@
         pr_read_inval,          /* /proc/<pid>/object                   */
         pr_read_inval,          /* /proc/<pid>/object/xxx               */
         pr_read_inval,          /* /proc/<pid>/lwp                      */
         pr_read_inval,          /* /proc/<pid>/lwp/<lwpid>              */
         pr_read_inval,          /* /proc/<pid>/lwp/<lwpid>/lwpctl       */
+        pr_read_lwpname,        /* /proc/<pid>/lwp/<lwpid>/lwpname      */
         pr_read_lwpstatus,      /* /proc/<pid>/lwp/<lwpid>/lwpstatus    */
         pr_read_lwpsinfo,       /* /proc/<pid>/lwp/<lwpid>/lwpsinfo     */
         pr_read_lwpusage,       /* /proc/<pid>/lwp/<lwpid>/lwpusage     */
         pr_read_xregs,          /* /proc/<pid>/lwp/<lwpid>/xregs        */
         pr_read_inval,          /* /proc/<pid>/lwp/<lwpid>/templates    */

@@ -1071,11 +1076,11 @@
  * XX64
  *      This is almost certainly broken for the amd64 kernel, because
  *      we have two kinds of LDT structures to export -- one for compatibility
  *      mode, and one for long mode, sigh.
  *
- *      For now lets just have a ldt of size 0 for 64-bit processes.
+ *      For now let's just have a ldt of size 0 for 64-bit processes.
  */
 static int
 pr_read_ldt(prnode_t *pnp, uio_t *uiop)
 {
         proc_t *p;

@@ -1536,10 +1541,37 @@
         kmem_free(pup, sizeof (*pup));
         kmem_free(upup, sizeof (*upup));
         return (error);
 }
 
+static int
+pr_read_lwpname(prnode_t *pnp, uio_t *uiop)
+{
+        char lwpname[THREAD_NAME_MAX];
+        kthread_t *t;
+        int error;
+
+        ASSERT(pnp->pr_type == PR_LWPNAME);
+
+        if (uiop->uio_offset >= THREAD_NAME_MAX)
+                return (0);
+
+        if ((error = prlock(pnp, ZNO)) != 0)
+                return (error);
+
+        bzero(lwpname, sizeof (lwpname));
+
+        t = pnp->pr_common->prc_thread;
+
+        if (t->t_name != NULL)
+                (void) strlcpy(lwpname, t->t_name, sizeof (lwpname));
+
+        prunlock(pnp);
+
+        return (pr_uioread(lwpname, sizeof (lwpname), uiop));
+}
+
 /* ARGSUSED */
 static int
 pr_read_xregs(prnode_t *pnp, uio_t *uiop)
 {
 #if defined(__sparc)

@@ -1806,10 +1838,11 @@
         pr_read_inval,          /* /proc/<pid>/object                   */
         pr_read_inval,          /* /proc/<pid>/object/xxx               */
         pr_read_inval,          /* /proc/<pid>/lwp                      */
         pr_read_inval,          /* /proc/<pid>/lwp/<lwpid>              */
         pr_read_inval,          /* /proc/<pid>/lwp/<lwpid>/lwpctl       */
+        pr_read_lwpname,        /* /proc/<pid>/lwp/<lwpid>/lwpname      */
         pr_read_lwpstatus_32,   /* /proc/<pid>/lwp/<lwpid>/lwpstatus    */
         pr_read_lwpsinfo_32,    /* /proc/<pid>/lwp/<lwpid>/lwpsinfo     */
         pr_read_lwpusage_32,    /* /proc/<pid>/lwp/<lwpid>/lwpusage     */
         pr_read_xregs,          /* /proc/<pid>/lwp/<lwpid>/xregs        */
         pr_read_inval,          /* /proc/<pid>/lwp/<lwpid>/templates    */

@@ -2718,10 +2751,58 @@
 #else
         return (pr_read_function[pnp->pr_type](pnp, uiop));
 #endif
 }
 
+/* Note we intentionally don't handle partial writes/updates. */
+static int
+pr_write_lwpname(prnode_t *pnp, uio_t *uiop)
+{
+        kthread_t *t = NULL;
+        char *lwpname;
+        int error;
+
+        lwpname = kmem_zalloc(THREAD_NAME_MAX, KM_SLEEP);
+
+        if ((error = uiomove(lwpname, THREAD_NAME_MAX, UIO_WRITE, uiop)) != 0) {
+                kmem_free(lwpname, THREAD_NAME_MAX);
+                return (error);
+        }
+
+        /* Somebody tried to write too long a thread name... */
+        if (lwpname[THREAD_NAME_MAX - 1] != '\0' || uiop->uio_resid > 0) {
+                kmem_free(lwpname, THREAD_NAME_MAX);
+                return (EIO);
+        }
+
+        VERIFY3U(lwpname[THREAD_NAME_MAX - 1], ==, '\0');
+
+        for (size_t i = 0; lwpname[i] != '\0'; i++) {
+                if (!ISPRINT(lwpname[i])) {
+                        kmem_free(lwpname, THREAD_NAME_MAX);
+                        return (EINVAL);
+                }
+        }
+
+        /* Equivalent of thread_setname(), but with the ZNO magic. */
+        if ((error = prlock(pnp, ZNO)) != 0) {
+                kmem_free(lwpname, THREAD_NAME_MAX);
+                return (error);
+        }
+
+        t = pnp->pr_common->prc_thread;
+        if (t->t_name == NULL) {
+                t->t_name = lwpname;
+        } else {
+                (void) strlcpy(t->t_name, lwpname, THREAD_NAME_MAX);
+                kmem_free(lwpname, THREAD_NAME_MAX);
+        }
+
+        prunlock(pnp);
+        return (0);
+}
+
 /* ARGSUSED */
 static int
 prwrite(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
 {
         prnode_t *pnp = VTOP(vp);

@@ -2796,10 +2877,13 @@
                  */
                 if (error == EINTR)
                         uiop->uio_resid = resid;
                 return (error);
 
+        case PR_LWPNAME:
+                return (pr_write_lwpname(pnp, uiop));
+
         default:
                 return ((vp->v_type == VDIR)? EISDIR : EBADF);
         }
         /* NOTREACHED */
 }

@@ -3356,10 +3440,11 @@
         pr_lookup_objectdir,    /* /proc/<pid>/object                   */
         pr_lookup_notdir,       /* /proc/<pid>/object/xxx               */
         pr_lookup_lwpdir,       /* /proc/<pid>/lwp                      */
         pr_lookup_lwpiddir,     /* /proc/<pid>/lwp/<lwpid>              */
         pr_lookup_notdir,       /* /proc/<pid>/lwp/<lwpid>/lwpctl       */
+        pr_lookup_notdir,       /* /proc/<pid>/lwp/<lwpid>/lwpname      */
         pr_lookup_notdir,       /* /proc/<pid>/lwp/<lwpid>/lwpstatus    */
         pr_lookup_notdir,       /* /proc/<pid>/lwp/<lwpid>/lwpsinfo     */
         pr_lookup_notdir,       /* /proc/<pid>/lwp/<lwpid>/lwpusage     */
         pr_lookup_notdir,       /* /proc/<pid>/lwp/<lwpid>/xregs        */
         pr_lookup_tmpldir,      /* /proc/<pid>/lwp/<lwpid>/templates    */

@@ -4619,10 +4704,14 @@
         case PR_PIDFILE:
         case PR_LWPIDFILE:
                 pnp->pr_mode = 0600;    /* read-write by owner only */
                 break;
 
+        case PR_LWPNAME:
+                pnp->pr_mode = 0644;    /* readable by all + owner can write */
+                break;
+
         case PR_PSINFO:
         case PR_LPSINFO:
         case PR_LWPSINFO:
         case PR_USAGE:
         case PR_LUSAGE:

@@ -4743,10 +4832,11 @@
         pr_readdir_objectdir,   /* /proc/<pid>/object                   */
         pr_readdir_notdir,      /* /proc/<pid>/object/xxx               */
         pr_readdir_lwpdir,      /* /proc/<pid>/lwp                      */
         pr_readdir_lwpiddir,    /* /proc/<pid>/lwp/<lwpid>              */
         pr_readdir_notdir,      /* /proc/<pid>/lwp/<lwpid>/lwpctl       */
+        pr_readdir_notdir,      /* /proc/<pid>/lwp/<lwpid>/lwpname      */
         pr_readdir_notdir,      /* /proc/<pid>/lwp/<lwpid>/lwpstatus    */
         pr_readdir_notdir,      /* /proc/<pid>/lwp/<lwpid>/lwpsinfo     */
         pr_readdir_notdir,      /* /proc/<pid>/lwp/<lwpid>/lwpusage     */
         pr_readdir_notdir,      /* /proc/<pid>/lwp/<lwpid>/xregs        */
         pr_readdir_tmpldir,     /* /proc/<pid>/lwp/<lwpid>/templates    */