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*/
34static void *
35thr(void *unused)
36{
37	(void) sleep(100);
38	return (NULL);
39}
40
41/*ARGSUSED*/
42int
43main(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