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