summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/disp/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/disp/thread.c')
-rw-r--r--usr/src/uts/common/disp/thread.c80
1 files changed, 79 insertions, 1 deletions
diff --git a/usr/src/uts/common/disp/thread.c b/usr/src/uts/common/disp/thread.c
index f2685af534..854b33798d 100644
--- a/usr/src/uts/common/disp/thread.c
+++ b/usr/src/uts/common/disp/thread.c
@@ -21,7 +21,7 @@
/*
* 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>
@@ -74,6 +74,7 @@
#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 */
@@ -791,6 +792,11 @@ thread_free(kthread_t *t)
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.
@@ -2127,3 +2133,75 @@ stkinfo_percent(caddr_t t_stk, caddr_t t_stkbase, caddr_t sp)
}
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));
+}