1 #include "test/jemalloc_test.h"
2 
3 #ifdef JEMALLOC_PROF
4 const char *malloc_conf = "prof:true,prof_active:false";
5 #endif
6 
7 static void
mallctl_thread_name_get_impl(const char * thread_name_expected,const char * func,int line)8 mallctl_thread_name_get_impl(const char *thread_name_expected, const char *func,
9     int line)
10 {
11 	const char *thread_name_old;
12 	size_t sz;
13 
14 	sz = sizeof(thread_name_old);
15 	assert_d_eq(mallctl("thread.prof.name", &thread_name_old, &sz, NULL, 0),
16 	    0, "%s():%d: Unexpected mallctl failure reading thread.prof.name",
17 	    func, line);
18 	assert_str_eq(thread_name_old, thread_name_expected,
19 	    "%s():%d: Unexpected thread.prof.name value", func, line);
20 }
21 #define	mallctl_thread_name_get(a)					\
22 	mallctl_thread_name_get_impl(a, __func__, __LINE__)
23 
24 static void
mallctl_thread_name_set_impl(const char * thread_name,const char * func,int line)25 mallctl_thread_name_set_impl(const char *thread_name, const char *func,
26     int line)
27 {
28 
29 	assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name,
30 	    sizeof(thread_name)), 0,
31 	    "%s():%d: Unexpected mallctl failure reading thread.prof.name",
32 	    func, line);
33 	mallctl_thread_name_get_impl(thread_name, func, line);
34 }
35 #define	mallctl_thread_name_set(a)					\
36 	mallctl_thread_name_set_impl(a, __func__, __LINE__)
37 
TEST_BEGIN(test_prof_thread_name_validation)38 TEST_BEGIN(test_prof_thread_name_validation)
39 {
40 	const char *thread_name;
41 
42 	test_skip_if(!config_prof);
43 
44 	mallctl_thread_name_get("");
45 	mallctl_thread_name_set("hi there");
46 
47 	/* NULL input shouldn't be allowed. */
48 	thread_name = NULL;
49 	assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name,
50 	    sizeof(thread_name)), EFAULT,
51 	    "Unexpected mallctl result writing \"%s\" to thread.prof.name",
52 	    thread_name);
53 
54 	/* '\n' shouldn't be allowed. */
55 	thread_name = "hi\nthere";
56 	assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name,
57 	    sizeof(thread_name)), EFAULT,
58 	    "Unexpected mallctl result writing \"%s\" to thread.prof.name",
59 	    thread_name);
60 
61 	/* Simultaneous read/write shouldn't be allowed. */
62 	{
63 		const char *thread_name_old;
64 		size_t sz;
65 
66 		sz = sizeof(thread_name_old);
67 		assert_d_eq(mallctl("thread.prof.name", &thread_name_old, &sz,
68 		    &thread_name, sizeof(thread_name)), EPERM,
69 		    "Unexpected mallctl result writing \"%s\" to "
70 		    "thread.prof.name", thread_name);
71 	}
72 
73 	mallctl_thread_name_set("");
74 }
75 TEST_END
76 
77 #define	NTHREADS	4
78 #define	NRESET		25
79 static void *
thd_start(void * varg)80 thd_start(void *varg)
81 {
82 	unsigned thd_ind = *(unsigned *)varg;
83 	char thread_name[16] = "";
84 	unsigned i;
85 
86 	malloc_snprintf(thread_name, sizeof(thread_name), "thread %u", thd_ind);
87 
88 	mallctl_thread_name_get("");
89 	mallctl_thread_name_set(thread_name);
90 
91 	for (i = 0; i < NRESET; i++) {
92 		assert_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0,
93 		    "Unexpected error while resetting heap profile data");
94 		mallctl_thread_name_get(thread_name);
95 	}
96 
97 	mallctl_thread_name_set(thread_name);
98 	mallctl_thread_name_set("");
99 
100 	return (NULL);
101 }
102 
TEST_BEGIN(test_prof_thread_name_threaded)103 TEST_BEGIN(test_prof_thread_name_threaded)
104 {
105 	thd_t thds[NTHREADS];
106 	unsigned thd_args[NTHREADS];
107 	unsigned i;
108 
109 	test_skip_if(!config_prof);
110 
111 	for (i = 0; i < NTHREADS; i++) {
112 		thd_args[i] = i;
113 		thd_create(&thds[i], thd_start, (void *)&thd_args[i]);
114 	}
115 	for (i = 0; i < NTHREADS; i++)
116 		thd_join(thds[i], NULL);
117 }
118 TEST_END
119 #undef NTHREADS
120 #undef NRESET
121 
122 int
main(void)123 main(void)
124 {
125 
126 	return (test(
127 	    test_prof_thread_name_validation,
128 	    test_prof_thread_name_threaded));
129 }
130