pthread: Add lwp_setname(2) and implement pthread_set_name_np(3)
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 19 Nov 2015 03:37:28 +0000 (11:37 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 19 Nov 2015 08:36:29 +0000 (16:36 +0800)
- Return thread name through kinfo.
- Show thread name in ps(1) for 'Hc'.
- Show thread name in top(1), if it is different from process name.

23 files changed:
bin/ps/extern.h
bin/ps/print.c
bin/ps/ps.c
include/unistd.h
lib/libc/sys/Makefile.inc
lib/libc/sys/Symbol.map
lib/libc/sys/lwp_setname.2 [new file with mode: 0644]
lib/libpthread/pthread_set_name_np.3
lib/libthread_xu/thread/thr_info.c
sys/kern/init_sysent.c
sys/kern/kern_kinfo.c
sys/kern/kern_prot.c
sys/kern/syscalls.c
sys/kern/syscalls.master
sys/sys/kinfo.h
sys/sys/param.h
sys/sys/syscall.h
sys/sys/syscall.mk
sys/sys/sysproto.h
sys/sys/sysunion.h
test/pthread/setname/Makefile [new file with mode: 0644]
test/pthread/setname/pthread_setname.c [new file with mode: 0644]
usr.bin/top/m_dragonfly.c

index b3190b3..565b03d 100644 (file)
@@ -40,7 +40,7 @@ struct nlist;
 struct var;
 struct varent;
 
-extern int eval, fscale, mempages, nlistread, rawcpu, cflag;
+extern int eval, fscale, mempages, nlistread, rawcpu, cflag, showtid;
 extern int sumrusage, termwidth, totwidth;
 extern int numcpus;
 extern STAILQ_HEAD(varent_head, varent) var_head;
index 2bb98d0..035c4b7 100644 (file)
 #include "ps.h"
 
 static const char *make_printable(const char *str);
+static const char *make_printable2(const char *str);
 static void put64(u_int64_t n, int w, int type);
 
+#define SHOW_THRNAME(k) \
+       (showtid && KI_PROC(k, pid) != -1 && KI_PROC(k, nthreads) > 1)
+
 void
 printheader(void)
 {
@@ -100,11 +104,24 @@ command(const KINFO *k, const struct varent *vent)
 
        if (cflag) {
                /* Don't pad the last field. */
-               if (STAILQ_NEXT(vent, link) == NULL)
-                       printf("%s", make_printable(KI_PROC(k, comm)));
-               else
-                       printf("%-*s", vent->width, 
-                               make_printable(KI_PROC(k, comm)));
+               if (STAILQ_NEXT(vent, link) == NULL) {
+                       if (SHOW_THRNAME(k)) {
+                               printf("%s/%s",
+                                   make_printable(KI_PROC(k, comm)),
+                                   make_printable2(KI_LWP(k, comm)));
+                       } else {
+                               printf("%s", make_printable(KI_PROC(k, comm)));
+                       }
+               } else {
+                       if (SHOW_THRNAME(k)) {
+                               printf("%-*s/%s", vent->width,
+                                   make_printable(KI_PROC(k, comm)),
+                                   make_printable2(KI_LWP(k, comm)));
+                       } else {
+                               printf("%-*s", vent->width, 
+                                       make_printable(KI_PROC(k, comm)));
+                       }
+               }
                return;
        }
 
@@ -163,10 +180,23 @@ void
 ucomm(const KINFO *k, const struct varent *vent)
 {
        /* Do not pad the last field */
-       if (STAILQ_NEXT(vent, link) == NULL)
-               printf("%s", make_printable(KI_PROC(k, comm)));
-       else
-               printf("%-*s", vent->width, make_printable(KI_PROC(k, comm)));
+       if (STAILQ_NEXT(vent, link) == NULL) {
+               if (SHOW_THRNAME(k)) {
+                       printf("%s/%s", make_printable(KI_PROC(k, comm)),
+                           make_printable2(KI_LWP(k, comm)));
+               } else {
+                       printf("%s", make_printable(KI_PROC(k, comm)));
+               }
+       } else {
+               if (SHOW_THRNAME(k)) {
+                       printf("%-*s/%s", vent->width,
+                           make_printable(KI_PROC(k, comm)),
+                           make_printable2(KI_LWP(k, comm)));
+               } else {
+                       printf("%-*s", vent->width,
+                           make_printable(KI_PROC(k, comm)));
+               }
+       }
 }
 
 void
@@ -711,6 +741,21 @@ make_printable(const char *str)
     return(cpy);
 }
 
+static const char *
+make_printable2(const char *str)
+{
+    static char *cpy2;
+    int len;
+
+    if (cpy2)
+       free(cpy2);
+    len = strlen(str);
+    if ((cpy2 = malloc(len * 4 + 1)) == NULL)
+       err(1, NULL);
+    strvis(cpy2, str, VIS_TAB | VIS_NL | VIS_NOSLASH);
+    return(cpy2);
+}
+
 /*
  * Output a number, divide down as needed to fit within the
  * field.  This function differs from the code used by systat
index a98a399..ea65205 100644 (file)
@@ -74,6 +74,7 @@ int   sumrusage;              /* -S */
 int    termwidth;              /* width of screen (0 == infinity) */
 int    totwidth;               /* calculated width of requested variables */
 int    numcpus;                /* hw.ncpu */
+int    showtid;                /* -H */
 
 static int needuser, needcomm, needenv;
 #if defined(LAZY_PS)
@@ -121,7 +122,7 @@ main(int argc, char **argv)
        pid_t pid;
        uid_t *uids;
        int all, ch, flag, i, fmt, ofmt, lineno, nentries, nocludge, dropgid;
-       int prtheader, wflag, what, xflg, uid, nuids, showtid;
+       int prtheader, wflag, what, xflg, uid, nuids;
        int chainflg;
        char errbuf[_POSIX2_LINE_MAX];
        const char *cp, *nlistf, *memf;
index 0df93ec..2f0aad9 100644 (file)
@@ -557,6 +557,7 @@ int  issetugid(void);
 long    lpathconf(const char *, int);
 int     lwp_create(struct lwp_params *);
 lwpid_t         lwp_gettid(void);
+int     lwp_setname(lwpid_t, const char *);
 #ifndef        _MKNOD_DECLARED
 int     mknod(const char *, mode_t, dev_t);
 #define        _MKNOD_DECLARED
index 2f5f8e1..d9df58b 100644 (file)
@@ -75,7 +75,7 @@ MAN+= _exit.2 accept.2 access.2 acct.2 adjtime.2 \
        intro.2 ioctl.2 ioprio_get.2 issetugid.2 jail.2 jail_attach.2 kill.2 \
        kldfind.2 kldfirstmod.2 kldload.2 kldnext.2 kldstat.2 kldsym.2 \
        kldunload.2 ktrace.2 kqueue.2 link.2 listen.2 lseek.2 \
-       lwp_create.2 lwp_gettid.2 lwp_kill.2 \
+       lwp_create.2 lwp_gettid.2 lwp_kill.2 lwp_setname.2 \
        madvise.2 mincore.2 minherit.2 mkdir.2 mkfifo.2 mknod.2 mlock.2 \
        mlockall.2 mmap.2 \
        modfind.2 modnext.2 modstat.2 \
index a8bf615..2d2e54e 100644 (file)
@@ -146,6 +146,7 @@ DF404.0 {
     lwp_gettid;
     lwp_kill;
     lwp_rtprio;
+    lwp_setname;
     madvise;
     mcontrol;
     mincore;
@@ -442,6 +443,7 @@ DFprivate_1.0 {
     __sys_lwp_gettid;
     __sys_lwp_kill;
     __sys_lwp_rtprio;
+    __sys_lwp_setname;
     __sys_madvise;
     __sys_mcontrol;
     __sys_mincore;
@@ -734,6 +736,7 @@ DFprivate_1.0 {
     _lwp_gettid;
     _lwp_kill;
     _lwp_rtprio;
+    _lwp_setname;
     _madvise;
     _mcontrol;
     _mincore;
diff --git a/lib/libc/sys/lwp_setname.2 b/lib/libc/sys/lwp_setname.2
new file mode 100644 (file)
index 0000000..07bc258
--- /dev/null
@@ -0,0 +1,82 @@
+.\" Copyright (c) 2015 The DragonFly Project.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to The DragonFly Project
+.\" by Sepherosa Ziehau <sepherosa@gmail.com>.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. Neither the name of The DragonFly Project nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific, prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd November 19, 2015
+.Dt LWP_SETNAME 2
+.Os
+.Sh NAME
+.Nm lwp_setname
+.Nd Change lwp name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn lwp_setname "lwpid_t tid" "const char *name"
+.Sh DESCRIPTION
+The
+.Fn lwp_setname
+system call sets the lwp name.
+The lwp is in the process calling this system call,
+and the lwp is specified by
+.Fa tid .
+If the
+.Fa name
+is
+.Dv NULL ,
+the lwp name will be set to the process name,
+which is the default name of the lwp.
+The
+.Fa name
+will be truncated,
+if it is longer than
+.Dv MAXCOMLEN .
+.Sh RETURN VALUES
+This system call returns \-1 on error and
+0 upon successful completion.
+.Sh ERRORS
+The
+.Fn lwp_setname
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa name
+parameter is outside the process's allocated address space.
+.Sh SEE ALSO
+.Xr lwp_create 2
+.Xr setproctitle 3
+.Sh HISTORY
+The
+.Fn lwp_setname
+function first appeared in
+.Dx 4.3 .
index da25119..123fa08 100644 (file)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD: src/share/man/man3/pthread_set_name_np.3,v 1.6 2007/10/22 10:08:01 ru Exp $
 .\"
-.Dd July 10, 2009
+.Dd November 19, 2015
 .Dt PTHREAD_SET_NAME_NP 3
 .Os
 .Sh NAME
@@ -45,12 +45,8 @@ function sets internal name for thread specified by
 argument to string value specified by
 .Fa name
 argument.
-.Pp
-This is a debugging interface and using it on a day-by-day basis makes
-no sense.
 .Sh ERRORS
-Because of the debugging nature of this function, all errors that may
-appear inside are silently ignored.
+All errors that may appear inside are silently ignored.
 .Sh AUTHORS
 This manual page was written by
 .An Alexey Zelkin Aq Mt phantom@FreeBSD.org .
index 01c7e8d..112ad75 100644 (file)
@@ -33,6 +33,7 @@
 #include "namespace.h"
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <pthread.h>
 #include <pthread_np.h>
 #include "un-namespace.h"
@@ -43,31 +44,19 @@ __weak_reference(_pthread_set_name_np, pthread_set_name_np);
 
 /* Set the thread name for debug. */
 void
-_pthread_set_name_np(pthread_t thread __unused, const char *name __unused)
+_pthread_set_name_np(pthread_t thread, const char *name)
 {
-#if 0
-       struct pthread *curthread = _get_curthread();
-       int ret = 0;
+       struct pthread *curthread = tls_get_curthread();
 
        if (curthread == thread) {
-               if (thr_set_name(thread->tid, name))
-                       ret = errno;
+               lwp_setname(thread->tid, name);
        } else {
                if (_thr_ref_add(curthread, thread, 0) == 0) {
                        THR_THREAD_LOCK(curthread, thread);
-                       if (thread->state != PS_DEAD) {
-                               if (thr_set_name(thread->tid, name))
-                                       ret = errno;
-                       }
+                       if (thread->state != PS_DEAD)
+                               lwp_setname(thread->tid, name);
                        THR_THREAD_UNLOCK(curthread, thread);
                        _thr_ref_delete(curthread, thread);
-               } else {
-                       ret = ESRCH;
                }
        }
-#if 0
-       /* XXX should return error code. */
-       return (ret);
-#endif
-#endif
 }
index 5868782..bc784d0 100644 (file)
@@ -567,4 +567,5 @@ struct sysent sysent[] = {
        { AS(utimensat_args), (sy_call_t *)sys_utimensat },     /* 539 = utimensat */
        { AS(futimens_args), (sy_call_t *)sys_futimens },       /* 540 = futimens */
        { AS(accept4_args), (sy_call_t *)sys_accept4 }, /* 541 = accept4 */
+       { AS(lwp_setname_args), (sy_call_t *)sys_lwp_setname }, /* 542 = lwp_setname */
 };
index 4ee9dff..26ad76e 100644 (file)
@@ -227,6 +227,7 @@ fill_kinfo_lwp(struct lwp *lwp, struct kinfo_lwp *kl)
                strncpy(kl->kl_wmesg, lwp->lwp_thread->td_wmesg, WMESGLEN);
                kl->kl_wmesg[WMESGLEN] = 0;
        }
+       strlcpy(kl->kl_comm, lwp->lwp_thread->td_comm, sizeof(kl->kl_comm));
 }
 
 /*
@@ -279,4 +280,5 @@ fill_kinfo_proc_kthread(struct thread *td, struct kinfo_proc *kp)
                strncpy(kp->kp_lwp.kl_wmesg, td->td_wmesg, WMESGLEN);
                kp->kp_lwp.kl_wmesg[WMESGLEN] = 0;
        }
+       strlcpy(kp->kp_lwp.kl_comm, td->td_comm, sizeof(kp->kp_lwp.kl_comm));
 }
index 48ecd32..ba5b3ce 100644 (file)
@@ -246,6 +246,44 @@ sys_getgroups(struct getgroups_args *uap)
        return (error);
 }
 
+int
+sys_lwp_setname(struct lwp_setname_args *uap)
+{
+       struct proc *p = curproc;
+       char comm0[MAXCOMLEN + 1];
+       const char *comm = NULL;
+       struct lwp *lp;
+       int error;
+
+       if (uap->name != NULL) {
+               error = copyinstr(uap->name, comm0, sizeof(comm0), NULL);
+               if (error) {
+                       if (error != ENAMETOOLONG)
+                               return error;
+                       /* Truncate */
+                       comm0[MAXCOMLEN] = '\0';
+               }
+               comm = comm0;
+       } else {
+               /* Restore to the default name, i.e. process name. */
+               comm = p->p_comm;
+       }
+
+       lwkt_gettoken(&p->p_token);
+
+       lp = lwp_rb_tree_RB_LOOKUP(&p->p_lwp_tree, uap->tid);
+       if (lp != NULL) {
+               strlcpy(lp->lwp_thread->td_comm, comm,
+                   sizeof(lp->lwp_thread->td_comm));
+               error = 0;
+       } else {
+               error = ESRCH;
+       }
+
+       lwkt_reltoken(&p->p_token);
+       return error;
+}
+
 int
 sys_setsid(struct setsid_args *uap)
 {
index 77d5033..f9170b8 100644 (file)
@@ -550,4 +550,5 @@ const char *syscallnames[] = {
        "utimensat",                    /* 539 = utimensat */
        "futimens",                     /* 540 = futimens */
        "accept4",                      /* 541 = accept4 */
+       "lwp_setname",                  /* 542 = lwp_setname */
 };
index 5baaaf1..11ff4d5 100644 (file)
 539    STD     { int utimensat(int fd, const char *path, const struct timespec *ts, int flags); }
 540    STD     { int futimens(int fd, const struct timespec *ts); }
 541    STD     { int accept4(int s, caddr_t name, int *anamelen, int flags); }
+542    STD     { int lwp_setname(lwpid_t tid, const char *name); }
index ddf8731..5bb82e5 100644 (file)
@@ -141,6 +141,8 @@ struct kinfo_lwp {
 #define WMESGLEN 8
        uintptr_t       kl_wchan;       /* waiting channel */
        char            kl_wmesg[WMESGLEN+1];   /* waiting message */
+
+       char            kl_comm[MAXCOMLEN+1];   /* lwp name */
 };
 
 /*
index a1eb427..ca05088 100644 (file)
  * 400306 - Add libexecinfo to base
  * 400307 - drm/i915 kernel module renamed to i915.ko
  * 400308 - <malloc.h> removal
+ * 400309 - Add lwp_setname() system call
  */
 #undef __DragonFly_version
-#define __DragonFly_version 400308     /* propagated to newvers */
+#define __DragonFly_version 400309     /* propagated to newvers */
 
 #include <sys/_null.h>
 
index a2563ee..9137581 100644 (file)
 #define        SYS_utimensat   539
 #define        SYS_futimens    540
 #define        SYS_accept4     541
-#define        SYS_MAXSYSCALL  542
+#define        SYS_lwp_setname 542
+#define        SYS_MAXSYSCALL  543
index e4ebfb3..7bc9d2d 100644 (file)
@@ -304,4 +304,5 @@ MIASM =  \
        pipe2.o \
        utimensat.o \
        futimens.o \
-       accept4.o
+       accept4.o \
+       lwp_setname.o
index eacd36f..cc2da29 100644 (file)
@@ -2308,6 +2308,13 @@ struct   accept4_args {
        int *   anamelen;       char anamelen_[PAD_(int *)];
        int     flags;  char flags_[PAD_(int)];
 };
+struct lwp_setname_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       lwpid_t tid;    char tid_[PAD_(lwpid_t)];
+       const char *    name;   char name_[PAD_(const char *)];
+};
 
 #ifdef COMPAT_43
 
@@ -2855,6 +2862,7 @@ int       sys_pipe2 (struct pipe2_args *);
 int    sys_utimensat (struct utimensat_args *);
 int    sys_futimens (struct futimens_args *);
 int    sys_accept4 (struct accept4_args *);
+int    sys_lwp_setname (struct lwp_setname_args *);
 
 #endif /* !_SYS_SYSPROTO_H_ */
 #undef PAD_
index 4692d6c..dfdecf5 100644 (file)
@@ -394,4 +394,5 @@ union sysunion {
        struct  utimensat_args utimensat;
        struct  futimens_args futimens;
        struct  accept4_args accept4;
+       struct  lwp_setname_args lwp_setname;
 };
diff --git a/test/pthread/setname/Makefile b/test/pthread/setname/Makefile
new file mode 100644 (file)
index 0000000..f712035
--- /dev/null
@@ -0,0 +1,8 @@
+PROG = pthread_setname
+WARNS = 6
+NOMAN = YES
+BINDIR=        /usr/local/bin
+
+LDADD  = -lpthread
+
+.include <bsd.prog.mk>
diff --git a/test/pthread/setname/pthread_setname.c b/test/pthread/setname/pthread_setname.c
new file mode 100644 (file)
index 0000000..baef511
--- /dev/null
@@ -0,0 +1,59 @@
+#include <err.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void *
+setselfname(void *arg __unused)
+{
+       pthread_set_name_np(pthread_self(), __func__);
+       pause();
+       return NULL;
+}
+
+static void *
+waitname(void *arg __unused)
+{
+       pause();
+       return NULL;
+}
+
+static void *
+resetname(void *arg __unused)
+{
+       pthread_set_name_np(pthread_self(), __func__);
+       sleep(10);
+       pthread_set_name_np(pthread_self(), NULL);
+       pause();
+       return NULL;
+}
+
+int
+main(void)
+{
+       pthread_t tid1, tid2, tid3;
+       char longname[256];
+       int error;
+
+       error = pthread_create(&tid1, NULL, setselfname, NULL);
+       if (error)
+               errc(1, error, "pthread_create(setselfname) failed");
+
+       error = pthread_create(&tid2, NULL, waitname, NULL);
+       if (error)
+               errc(1, error, "pthread_create(waitname) failed");
+       pthread_set_name_np(tid2, "waitname");
+
+       error = pthread_create(&tid3, NULL, resetname, NULL);
+       if (error)
+               errc(1, error, "pthread_create(resetname) failed");
+
+       memset(longname, 'x', sizeof(longname));
+       longname[sizeof(longname) - 1] = '\0';
+       pthread_set_name_np(pthread_self(), longname);
+
+       pause();
+       exit(0);
+}
index 37ac314..7c0ffed 100644 (file)
@@ -69,6 +69,7 @@ int n_cpus = 0;
 struct handle {
        struct kinfo_proc **next_proc;  /* points to next valid proc pointer */
        int remaining;          /* number of pointers remaining */
+       int show_threads;
 };
 
 /* declarations for load_avg */
@@ -624,6 +625,7 @@ get_process_info(struct system_info *si, struct process_select *sel,
        /* pass back a handle */
        handle.next_proc = pref;
        handle.remaining = active_procs;
+       handle.show_threads = show_threads;
        return ((caddr_t) & handle);
 }
 
@@ -666,9 +668,16 @@ format_next_process(caddr_t xhandle, char *(*get_userid) (int))
        if (PP(pp, flags) & P_SYSTEM) {
                /* system process */
                snprintf(cmdfield, sizeof cmdfield, "[%s]", comm);
-       } else if (LP(pp, tid) > 0) {
+       } else if (hp->show_threads && PP(pp, nthreads) > 1) {
                /* display it as a thread */
-               snprintf(cmdfield, sizeof cmdfield, "%s{%d}", comm, LP(pp, tid));
+               if (strcmp(PP(pp, comm), LP(pp, comm)) == 0) {
+                       snprintf(cmdfield, sizeof cmdfield, "%s{%d}", comm,
+                           LP(pp, tid));
+               } else {
+                       /* show thread name in addition to tid */
+                       snprintf(cmdfield, sizeof cmdfield, "%s{%d/%s}", comm,
+                           LP(pp, tid), LP(pp, comm));
+               }
        } else {
                snprintf(cmdfield, sizeof cmdfield, "%s", comm);
        }