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 
17 #include <errno.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <sys/param.h>
21 #include <sys/resource.h>
22 #include "pthread.h"
23 #include "internals.h"
24 #include <shlib-compat.h>
25 
__pthread_attr_init_2_1(pthread_attr_t * attr)26 int __pthread_attr_init_2_1(pthread_attr_t *attr)
27 {
28   size_t ps = __getpagesize ();
29 
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;
39   return 0;
40 }
41 
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)
__pthread_attr_init_2_0(pthread_attr_t * attr)46 int __pthread_attr_init_2_0(pthread_attr_t *attr)
47 {
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;
53   return 0;
54 }
55 compat_symbol (libpthread, __pthread_attr_init_2_0, pthread_attr_init,
56 	       GLIBC_2_0);
57 #endif
58 
pthread_attr_destroy(pthread_attr_t * attr)59 int pthread_attr_destroy(pthread_attr_t *attr)
60 {
61   return 0;
62 }
63 
pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate)64 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
65 {
66   if (detachstate < PTHREAD_CREATE_JOINABLE ||
67       detachstate > PTHREAD_CREATE_DETACHED)
68     return EINVAL;
69   attr->__detachstate = detachstate;
70   return 0;
71 }
72 
pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate)73 int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
74 {
75   *detachstate = attr->__detachstate;
76   return 0;
77 }
78 
pthread_attr_setschedparam(pthread_attr_t * attr,const struct sched_param * param)79 int pthread_attr_setschedparam(pthread_attr_t *attr,
80                                const struct sched_param *param)
81 {
82   int max_prio = __sched_get_priority_max(attr->__schedpolicy);
83   int min_prio = __sched_get_priority_min(attr->__schedpolicy);
84 
85   if (param->sched_priority < min_prio || param->sched_priority > max_prio)
86     return EINVAL;
87   memcpy (&attr->__schedparam, param, sizeof (struct sched_param));
88   return 0;
89 }
90 
pthread_attr_getschedparam(const pthread_attr_t * attr,struct sched_param * param)91 int pthread_attr_getschedparam(const pthread_attr_t *attr,
92                                struct sched_param *param)
93 {
94   memcpy (param, &attr->__schedparam, sizeof (struct sched_param));
95   return 0;
96 }
97 
pthread_attr_setschedpolicy(pthread_attr_t * attr,int policy)98 int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
99 {
100   if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
101     return EINVAL;
102   attr->__schedpolicy = policy;
103   return 0;
104 }
105 
pthread_attr_getschedpolicy(const pthread_attr_t * attr,int * policy)106 int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
107 {
108   *policy = attr->__schedpolicy;
109   return 0;
110 }
111 
pthread_attr_setinheritsched(pthread_attr_t * attr,int inherit)112 int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
113 {
114   if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED)
115     return EINVAL;
116   attr->__inheritsched = inherit;
117   return 0;
118 }
119 
pthread_attr_getinheritsched(const pthread_attr_t * attr,int * inherit)120 int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
121 {
122   *inherit = attr->__inheritsched;
123   return 0;
124 }
125 
pthread_attr_setscope(pthread_attr_t * attr,int scope)126 int pthread_attr_setscope(pthread_attr_t *attr, int scope)
127 {
128   switch (scope) {
129   case PTHREAD_SCOPE_SYSTEM:
130     attr->__scope = scope;
131     return 0;
132   case PTHREAD_SCOPE_PROCESS:
133     return ENOTSUP;
134   default:
135     return EINVAL;
136   }
137 }
138 
pthread_attr_getscope(const pthread_attr_t * attr,int * scope)139 int pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
140 {
141   *scope = attr->__scope;
142   return 0;
143 }
144 
__pthread_attr_setguardsize(pthread_attr_t * attr,size_t guardsize)145 int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
146 {
147   /* The guard size must not be larger than the stack itself */
148   if (guardsize >= attr->__stacksize) return EINVAL;
149 
150   attr->__guardsize = guardsize;
151 
152   return 0;
153 }
weak_alias(__pthread_attr_setguardsize,pthread_attr_setguardsize)154 weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize)
155 
156 int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
157 {
158   *guardsize = attr->__guardsize;
159   return 0;
160 }
weak_alias(__pthread_attr_getguardsize,pthread_attr_getguardsize)161 weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize)
162 
163 int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
164 {
165   attr->__stackaddr = stackaddr;
166   attr->__stackaddr_set = 1;
167   return 0;
168 }
weak_alias(__pthread_attr_setstackaddr,pthread_attr_setstackaddr)169 weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr)
170 
171 link_warning (pthread_attr_setstackaddr,
172 	      "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'")
173 
174 int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
175 {
176   /* XXX This function has a stupid definition.  The standard specifies
177      no error value but what is if no stack address was set?  We simply
178      return the value we have in the member.  */
179   *stackaddr = attr->__stackaddr;
180   return 0;
181 }
weak_alias(__pthread_attr_getstackaddr,pthread_attr_getstackaddr)182 weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
183 
184 link_warning (pthread_attr_getstackaddr,
185 	      "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'")
186 
187 
188 int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
189 {
190 #ifdef FLOATING_STACKS
191   /* We have to check against the maximum allowed stack size.  This is no
192      problem if the manager is already started and we determined it.  If
193      this hasn't happened, we have to find the limit outself.  */
194   if (__pthread_max_stacksize == 0)
195     __pthread_init_max_stacksize ();
196 
197   if (stacksize > __pthread_max_stacksize)
198     return EINVAL;
199 #else
200   /* We have a fixed size limit.  */
201   if (stacksize > STACK_SIZE)
202     return EINVAL;
203 #endif
204 
205   /* We don't accept value smaller than PTHREAD_STACK_MIN.  */
206   if (stacksize < PTHREAD_STACK_MIN)
207     return EINVAL;
208 
209   attr->__stacksize = stacksize;
210   return 0;
211 }
weak_alias(__pthread_attr_setstacksize,pthread_attr_setstacksize)212 weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize)
213 
214 int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
215 {
216   *stacksize = attr->__stacksize;
217   return 0;
218 }
weak_alias(__pthread_attr_getstacksize,pthread_attr_getstacksize)219 weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize)
220 
221 int __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
222 			     size_t stacksize)
223 {
224   int err;
225 
226   if ((((uintptr_t) stackaddr)
227        & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0)
228     err = EINVAL;
229   else
230     err = __pthread_attr_setstacksize (attr, stacksize);
231   if (err == 0)
232     {
233 #ifndef _STACK_GROWS_UP
234       attr->__stackaddr = (char *) stackaddr + stacksize;
235 #else
236       attr->__stackaddr = stackaddr;
237 #endif
238       attr->__stackaddr_set = 1;
239     }
240 
241   return err;
242 }
weak_alias(__pthread_attr_setstack,pthread_attr_setstack)243 weak_alias (__pthread_attr_setstack, pthread_attr_setstack)
244 
245 int __pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr,
246 			     size_t *stacksize)
247 {
248   /* XXX This function has a stupid definition.  The standard specifies
249      no error value but what is if no stack address was set?  We simply
250      return the value we have in the member.  */
251 #ifndef _STACK_GROWS_UP
252   *stackaddr = (char *) attr->__stackaddr - attr->__stacksize;
253 #else
254   *stackaddr = attr->__stackaddr;
255 #endif
256   *stacksize = attr->__stacksize;
257   return 0;
258 }
weak_alias(__pthread_attr_getstack,pthread_attr_getstack)259 weak_alias (__pthread_attr_getstack, pthread_attr_getstack)
260 
261 int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
262 {
263   pthread_handle handle = thread_handle (thread);
264   pthread_descr descr;
265 
266   if (handle == NULL)
267     return ENOENT;
268 
269   descr = handle->h_descr;
270 
271   attr->__detachstate = (descr->p_detached
272 			 ? PTHREAD_CREATE_DETACHED
273 			 : PTHREAD_CREATE_JOINABLE);
274 
275   attr->__schedpolicy = __sched_getscheduler (descr->p_pid);
276   if (attr->__schedpolicy == -1)
277     return errno;
278 
279   if (__sched_getparam (descr->p_pid,
280 			(struct sched_param *) &attr->__schedparam) != 0)
281     return errno;
282 
283   attr->__inheritsched = descr->p_inheritsched;
284   attr->__scope = PTHREAD_SCOPE_SYSTEM;
285 #ifdef _STACK_GROWS_DOWN
286   attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr
287 		      - descr->p_guardsize;
288 #else
289   attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr;
290 #endif
291   attr->__guardsize = descr->p_guardsize;
292   attr->__stackaddr_set = descr->p_userstack;
293 #ifdef NEED_SEPARATE_REGISTER_STACK
294   if (descr->p_userstack == 0)
295     attr->__stacksize *= 2;
296   /* XXX This is awkward.  The guard pages are in the middle of the
297      two stacks.  We must count the guard size in the stack size since
298      otherwise the range of the stack area cannot be computed.  */
299   attr->__stacksize += attr->__guardsize;
300 #endif
301 #ifndef _STACK_GROWS_UP
302   attr->__stackaddr = (char *)(descr + 1);
303 #else
304   attr->__stackaddr = (char *)descr;
305 #endif
306 
307   return 0;
308 }
309