1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2018 Joyent, Inc.
14  */
15 
16 /*
17  * Some basic pthread name API tests.
18  */
19 
20 #include <sys/stat.h>
21 #include <pthread.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <thread.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <err.h>
31 
32 
33 /*ARGSUSED*/
34 static void *
thr(void * unused)35 thr(void *unused)
36 {
37 	(void) sleep(100);
38 	return (NULL);
39 }
40 
41 /*ARGSUSED*/
42 int
main(int argc,char * argv[])43 main(int argc, char *argv[])
44 {
45 	char name[PTHREAD_MAX_NAMELEN_NP];
46 	pthread_attr_t attr;
47 	char path[PATH_MAX];
48 	pthread_t tid;
49 	ssize_t n;
50 	int test;
51 	int rc;
52 	int fd;
53 
54 	/* Default thread name is empty string. */
55 	test = 1;
56 
57 	rc = pthread_getname_np(pthread_self(), name, sizeof (name));
58 
59 	if (rc != 0 || strcmp(name, "") != 0)
60 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
61 
62 	/* Can set name. */
63 	test = 2;
64 
65 	(void) strlcpy(name, "main", sizeof (name));
66 	rc = pthread_setname_np(pthread_self(), name);
67 
68 	if (rc != 0)
69 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
70 
71 	rc = pthread_getname_np(pthread_self(), name, sizeof (name));
72 
73 	if (rc != 0 || strcmp(name, "main") != 0)
74 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
75 
76 	/* ERANGE check. */
77 	test = 3;
78 
79 	rc = pthread_getname_np(pthread_self(), name, 2);
80 
81 	if (rc != ERANGE)
82 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
83 
84 	/* EINVAL check. */
85 	test = 4;
86 
87 	rc = pthread_getname_np(pthread_self(), NULL, sizeof (name));
88 
89 	if (rc != EINVAL)
90 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
91 
92 	/* can clear thread name. */
93 	test = 5;
94 
95 	rc = pthread_setname_np(pthread_self(), NULL);
96 
97 	if (rc != 0)
98 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
99 
100 	rc = pthread_getname_np(pthread_self(), name, sizeof (name));
101 
102 	if (rc != 0 || strcmp(name, "") != 0)
103 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
104 
105 	/* non-existent thread check. */
106 	test = 6;
107 
108 	rc = pthread_getname_np(808, name, sizeof (name));
109 
110 	if (rc != ESRCH)
111 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
112 
113 	rc = pthread_setname_np(808, "state");
114 
115 	if (rc != ESRCH)
116 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
117 
118 	/* too long a name. */
119 	test = 7;
120 
121 	rc = pthread_setname_np(pthread_self(),
122 	    "12345678901234567890123456789012");
123 
124 	if (rc != ERANGE)
125 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
126 
127 	/* can name another thread. */
128 	test = 8;
129 
130 	rc = pthread_create(&tid, NULL, thr, NULL);
131 
132 	if (rc != 0)
133 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
134 
135 	rc = pthread_setname_np(tid, "otherthread");
136 
137 	if (rc != 0)
138 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
139 
140 	/* attr tests. */
141 	test = 9;
142 
143 	(void) pthread_attr_init(&attr);
144 
145 	rc = pthread_attr_setname_np(&attr,
146 	    "12345678901234567890123456789012");
147 
148 	if (rc != ERANGE)
149 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
150 
151 	rc = pthread_attr_setname_np(&attr, "thread2");
152 
153 	if (rc != 0)
154 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
155 
156 	rc = pthread_attr_getname_np(&attr, NULL, sizeof (name));
157 
158 	if (rc != EINVAL)
159 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
160 
161 	rc = pthread_attr_getname_np(&attr, name, 2);
162 
163 	if (rc != ERANGE)
164 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
165 
166 	/* does the attr actually apply? */
167 	test = 10;
168 
169 	rc = pthread_create(&tid, &attr, thr, NULL);
170 
171 	if (rc != 0)
172 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
173 
174 	rc = pthread_getname_np(tid, name, sizeof (name));
175 
176 	if (rc != 0 || strcmp(name, "thread2") != 0)
177 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
178 
179 	/* proc read tests */
180 	test = 11;
181 
182 	(void) snprintf(path, sizeof (path),
183 	    "/proc/self/lwp/%d/lwpname", (int)tid);
184 
185 	fd = open(path, O_RDWR);
186 
187 	if (fd == -1)
188 		errx(EXIT_FAILURE, "test %d failed with %d", test, errno);
189 
190 	n = read(fd, name, sizeof (name));
191 
192 	if (n != sizeof (name) || strcmp(name, "thread2") != 0)
193 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
194 
195 	if (lseek(fd, 0, SEEK_SET) != 0)
196 		errx(EXIT_FAILURE, "test %d failed with %d", test, errno);
197 
198 	n = read(fd, name, PTHREAD_MAX_NAMELEN_NP * 2);
199 
200 	if (n != sizeof (name) || strcmp(name, "thread2") != 0)
201 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
202 
203 	if (lseek(fd, 0, SEEK_SET) != 0)
204 		errx(EXIT_FAILURE, "test %d failed with %d", test, errno);
205 
206 	n = read(fd, name, 4);
207 
208 	if (n != 4 || strncmp(name, "thre", 4) != 0)
209 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
210 
211 	/* proc write tests */
212 	test = 12;
213 
214 	if (lseek(fd, 0, SEEK_SET) != 0)
215 		errx(EXIT_FAILURE, "test %d failed with %d", test, errno);
216 
217 	n = write(fd, "1234567890123456789012345678901",
218 	    PTHREAD_MAX_NAMELEN_NP);
219 
220 	if (n != PTHREAD_MAX_NAMELEN_NP)
221 		errx(EXIT_FAILURE, "test %d failed with %d", test, errno);
222 
223 	if (lseek(fd, 0, SEEK_SET) != 0)
224 		errx(EXIT_FAILURE, "test %d failed with %d", test, errno);
225 
226 	n = write(fd, "foo", sizeof ("foo"));
227 
228 	if (n != sizeof ("foo"))
229 		errx(EXIT_FAILURE, "test %d failed with %d", test, errno);
230 
231 	if (lseek(fd, 0, SEEK_SET) != 0)
232 		errx(EXIT_FAILURE, "test %d failed with %d", test, errno);
233 
234 	n = read(fd, name, sizeof (name));
235 
236 	if (n != sizeof (name) || strcmp(name, "foo") != 0)
237 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
238 
239 	(void) close(fd);
240 
241 	/* thr_* API. */
242 	test = 13;
243 
244 	rc = thr_setname(thr_self(), "main");
245 
246 	if (rc != 0)
247 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
248 
249 	rc = thr_getname(thr_self(), name, sizeof (name));
250 
251 	if (rc != 0 || strcmp(name, "main") != 0)
252 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
253 
254 	/* badness */
255 	test = 14;
256 
257 	rc = thr_setname(thr_self(), "\033]0;messeduptitle\a");
258 
259 	if (rc != EINVAL)
260 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
261 
262 	rc = thr_setname(thr_self(), "ab\177\177\n");
263 
264 	if (rc != EINVAL)
265 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
266 
267 	rc = pthread_attr_setname_np(&attr, "\033]0;messeduptitle\a");
268 
269 	if (rc != EINVAL)
270 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
271 
272 	rc = pthread_attr_setname_np(&attr, "ab\177\177\n");
273 
274 	if (rc != EINVAL)
275 		errx(EXIT_FAILURE, "test %d failed with %d", test, rc);
276 
277 	return (EXIT_SUCCESS);
278 }
279