Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section
@@ -19,11 +19,11 @@
* CDDL HEADER END
*/
/*
* Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2018 Joyent, Inc.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysmacros.h>
@@ -72,10 +72,11 @@
#include <sys/kdi.h>
#include <sys/schedctl.h>
#include <sys/waitq.h>
#include <sys/cpucaps.h>
#include <sys/kiconv.h>
+#include <sys/ctype.h>
struct kmem_cache *thread_cache; /* cache of free threads */
struct kmem_cache *lwp_cache; /* cache of free lwps */
struct kmem_cache *turnstile_cache; /* cache of free turnstiles */
@@ -789,10 +790,15 @@
mutex_enter(&pidlock);
nthread--;
mutex_exit(&pidlock);
+ if (t->t_name != NULL) {
+ kmem_free(t->t_name, THREAD_NAME_MAX);
+ t->t_name = NULL;
+ }
+
/*
* Free thread, lwp and stack. This needs to be done carefully, since
* if T_TALLOCSTK is set, the thread is part of the stack.
*/
t->t_lwp = NULL;
@@ -2124,6 +2130,78 @@
percent = ((100 * percent) / s) + 1;
if (percent > 100) {
percent = 100;
}
return (percent);
+}
+
+/*
+ * NOTE: This will silently truncate a name > THREAD_NAME_MAX - 1 characters
+ * long. It is expected that callers (acting on behalf of userland clients)
+ * will perform any required checks to return the correct error semantics.
+ * It is also expected callers on behalf of userland clients have done
+ * any necessary permission checks.
+ */
+int
+thread_setname(kthread_t *t, const char *name)
+{
+ char *buf = NULL;
+
+ /*
+ * We optimistically assume that a thread's name will only be set
+ * once and so allocate memory in preparation of setting t_name.
+ * If it turns out a name has already been set, we just discard (free)
+ * the buffer we just allocated and reuse the current buffer
+ * (as all should be THREAD_NAME_MAX large).
+ *
+ * Such an arrangement means over the lifetime of a kthread_t, t_name
+ * is either NULL or has one value (the address of the buffer holding
+ * the current thread name). The assumption is that most kthread_t
+ * instances will not have a name assigned, so dynamically allocating
+ * the memory should minimize the footprint of this feature, but by
+ * having the buffer persist for the life of the thread, it simplifies
+ * usage in highly constrained situations (e.g. dtrace).
+ */
+ if (name != NULL && name[0] != '\0') {
+ for (size_t i = 0; name[i] != '\0'; i++) {
+ if (!isprint(name[i]))
+ return (EINVAL);
+ }
+
+ buf = kmem_zalloc(THREAD_NAME_MAX, KM_SLEEP);
+ (void) strlcpy(buf, name, THREAD_NAME_MAX);
+ }
+
+ mutex_enter(&ttoproc(t)->p_lock);
+ if (t->t_name == NULL) {
+ t->t_name = buf;
+ } else {
+ if (buf != NULL) {
+ (void) strlcpy(t->t_name, name, THREAD_NAME_MAX);
+ kmem_free(buf, THREAD_NAME_MAX);
+ } else {
+ bzero(t->t_name, THREAD_NAME_MAX);
+ }
+ }
+ mutex_exit(&ttoproc(t)->p_lock);
+ return (0);
+}
+
+int
+thread_vsetname(kthread_t *t, const char *fmt, ...)
+{
+ char name[THREAD_NAME_MAX];
+ va_list va;
+ int rc;
+
+ va_start(va, fmt);
+ rc = vsnprintf(name, sizeof (name), fmt, va);
+ va_end(va);
+
+ if (rc < 0)
+ return (EINVAL);
+
+ if (rc >= sizeof (name))
+ return (ENAMETOOLONG);
+
+ return (thread_setname(t, name));
}