1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "lint.h"
28 #include "thr_uberdata.h"
29 #include <sched.h>
30
31 /*
32 * Default attribute object for pthread_create() with NULL attr pointer.
33 * Note that the 'guardsize' field is initialized on the first call.
34 */
35 const thrattr_t *
def_thrattr(void)36 def_thrattr(void)
37 {
38 static thrattr_t thrattr = {
39 0, /* stksize */
40 NULL, /* stkaddr */
41 PTHREAD_CREATE_JOINABLE, /* detachstate */
42 PTHREAD_CREATE_NONDAEMON_NP, /* daemonstate */
43 PTHREAD_SCOPE_PROCESS, /* scope */
44 0, /* prio */
45 SCHED_OTHER, /* policy */
46 PTHREAD_INHERIT_SCHED, /* inherit */
47 0 /* guardsize */
48 };
49 if (thrattr.guardsize == 0)
50 thrattr.guardsize = _sysconf(_SC_PAGESIZE);
51 return (&thrattr);
52 }
53
54 /*
55 * pthread_attr_init: allocates the attribute object and initializes it
56 * with the default values.
57 */
58 #pragma weak _pthread_attr_init = pthread_attr_init
59 int
pthread_attr_init(pthread_attr_t * attr)60 pthread_attr_init(pthread_attr_t *attr)
61 {
62 thrattr_t *ap;
63
64 if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
65 *ap = *def_thrattr();
66 attr->__pthread_attrp = ap;
67 return (0);
68 }
69 return (ENOMEM);
70 }
71
72 /*
73 * pthread_attr_destroy: frees the attribute object and invalidates it
74 * with NULL value.
75 */
76 int
pthread_attr_destroy(pthread_attr_t * attr)77 pthread_attr_destroy(pthread_attr_t *attr)
78 {
79 if (attr == NULL || attr->__pthread_attrp == NULL)
80 return (EINVAL);
81 lfree(attr->__pthread_attrp, sizeof (thrattr_t));
82 attr->__pthread_attrp = NULL;
83 return (0);
84 }
85
86 /*
87 * pthread_attr_clone: make a copy of a pthread_attr_t.
88 */
89 int
pthread_attr_clone(pthread_attr_t * attr,const pthread_attr_t * old_attr)90 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
91 {
92 thrattr_t *ap;
93 const thrattr_t *old_ap =
94 old_attr? old_attr->__pthread_attrp : def_thrattr();
95
96 if (old_ap == NULL)
97 return (EINVAL);
98 if ((ap = lmalloc(sizeof (thrattr_t))) == NULL)
99 return (ENOMEM);
100 *ap = *old_ap;
101 attr->__pthread_attrp = ap;
102 return (0);
103 }
104
105 /*
106 * pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal.
107 * A NULL pthread_attr_t pointer implies default attributes.
108 * This is a consolidation-private interface, for librt.
109 */
110 int
pthread_attr_equal(const pthread_attr_t * attr1,const pthread_attr_t * attr2)111 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
112 {
113 const thrattr_t *ap1 = attr1? attr1->__pthread_attrp : def_thrattr();
114 const thrattr_t *ap2 = attr2? attr2->__pthread_attrp : def_thrattr();
115
116 if (ap1 == NULL || ap2 == NULL)
117 return (0);
118 return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
119 }
120
121 /*
122 * pthread_attr_setstacksize: sets the user stack size, minimum should
123 * be PTHREAD_STACK_MIN (MINSTACK).
124 * This is equivalent to stksize argument in thr_create().
125 */
126 int
pthread_attr_setstacksize(pthread_attr_t * attr,size_t stacksize)127 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
128 {
129 thrattr_t *ap;
130
131 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
132 stacksize >= MINSTACK) {
133 ap->stksize = stacksize;
134 return (0);
135 }
136 return (EINVAL);
137 }
138
139 /*
140 * pthread_attr_getstacksize: gets the user stack size.
141 */
142 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
143 int
pthread_attr_getstacksize(const pthread_attr_t * attr,size_t * stacksize)144 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
145 {
146 thrattr_t *ap;
147
148 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
149 stacksize != NULL) {
150 *stacksize = ap->stksize;
151 return (0);
152 }
153 return (EINVAL);
154 }
155
156 /*
157 * pthread_attr_setstackaddr: sets the user stack addr.
158 * This is equivalent to stkaddr argument in thr_create().
159 */
160 int
pthread_attr_setstackaddr(pthread_attr_t * attr,void * stackaddr)161 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
162 {
163 thrattr_t *ap;
164
165 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
166 ap->stkaddr = stackaddr;
167 return (0);
168 }
169 return (EINVAL);
170 }
171
172 /*
173 * pthread_attr_getstackaddr: gets the user stack addr.
174 */
175 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
176 int
pthread_attr_getstackaddr(const pthread_attr_t * attr,void ** stackaddr)177 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
178 {
179 thrattr_t *ap;
180
181 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
182 stackaddr != NULL) {
183 *stackaddr = ap->stkaddr;
184 return (0);
185 }
186 return (EINVAL);
187 }
188
189 /*
190 * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
191 * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
192 */
193 int
pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate)194 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
195 {
196 thrattr_t *ap;
197
198 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
199 (detachstate == PTHREAD_CREATE_DETACHED ||
200 detachstate == PTHREAD_CREATE_JOINABLE)) {
201 ap->detachstate = detachstate;
202 return (0);
203 }
204 return (EINVAL);
205 }
206
207 /*
208 * pthread_attr_getdetachstate: gets the detach state.
209 */
210 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
211 int
pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate)212 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
213 {
214 thrattr_t *ap;
215
216 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
217 detachstate != NULL) {
218 *detachstate = ap->detachstate;
219 return (0);
220 }
221 return (EINVAL);
222 }
223
224 /*
225 * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON.
226 * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON).
227 * For now, this is a private interface in libc.
228 */
229 int
pthread_attr_setdaemonstate_np(pthread_attr_t * attr,int daemonstate)230 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
231 {
232 thrattr_t *ap;
233
234 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
235 (daemonstate == PTHREAD_CREATE_DAEMON_NP ||
236 daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) {
237 ap->daemonstate = daemonstate;
238 return (0);
239 }
240 return (EINVAL);
241 }
242
243 /*
244 * pthread_attr_getdaemonstate_np: gets the daemon state.
245 * For now, this is a private interface in libc.
246 */
247 int
pthread_attr_getdaemonstate_np(const pthread_attr_t * attr,int * daemonstate)248 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
249 {
250 thrattr_t *ap;
251
252 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
253 daemonstate != NULL) {
254 *daemonstate = ap->daemonstate;
255 return (0);
256 }
257 return (EINVAL);
258 }
259
260 /*
261 * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
262 * This is equivalent to setting THR_BOUND flag in thr_create().
263 */
264 int
pthread_attr_setscope(pthread_attr_t * attr,int scope)265 pthread_attr_setscope(pthread_attr_t *attr, int scope)
266 {
267 thrattr_t *ap;
268
269 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
270 (scope == PTHREAD_SCOPE_SYSTEM ||
271 scope == PTHREAD_SCOPE_PROCESS)) {
272 ap->scope = scope;
273 return (0);
274 }
275 return (EINVAL);
276 }
277
278 /*
279 * pthread_attr_getscope: gets the scheduling scope.
280 */
281 #pragma weak _pthread_attr_getscope = pthread_attr_getscope
282 int
pthread_attr_getscope(const pthread_attr_t * attr,int * scope)283 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
284 {
285 thrattr_t *ap;
286
287 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
288 scope != NULL) {
289 *scope = ap->scope;
290 return (0);
291 }
292 return (EINVAL);
293 }
294
295 /*
296 * pthread_attr_setinheritsched: sets the scheduling parameters to be
297 * EXPLICIT or INHERITED from parent thread.
298 */
299 int
pthread_attr_setinheritsched(pthread_attr_t * attr,int inherit)300 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
301 {
302 thrattr_t *ap;
303
304 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
305 (inherit == PTHREAD_EXPLICIT_SCHED ||
306 inherit == PTHREAD_INHERIT_SCHED)) {
307 ap->inherit = inherit;
308 return (0);
309 }
310 return (EINVAL);
311 }
312
313 /*
314 * pthread_attr_getinheritsched: gets the scheduling inheritance.
315 */
316 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
317 int
pthread_attr_getinheritsched(const pthread_attr_t * attr,int * inherit)318 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
319 {
320 thrattr_t *ap;
321
322 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
323 inherit != NULL) {
324 *inherit = ap->inherit;
325 return (0);
326 }
327 return (EINVAL);
328 }
329
330 /*
331 * pthread_attr_setschedpolicy: sets the scheduling policy.
332 */
333 int
pthread_attr_setschedpolicy(pthread_attr_t * attr,int policy)334 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
335 {
336 thrattr_t *ap;
337
338 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
339 policy != SCHED_SYS && get_info_by_policy(policy) != NULL) {
340 ap->policy = policy;
341 return (0);
342 }
343 return (EINVAL);
344 }
345
346 /*
347 * pthread_attr_getpolicy: gets the scheduling policy.
348 */
349 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
350 int
pthread_attr_getschedpolicy(const pthread_attr_t * attr,int * policy)351 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
352 {
353 thrattr_t *ap;
354
355 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
356 policy != NULL) {
357 *policy = ap->policy;
358 return (0);
359 }
360 return (EINVAL);
361 }
362
363 /*
364 * pthread_attr_setschedparam: sets the scheduling parameters.
365 * Currently, we support priority only.
366 */
367 int
pthread_attr_setschedparam(pthread_attr_t * attr,const struct sched_param * param)368 pthread_attr_setschedparam(pthread_attr_t *attr,
369 const struct sched_param *param)
370 {
371 thrattr_t *ap;
372
373 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
374 param != NULL) {
375 ap->prio = param->sched_priority;
376 return (0);
377 }
378 return (EINVAL);
379 }
380
381 /*
382 * pthread_attr_getschedparam: gets the scheduling parameters.
383 * Currently, only priority is defined as sched parameter.
384 */
385 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
386 int
pthread_attr_getschedparam(const pthread_attr_t * attr,struct sched_param * param)387 pthread_attr_getschedparam(const pthread_attr_t *attr,
388 struct sched_param *param)
389 {
390 thrattr_t *ap;
391
392 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
393 param != NULL) {
394 param->sched_priority = ap->prio;
395 return (0);
396 }
397 return (EINVAL);
398 }
399
400 /*
401 * UNIX98
402 * pthread_attr_setguardsize: sets the guardsize
403 */
404 int
pthread_attr_setguardsize(pthread_attr_t * attr,size_t guardsize)405 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
406 {
407 thrattr_t *ap;
408
409 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
410 ap->guardsize = guardsize;
411 return (0);
412 }
413 return (EINVAL);
414 }
415
416 /*
417 * UNIX98
418 * pthread_attr_getguardsize: gets the guardsize
419 */
420 int
pthread_attr_getguardsize(const pthread_attr_t * attr,size_t * guardsize)421 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
422 {
423 thrattr_t *ap;
424
425 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
426 guardsize != NULL) {
427 *guardsize = ap->guardsize;
428 return (0);
429 }
430 return (EINVAL);
431 }
432
433 /*
434 * pthread_attr_setstack: sets the user stack addr and stack size.
435 * This is equivalent to the stack_base and stack_size arguments
436 * to thr_create().
437 */
438 int
pthread_attr_setstack(pthread_attr_t * attr,void * stackaddr,size_t stacksize)439 pthread_attr_setstack(pthread_attr_t *attr,
440 void *stackaddr, size_t stacksize)
441 {
442 thrattr_t *ap;
443
444 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
445 stacksize >= MINSTACK) {
446 ap->stkaddr = stackaddr;
447 ap->stksize = stacksize;
448 if (stackaddr != NULL &&
449 setup_top_frame(stackaddr, stacksize, NULL) == NULL)
450 return (EACCES);
451 return (0);
452 }
453 return (EINVAL);
454 }
455
456 /*
457 * pthread_attr_getstack: gets the user stack addr and stack size.
458 */
459 int
pthread_attr_getstack(const pthread_attr_t * attr,void ** stackaddr,size_t * stacksize)460 pthread_attr_getstack(const pthread_attr_t *attr,
461 void **stackaddr, size_t *stacksize)
462 {
463 thrattr_t *ap;
464
465 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
466 stackaddr != NULL && stacksize != NULL) {
467 *stackaddr = ap->stkaddr;
468 *stacksize = ap->stksize;
469 return (0);
470 }
471 return (EINVAL);
472 }
473