Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libc/port/threads/pthr_attr.c
+++ new/usr/src/lib/libc/port/threads/pthr_attr.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 - * Copyright 2015, Joyent, Inc.
28 + * Copyright 2018, Joyent, Inc.
29 29 */
30 30
31 31 #include "lint.h"
32 32 #include "thr_uberdata.h"
33 +#include <sys/ctype.h>
34 +#include <strings.h>
33 35 #include <sched.h>
34 36
35 37 /*
36 38 * Default attribute object for pthread_create() with NULL attr pointer.
37 39 * Note that the 'guardsize' field is initialized on the first call.
38 40 */
39 41 const thrattr_t *
40 42 def_thrattr(void)
41 43 {
42 44 static thrattr_t thrattr = {
43 45 0, /* stksize */
44 46 NULL, /* stkaddr */
45 47 PTHREAD_CREATE_JOINABLE, /* detachstate */
46 48 PTHREAD_CREATE_NONDAEMON_NP, /* daemonstate */
47 49 PTHREAD_SCOPE_PROCESS, /* scope */
48 50 0, /* prio */
49 51 SCHED_OTHER, /* policy */
50 52 PTHREAD_INHERIT_SCHED, /* inherit */
51 - 0 /* guardsize */
53 + 0, /* guardsize */
54 + { 0 } /* name */
52 55 };
53 56 if (thrattr.guardsize == 0)
54 57 thrattr.guardsize = _sysconf(_SC_PAGESIZE);
55 58 return (&thrattr);
56 59 }
57 60
58 61 /*
59 62 * pthread_attr_init: allocates the attribute object and initializes it
60 63 * with the default values.
61 64 */
62 65 #pragma weak _pthread_attr_init = pthread_attr_init
63 66 int
64 67 pthread_attr_init(pthread_attr_t *attr)
65 68 {
66 69 thrattr_t *ap;
67 70
68 71 if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
69 72 *ap = *def_thrattr();
70 73 attr->__pthread_attrp = ap;
71 74 return (0);
72 75 }
73 76 return (ENOMEM);
74 77 }
75 78
76 79 /*
77 80 * pthread_attr_destroy: frees the attribute object and invalidates it
78 81 * with NULL value.
79 82 */
80 83 int
81 84 pthread_attr_destroy(pthread_attr_t *attr)
82 85 {
83 86 if (attr == NULL || attr->__pthread_attrp == NULL)
84 87 return (EINVAL);
85 88 lfree(attr->__pthread_attrp, sizeof (thrattr_t));
86 89 attr->__pthread_attrp = NULL;
87 90 return (0);
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
88 91 }
89 92
90 93 /*
91 94 * pthread_attr_clone: make a copy of a pthread_attr_t.
92 95 */
93 96 int
94 97 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
95 98 {
96 99 thrattr_t *ap;
97 100 const thrattr_t *old_ap =
98 - old_attr? old_attr->__pthread_attrp : def_thrattr();
101 + old_attr ? old_attr->__pthread_attrp : def_thrattr();
99 102
100 103 if (old_ap == NULL)
101 104 return (EINVAL);
102 105 if ((ap = lmalloc(sizeof (thrattr_t))) == NULL)
103 106 return (ENOMEM);
104 107 *ap = *old_ap;
105 108 attr->__pthread_attrp = ap;
106 109 return (0);
107 110 }
108 111
109 112 /*
110 113 * pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal.
111 114 * A NULL pthread_attr_t pointer implies default attributes.
112 115 * This is a consolidation-private interface, for librt.
113 116 */
114 117 int
115 118 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
116 119 {
117 - const thrattr_t *ap1 = attr1? attr1->__pthread_attrp : def_thrattr();
118 - const thrattr_t *ap2 = attr2? attr2->__pthread_attrp : def_thrattr();
120 + const thrattr_t *ap1 = attr1 ? attr1->__pthread_attrp : def_thrattr();
121 + const thrattr_t *ap2 = attr2 ? attr2->__pthread_attrp : def_thrattr();
119 122
120 123 if (ap1 == NULL || ap2 == NULL)
121 124 return (0);
122 125 return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
123 126 }
124 127
125 128 /*
126 129 * pthread_attr_setstacksize: sets the user stack size, minimum should
127 130 * be PTHREAD_STACK_MIN (MINSTACK).
128 131 * This is equivalent to stksize argument in thr_create().
129 132 */
130 133 int
131 134 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
132 135 {
133 136 thrattr_t *ap;
134 137
135 138 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
136 139 stacksize >= MINSTACK) {
137 140 ap->stksize = stacksize;
138 141 return (0);
139 142 }
140 143 return (EINVAL);
141 144 }
142 145
143 146 /*
144 147 * pthread_attr_getstacksize: gets the user stack size.
145 148 */
146 149 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
147 150 int
148 151 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
149 152 {
150 153 thrattr_t *ap;
151 154
152 155 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
153 156 stacksize != NULL) {
154 157 *stacksize = ap->stksize;
155 158 return (0);
156 159 }
157 160 return (EINVAL);
158 161 }
159 162
160 163 /*
161 164 * pthread_attr_setstackaddr: sets the user stack addr.
162 165 * This is equivalent to stkaddr argument in thr_create().
163 166 */
164 167 int
165 168 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
166 169 {
167 170 thrattr_t *ap;
168 171
169 172 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
170 173 ap->stkaddr = stackaddr;
171 174 return (0);
172 175 }
173 176 return (EINVAL);
174 177 }
175 178
176 179 /*
177 180 * pthread_attr_getstackaddr: gets the user stack addr.
178 181 */
179 182 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
180 183 int
181 184 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
182 185 {
183 186 thrattr_t *ap;
184 187
185 188 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
186 189 stackaddr != NULL) {
187 190 *stackaddr = ap->stkaddr;
188 191 return (0);
189 192 }
190 193 return (EINVAL);
191 194 }
192 195
193 196 /*
194 197 * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
195 198 * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
196 199 */
197 200 int
198 201 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
199 202 {
200 203 thrattr_t *ap;
201 204
202 205 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
203 206 (detachstate == PTHREAD_CREATE_DETACHED ||
204 207 detachstate == PTHREAD_CREATE_JOINABLE)) {
205 208 ap->detachstate = detachstate;
206 209 return (0);
207 210 }
208 211 return (EINVAL);
209 212 }
210 213
211 214 /*
212 215 * pthread_attr_getdetachstate: gets the detach state.
213 216 */
214 217 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
215 218 int
216 219 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
217 220 {
218 221 thrattr_t *ap;
219 222
220 223 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
221 224 detachstate != NULL) {
222 225 *detachstate = ap->detachstate;
223 226 return (0);
224 227 }
225 228 return (EINVAL);
226 229 }
227 230
228 231 /*
229 232 * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON.
230 233 * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON).
231 234 * For now, this is a private interface in libc.
232 235 */
233 236 int
234 237 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
235 238 {
236 239 thrattr_t *ap;
237 240
238 241 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
239 242 (daemonstate == PTHREAD_CREATE_DAEMON_NP ||
240 243 daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) {
241 244 ap->daemonstate = daemonstate;
242 245 return (0);
243 246 }
244 247 return (EINVAL);
245 248 }
246 249
247 250 /*
248 251 * pthread_attr_getdaemonstate_np: gets the daemon state.
249 252 * For now, this is a private interface in libc, but it is exposed in the
250 253 * mapfile for the purposes of testing only.
251 254 */
252 255 int
253 256 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
254 257 {
255 258 thrattr_t *ap;
256 259
257 260 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
258 261 daemonstate != NULL) {
259 262 *daemonstate = ap->daemonstate;
260 263 return (0);
261 264 }
262 265 return (EINVAL);
263 266 }
264 267
265 268 /*
266 269 * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
267 270 * This is equivalent to setting THR_BOUND flag in thr_create().
268 271 */
269 272 int
270 273 pthread_attr_setscope(pthread_attr_t *attr, int scope)
271 274 {
272 275 thrattr_t *ap;
273 276
274 277 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
275 278 (scope == PTHREAD_SCOPE_SYSTEM ||
276 279 scope == PTHREAD_SCOPE_PROCESS)) {
277 280 ap->scope = scope;
278 281 return (0);
279 282 }
280 283 return (EINVAL);
281 284 }
282 285
283 286 /*
284 287 * pthread_attr_getscope: gets the scheduling scope.
285 288 */
286 289 #pragma weak _pthread_attr_getscope = pthread_attr_getscope
287 290 int
288 291 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
289 292 {
290 293 thrattr_t *ap;
291 294
292 295 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
293 296 scope != NULL) {
294 297 *scope = ap->scope;
295 298 return (0);
296 299 }
297 300 return (EINVAL);
298 301 }
299 302
300 303 /*
301 304 * pthread_attr_setinheritsched: sets the scheduling parameters to be
302 305 * EXPLICIT or INHERITED from parent thread.
303 306 */
304 307 int
305 308 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
306 309 {
307 310 thrattr_t *ap;
308 311
309 312 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
310 313 (inherit == PTHREAD_EXPLICIT_SCHED ||
311 314 inherit == PTHREAD_INHERIT_SCHED)) {
312 315 ap->inherit = inherit;
313 316 return (0);
314 317 }
315 318 return (EINVAL);
316 319 }
317 320
318 321 /*
319 322 * pthread_attr_getinheritsched: gets the scheduling inheritance.
320 323 */
321 324 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
322 325 int
323 326 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
324 327 {
325 328 thrattr_t *ap;
326 329
327 330 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
328 331 inherit != NULL) {
329 332 *inherit = ap->inherit;
330 333 return (0);
331 334 }
332 335 return (EINVAL);
333 336 }
334 337
335 338 /*
336 339 * pthread_attr_setschedpolicy: sets the scheduling policy.
337 340 */
338 341 int
339 342 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
340 343 {
341 344 thrattr_t *ap;
342 345
343 346 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
344 347 policy != SCHED_SYS && get_info_by_policy(policy) != NULL) {
345 348 ap->policy = policy;
346 349 return (0);
347 350 }
348 351 return (EINVAL);
349 352 }
350 353
351 354 /*
352 355 * pthread_attr_getpolicy: gets the scheduling policy.
353 356 */
354 357 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
355 358 int
356 359 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
357 360 {
358 361 thrattr_t *ap;
359 362
360 363 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
361 364 policy != NULL) {
362 365 *policy = ap->policy;
363 366 return (0);
364 367 }
365 368 return (EINVAL);
366 369 }
367 370
368 371 /*
369 372 * pthread_attr_setschedparam: sets the scheduling parameters.
370 373 * Currently, we support priority only.
371 374 */
372 375 int
373 376 pthread_attr_setschedparam(pthread_attr_t *attr,
374 377 const struct sched_param *param)
375 378 {
376 379 thrattr_t *ap;
377 380
378 381 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
379 382 param != NULL) {
380 383 ap->prio = param->sched_priority;
381 384 return (0);
382 385 }
383 386 return (EINVAL);
384 387 }
385 388
386 389 /*
387 390 * pthread_attr_getschedparam: gets the scheduling parameters.
388 391 * Currently, only priority is defined as sched parameter.
389 392 */
390 393 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
391 394 int
392 395 pthread_attr_getschedparam(const pthread_attr_t *attr,
393 396 struct sched_param *param)
394 397 {
395 398 thrattr_t *ap;
396 399
397 400 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
398 401 param != NULL) {
399 402 param->sched_priority = ap->prio;
400 403 return (0);
401 404 }
402 405 return (EINVAL);
403 406 }
404 407
405 408 /*
406 409 * UNIX98
407 410 * pthread_attr_setguardsize: sets the guardsize
408 411 */
409 412 int
410 413 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
411 414 {
412 415 thrattr_t *ap;
413 416
414 417 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
415 418 ap->guardsize = guardsize;
416 419 return (0);
417 420 }
418 421 return (EINVAL);
419 422 }
420 423
421 424 /*
422 425 * UNIX98
423 426 * pthread_attr_getguardsize: gets the guardsize
424 427 */
425 428 int
426 429 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
427 430 {
428 431 thrattr_t *ap;
429 432
430 433 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
431 434 guardsize != NULL) {
432 435 *guardsize = ap->guardsize;
433 436 return (0);
434 437 }
435 438 return (EINVAL);
436 439 }
437 440
438 441 /*
439 442 * pthread_attr_setstack: sets the user stack addr and stack size.
440 443 * This is equivalent to the stack_base and stack_size arguments
441 444 * to thr_create().
442 445 */
443 446 int
444 447 pthread_attr_setstack(pthread_attr_t *attr,
445 448 void *stackaddr, size_t stacksize)
446 449 {
447 450 thrattr_t *ap;
448 451
449 452 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
450 453 stacksize >= MINSTACK) {
451 454 ap->stkaddr = stackaddr;
452 455 ap->stksize = stacksize;
453 456 if (stackaddr != NULL &&
454 457 setup_top_frame(stackaddr, stacksize, NULL) == NULL)
455 458 return (EACCES);
456 459 return (0);
457 460 }
458 461 return (EINVAL);
459 462 }
460 463
461 464 /*
462 465 * pthread_attr_getstack: gets the user stack addr and stack size.
463 466 */
464 467 int
465 468 pthread_attr_getstack(const pthread_attr_t *attr,
466 469 void **stackaddr, size_t *stacksize)
467 470 {
468 471 thrattr_t *ap;
↓ open down ↓ |
340 lines elided |
↑ open up ↑ |
469 472
470 473 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
471 474 stackaddr != NULL && stacksize != NULL) {
472 475 *stackaddr = ap->stkaddr;
473 476 *stacksize = ap->stksize;
474 477 return (0);
475 478 }
476 479 return (EINVAL);
477 480 }
478 481
482 +int
483 +pthread_attr_setname_np(pthread_attr_t *attr, const char *name)
484 +{
485 + thrattr_t *ap;
486 +
487 + if (attr == NULL || (ap = attr->__pthread_attrp) == NULL)
488 + return (EINVAL);
489 +
490 + if (name == NULL) {
491 + bzero(ap->name, sizeof (ap->name));
492 + return (0);
493 + }
494 +
495 + if (strlen(name) >= sizeof (ap->name))
496 + return (ERANGE);
497 +
498 + /*
499 + * We really want the ASCII version of isprint() here...
500 + */
501 + for (size_t i = 0; name[i] != '\0'; i++) {
502 + if (!ISPRINT(name[i]))
503 + return (EINVAL);
504 + }
505 +
506 + /*
507 + * not having garbage after the end of the string simplifies attr
508 + * comparison
509 + */
510 + bzero(ap->name, sizeof (ap->name));
511 + (void) strlcpy(ap->name, name, sizeof (ap->name));
512 + return (0);
513 +}
514 +
515 +int
516 +pthread_attr_getname_np(pthread_attr_t *attr, char *buf, size_t len)
517 +{
518 + thrattr_t *ap;
519 +
520 + if (buf == NULL || attr == NULL ||
521 + (ap = attr->__pthread_attrp) == NULL)
522 + return (EINVAL);
523 +
524 + if (strlcpy(buf, ap->name, len) > len)
525 + return (ERANGE);
526 + return (0);
527 +}
528 +
479 529 /*
480 530 * This function is a common BSD extension to pthread which is used to obtain
481 531 * the attributes of a thread that might have changed after its creation, for
482 532 * example, it's stack address.
483 533 *
484 534 * Note, there is no setattr analogue, nor do we desire to add one at this time.
485 535 * Similarly there is no native threads API analogue (nor should we add one for
486 536 * C11).
487 537 *
488 538 * The astute reader may note that there is a GNU version of this called
489 539 * pthread_getattr_np(). The two functions are similar, but subtley different in
490 540 * a rather important way. While the pthread_attr_get_np() expects to be given
491 541 * a pthread_attr_t that has had pthread_attr_init() called on in,
492 542 * pthread_getattr_np() does not. However, on GNU systems, where the function
493 543 * originates, the pthread_attr_t is not opaque and thus it is entirely safe to
494 544 * both call pthread_attr_init() and then call pthread_getattr_np() on the same
495 545 * attributes object. On illumos, since the pthread_attr_t is opaque, that would
496 546 * be a memory leak. As such, we don't provide it.
497 547 */
498 548 int
499 549 pthread_attr_get_np(pthread_t tid, pthread_attr_t *attr)
500 550 {
501 551 int ret;
502 552 ulwp_t *self = curthread;
503 553 uberdata_t *udp = self->ul_uberdata;
504 554 ulwp_t *target = NULL;
505 555 thrattr_t *ap;
506 556
507 557 /*
508 558 * To ensure that information about the target thread does not change or
509 559 * disappear while we're trying to interrogate it, we grab the uwlp
510 560 * lock.
511 561 */
512 562 if (self->ul_lwpid == tid) {
513 563 ulwp_lock(self, udp);
514 564 target = self;
515 565 } else {
516 566 target = find_lwp(tid);
517 567 if (target == NULL)
518 568 return (ESRCH);
519 569 }
520 570
521 571 if (attr == NULL) {
522 572 ret = EINVAL;
523 573 goto out;
524 574 }
525 575
526 576 if ((ap = attr->__pthread_attrp) == NULL) {
527 577 ret = EINVAL;
528 578 goto out;
529 579 }
530 580
531 581 ap->stksize = target->ul_stksiz;
532 582 ap->stkaddr = target->ul_stk;
533 583 if (target->ul_usropts & THR_DETACHED) {
534 584 ap->detachstate = PTHREAD_CREATE_DETACHED;
535 585 } else {
536 586 ap->detachstate = PTHREAD_CREATE_JOINABLE;
537 587 }
538 588
539 589 if (target->ul_usropts & THR_DAEMON) {
540 590 ap->daemonstate = PTHREAD_CREATE_DAEMON_NP;
541 591 } else {
542 592 ap->daemonstate = PTHREAD_CREATE_NONDAEMON_NP;
543 593 }
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
544 594
545 595 if (target->ul_usropts & THR_BOUND) {
546 596 ap->scope = PTHREAD_SCOPE_SYSTEM;
547 597 } else {
548 598 ap->scope = PTHREAD_SCOPE_PROCESS;
549 599 }
550 600 ap->prio = target->ul_pri;
551 601 ap->policy = target->ul_policy;
552 602 ap->inherit = target->ul_ptinherit;
553 603 ap->guardsize = target->ul_guardsize;
604 + (void) pthread_getname_np(tid, ap->name, sizeof (ap->name));
554 605
555 606 ret = 0;
556 607 out:
557 608 ulwp_unlock(target, udp);
558 609 return (ret);
559 610 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX