]>
Commit | Line | Data |
---|---|---|
5afdca00 UD |
1 | /* Linuxthreads - a simple clone()-based implementation of Posix */ |
2 | /* threads for Linux. */ | |
3 | /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ | |
4 | /* */ | |
5 | /* This program is free software; you can redistribute it and/or */ | |
6 | /* modify it under the terms of the GNU Library General Public License */ | |
7 | /* as published by the Free Software Foundation; either version 2 */ | |
8 | /* of the License, or (at your option) any later version. */ | |
9 | /* */ | |
10 | /* This program is distributed in the hope that it will be useful, */ | |
11 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ | |
12 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ | |
13 | /* GNU Library General Public License for more details. */ | |
14 | ||
15 | /* Handling of thread attributes */ | |
16 | ||
4959e310 | 17 | #include <errno.h> |
ba9234d9 | 18 | #include <string.h> |
5afdca00 | 19 | #include <unistd.h> |
5d409851 | 20 | #include <sys/param.h> |
234dd7a6 | 21 | #include <sys/resource.h> |
5afdca00 UD |
22 | #include "pthread.h" |
23 | #include "internals.h" | |
ef7dddd0 | 24 | #include <shlib-compat.h> |
5afdca00 | 25 | |
5d409851 UD |
26 | int __pthread_attr_init_2_1(pthread_attr_t *attr) |
27 | { | |
28 | size_t ps = __getpagesize (); | |
29 | ||
c70ca1fa UD |
30 | attr->__detachstate = PTHREAD_CREATE_JOINABLE; |
31 | attr->__schedpolicy = SCHED_OTHER; | |
32 | attr->__schedparam.sched_priority = 0; | |
33 | attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; | |
34 | attr->__scope = PTHREAD_SCOPE_SYSTEM; | |
35 | attr->__guardsize = ps; | |
36 | attr->__stackaddr = NULL; | |
37 | attr->__stackaddr_set = 0; | |
38 | attr->__stacksize = STACK_SIZE - ps; | |
5d409851 UD |
39 | return 0; |
40 | } | |
5d409851 | 41 | |
ef7dddd0 UD |
42 | versioned_symbol (libpthread, __pthread_attr_init_2_1, pthread_attr_init, |
43 | GLIBC_2_1); | |
44 | ||
45 | #if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) | |
5d409851 | 46 | int __pthread_attr_init_2_0(pthread_attr_t *attr) |
5afdca00 | 47 | { |
c70ca1fa UD |
48 | attr->__detachstate = PTHREAD_CREATE_JOINABLE; |
49 | attr->__schedpolicy = SCHED_OTHER; | |
50 | attr->__schedparam.sched_priority = 0; | |
51 | attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; | |
52 | attr->__scope = PTHREAD_SCOPE_SYSTEM; | |
5afdca00 UD |
53 | return 0; |
54 | } | |
41aefe41 UD |
55 | compat_symbol (libpthread, __pthread_attr_init_2_0, pthread_attr_init, |
56 | GLIBC_2_0); | |
5d409851 | 57 | #endif |
5afdca00 | 58 | |
82f81a90 | 59 | int __pthread_attr_destroy(pthread_attr_t *attr) |
5afdca00 UD |
60 | { |
61 | return 0; | |
62 | } | |
82f81a90 | 63 | strong_alias (__pthread_attr_destroy, pthread_attr_destroy); |
5afdca00 | 64 | |
82f81a90 | 65 | int __pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) |
5afdca00 UD |
66 | { |
67 | if (detachstate < PTHREAD_CREATE_JOINABLE || | |
68 | detachstate > PTHREAD_CREATE_DETACHED) | |
69 | return EINVAL; | |
c70ca1fa | 70 | attr->__detachstate = detachstate; |
5afdca00 UD |
71 | return 0; |
72 | } | |
82f81a90 | 73 | strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate); |
5afdca00 | 74 | |
82f81a90 | 75 | int __pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) |
5afdca00 | 76 | { |
c70ca1fa | 77 | *detachstate = attr->__detachstate; |
5afdca00 UD |
78 | return 0; |
79 | } | |
82f81a90 | 80 | strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate); |
5afdca00 | 81 | |
82f81a90 UD |
82 | int __pthread_attr_setschedparam(pthread_attr_t *attr, |
83 | const struct sched_param *param) | |
5afdca00 | 84 | { |
c70ca1fa UD |
85 | int max_prio = __sched_get_priority_max(attr->__schedpolicy); |
86 | int min_prio = __sched_get_priority_min(attr->__schedpolicy); | |
5afdca00 UD |
87 | |
88 | if (param->sched_priority < min_prio || param->sched_priority > max_prio) | |
89 | return EINVAL; | |
c70ca1fa | 90 | memcpy (&attr->__schedparam, param, sizeof (struct sched_param)); |
5afdca00 UD |
91 | return 0; |
92 | } | |
82f81a90 | 93 | strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam); |
5afdca00 | 94 | |
82f81a90 UD |
95 | int __pthread_attr_getschedparam(const pthread_attr_t *attr, |
96 | struct sched_param *param) | |
5afdca00 | 97 | { |
c70ca1fa | 98 | memcpy (param, &attr->__schedparam, sizeof (struct sched_param)); |
5afdca00 UD |
99 | return 0; |
100 | } | |
82f81a90 | 101 | strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam); |
5afdca00 | 102 | |
82f81a90 | 103 | int __pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) |
5afdca00 UD |
104 | { |
105 | if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR) | |
106 | return EINVAL; | |
c70ca1fa | 107 | attr->__schedpolicy = policy; |
5afdca00 UD |
108 | return 0; |
109 | } | |
82f81a90 | 110 | strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy); |
5afdca00 | 111 | |
82f81a90 | 112 | int __pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) |
5afdca00 | 113 | { |
c70ca1fa | 114 | *policy = attr->__schedpolicy; |
5afdca00 UD |
115 | return 0; |
116 | } | |
82f81a90 | 117 | strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy); |
5afdca00 | 118 | |
82f81a90 | 119 | int __pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) |
5afdca00 UD |
120 | { |
121 | if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED) | |
122 | return EINVAL; | |
c70ca1fa | 123 | attr->__inheritsched = inherit; |
5afdca00 UD |
124 | return 0; |
125 | } | |
82f81a90 | 126 | strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched); |
5afdca00 | 127 | |
82f81a90 | 128 | int __pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) |
5afdca00 | 129 | { |
c70ca1fa | 130 | *inherit = attr->__inheritsched; |
5afdca00 UD |
131 | return 0; |
132 | } | |
82f81a90 | 133 | strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched); |
5afdca00 | 134 | |
82f81a90 | 135 | int __pthread_attr_setscope(pthread_attr_t *attr, int scope) |
5afdca00 UD |
136 | { |
137 | switch (scope) { | |
138 | case PTHREAD_SCOPE_SYSTEM: | |
c70ca1fa | 139 | attr->__scope = scope; |
5afdca00 UD |
140 | return 0; |
141 | case PTHREAD_SCOPE_PROCESS: | |
142 | return ENOTSUP; | |
143 | default: | |
144 | return EINVAL; | |
145 | } | |
146 | } | |
82f81a90 | 147 | strong_alias (__pthread_attr_setscope, pthread_attr_setscope); |
5afdca00 | 148 | |
82f81a90 | 149 | int __pthread_attr_getscope(const pthread_attr_t *attr, int *scope) |
5afdca00 | 150 | { |
c70ca1fa | 151 | *scope = attr->__scope; |
5afdca00 UD |
152 | return 0; |
153 | } | |
82f81a90 | 154 | strong_alias (__pthread_attr_getscope, pthread_attr_getscope); |
5d409851 UD |
155 | |
156 | int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) | |
157 | { | |
ddbf7fef | 158 | /* The guard size must not be larger than the stack itself */ |
c70ca1fa | 159 | if (guardsize >= attr->__stacksize) return EINVAL; |
5d409851 | 160 | |
c70ca1fa | 161 | attr->__guardsize = guardsize; |
5d409851 UD |
162 | |
163 | return 0; | |
164 | } | |
165 | weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize) | |
166 | ||
167 | int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) | |
168 | { | |
c70ca1fa | 169 | *guardsize = attr->__guardsize; |
5d409851 UD |
170 | return 0; |
171 | } | |
172 | weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize) | |
173 | ||
174 | int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) | |
175 | { | |
c70ca1fa UD |
176 | attr->__stackaddr = stackaddr; |
177 | attr->__stackaddr_set = 1; | |
5d409851 UD |
178 | return 0; |
179 | } | |
180 | weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr) | |
181 | ||
e8a5cd43 UD |
182 | link_warning (pthread_attr_setstackaddr, |
183 | "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'") | |
184 | ||
5d409851 UD |
185 | int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) |
186 | { | |
187 | /* XXX This function has a stupid definition. The standard specifies | |
188 | no error value but what is if no stack address was set? We simply | |
189 | return the value we have in the member. */ | |
c70ca1fa | 190 | *stackaddr = attr->__stackaddr; |
5d409851 UD |
191 | return 0; |
192 | } | |
c6bd526f | 193 | weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr) |
5d409851 | 194 | |
e8a5cd43 UD |
195 | link_warning (pthread_attr_getstackaddr, |
196 | "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'") | |
197 | ||
198 | ||
5d409851 UD |
199 | int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) |
200 | { | |
234dd7a6 UD |
201 | #ifdef FLOATING_STACKS |
202 | /* We have to check against the maximum allowed stack size. This is no | |
203 | problem if the manager is already started and we determined it. If | |
204 | this hasn't happened, we have to find the limit outself. */ | |
205 | if (__pthread_max_stacksize == 0) | |
a66f0958 | 206 | __pthread_init_max_stacksize (); |
234dd7a6 UD |
207 | |
208 | if (stacksize > __pthread_max_stacksize) | |
209 | return EINVAL; | |
210 | #else | |
211 | /* We have a fixed size limit. */ | |
212 | if (stacksize > STACK_SIZE) | |
213 | return EINVAL; | |
214 | #endif | |
215 | ||
3387a425 UD |
216 | /* We don't accept value smaller than PTHREAD_STACK_MIN. */ |
217 | if (stacksize < PTHREAD_STACK_MIN) | |
5d409851 UD |
218 | return EINVAL; |
219 | ||
c70ca1fa | 220 | attr->__stacksize = stacksize; |
5d409851 UD |
221 | return 0; |
222 | } | |
223 | weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize) | |
224 | ||
225 | int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) | |
226 | { | |
c70ca1fa | 227 | *stacksize = attr->__stacksize; |
5d409851 UD |
228 | return 0; |
229 | } | |
230 | weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize) | |
b81c8961 UD |
231 | |
232 | int __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, | |
233 | size_t stacksize) | |
234 | { | |
235 | int err; | |
236 | ||
237 | if ((((uintptr_t) stackaddr) | |
1fb7dc3c | 238 | & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0) |
b81c8961 UD |
239 | err = EINVAL; |
240 | else | |
241 | err = __pthread_attr_setstacksize (attr, stacksize); | |
242 | if (err == 0) | |
243 | { | |
e8a5cd43 | 244 | #ifndef _STACK_GROWS_UP |
b81c8961 UD |
245 | attr->__stackaddr = (char *) stackaddr + stacksize; |
246 | #else | |
247 | attr->__stackaddr = stackaddr; | |
248 | #endif | |
249 | attr->__stackaddr_set = 1; | |
250 | } | |
251 | ||
252 | return err; | |
253 | } | |
254 | weak_alias (__pthread_attr_setstack, pthread_attr_setstack) | |
255 | ||
256 | int __pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr, | |
257 | size_t *stacksize) | |
258 | { | |
259 | /* XXX This function has a stupid definition. The standard specifies | |
260 | no error value but what is if no stack address was set? We simply | |
261 | return the value we have in the member. */ | |
5a7d27d4 UD |
262 | #ifndef _STACK_GROWS_UP |
263 | *stackaddr = (char *) attr->__stackaddr - attr->__stacksize; | |
264 | #else | |
b81c8961 | 265 | *stackaddr = attr->__stackaddr; |
5a7d27d4 | 266 | #endif |
b81c8961 UD |
267 | *stacksize = attr->__stacksize; |
268 | return 0; | |
269 | } | |
270 | weak_alias (__pthread_attr_getstack, pthread_attr_getstack) | |
3bf927cb UD |
271 | |
272 | int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) | |
273 | { | |
274 | pthread_handle handle = thread_handle (thread); | |
275 | pthread_descr descr; | |
3bf927cb UD |
276 | |
277 | if (handle == NULL) | |
278 | return ENOENT; | |
279 | ||
280 | descr = handle->h_descr; | |
281 | ||
282 | attr->__detachstate = (descr->p_detached | |
283 | ? PTHREAD_CREATE_DETACHED | |
284 | : PTHREAD_CREATE_JOINABLE); | |
285 | ||
286 | attr->__schedpolicy = __sched_getscheduler (descr->p_pid); | |
287 | if (attr->__schedpolicy == -1) | |
288 | return errno; | |
289 | ||
290 | if (__sched_getparam (descr->p_pid, | |
291 | (struct sched_param *) &attr->__schedparam) != 0) | |
292 | return errno; | |
293 | ||
3bf927cb UD |
294 | attr->__inheritsched = descr->p_inheritsched; |
295 | attr->__scope = PTHREAD_SCOPE_SYSTEM; | |
cc765c2a | 296 | #ifdef _STACK_GROWS_DOWN |
b6a0a996 UD |
297 | # ifdef USE_TLS |
298 | attr->__stacksize = descr->p_stackaddr - (char *)descr->p_guardaddr | |
299 | - descr->p_guardsize; | |
300 | # else | |
1fb7dc3c UD |
301 | attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr |
302 | - descr->p_guardsize; | |
b6a0a996 | 303 | # endif |
cc765c2a | 304 | #else |
b6a0a996 UD |
305 | # ifdef USE_TLS |
306 | attr->__stacksize = (char *)descr->p_guardaddr - descr->p_stackaddr; | |
307 | # else | |
cc765c2a | 308 | attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr; |
b6a0a996 | 309 | # endif |
cc765c2a | 310 | #endif |
3bf927cb UD |
311 | attr->__guardsize = descr->p_guardsize; |
312 | attr->__stackaddr_set = descr->p_userstack; | |
313 | #ifdef NEED_SEPARATE_REGISTER_STACK | |
93a4b7ca UD |
314 | if (descr->p_userstack == 0) |
315 | attr->__stacksize *= 2; | |
3bf927cb UD |
316 | /* XXX This is awkward. The guard pages are in the middle of the |
317 | two stacks. We must count the guard size in the stack size since | |
318 | otherwise the range of the stack area cannot be computed. */ | |
aeba9785 | 319 | attr->__stacksize += attr->__guardsize; |
3bf927cb | 320 | #endif |
b6a0a996 UD |
321 | #ifdef USE_TLS |
322 | attr->__stackaddr = descr->p_stackaddr; | |
1fb7dc3c | 323 | #else |
b6a0a996 UD |
324 | # ifndef _STACK_GROWS_UP |
325 | attr->__stackaddr = (char *)(descr + 1); | |
326 | # else | |
cc765c2a | 327 | attr->__stackaddr = (char *)descr; |
b6a0a996 | 328 | # endif |
1fb7dc3c | 329 | #endif |
3bf927cb UD |
330 | |
331 | return 0; | |
332 | } |