1 /*
2 **  GNU Pth - The GNU Portable Threads
3 **  Copyright (c) 1999-2006 Ralf S. Engelschall <rse@engelschall.com>
4 **
5 **  This file is part of GNU Pth, a non-preemptive thread scheduling
6 **  library which can be found at http://www.gnu.org/software/pth/.
7 **
8 **  This library is free software; you can redistribute it and/or
9 **  modify it under the terms of the GNU Lesser General Public
10 **  License as published by the Free Software Foundation; either
11 **  version 2.1 of the License, or (at your option) any later version.
12 **
13 **  This library is distributed in the hope that it will be useful,
14 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 **  Lesser General Public License for more details.
17 **
18 **  You should have received a copy of the GNU Lesser General Public
19 **  License along with this library; if not, write to the Free Software
20 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 **  USA, or contact Ralf S. Engelschall <rse@engelschall.com>.
22 **
23 **  pth_attr.c: Pth thread attributes
24 */
25                              /* ``Unix -- where you can do anything
26                                   in two keystrokes, or less...''
27                                                      -- Unknown  */
28 #include "pth_p.h"
29 
30 #if cpp
31 
32 enum {
33     PTH_ATTR_GET,
34     PTH_ATTR_SET
35 };
36 
37 struct pth_attr_st {
38     pth_t        a_tid;
39     int          a_prio;
40     int          a_dispatches;
41     char         a_name[PTH_TCB_NAMELEN];
42     int          a_joinable;
43     unsigned int a_cancelstate;
44     unsigned int a_stacksize;
45     char        *a_stackaddr;
46 };
47 
48 #endif /* cpp */
49 
pth_attr_of(pth_t t)50 pth_attr_t pth_attr_of(pth_t t)
51 {
52     pth_attr_t a;
53 
54     if (t == NULL)
55         return pth_error((pth_attr_t)NULL, EINVAL);
56     if ((a = (pth_attr_t)malloc(sizeof(struct pth_attr_st))) == NULL)
57         return pth_error((pth_attr_t)NULL, ENOMEM);
58     a->a_tid = t;
59     return a;
60 }
61 
pth_attr_new(void)62 pth_attr_t pth_attr_new(void)
63 {
64     pth_attr_t a;
65 
66     if ((a = (pth_attr_t)malloc(sizeof(struct pth_attr_st))) == NULL)
67         return pth_error((pth_attr_t)NULL, ENOMEM);
68     a->a_tid = NULL;
69     pth_attr_init(a);
70     return a;
71 }
72 
pth_attr_destroy(pth_attr_t a)73 int pth_attr_destroy(pth_attr_t a)
74 {
75     if (a == NULL)
76         return pth_error(FALSE, EINVAL);
77     free(a);
78     return TRUE;
79 }
80 
pth_attr_init(pth_attr_t a)81 int pth_attr_init(pth_attr_t a)
82 {
83     if (a == NULL)
84         return pth_error(FALSE, EINVAL);
85     if (a->a_tid != NULL)
86         return pth_error(FALSE, EPERM);
87     a->a_prio = PTH_PRIO_STD;
88     pth_util_cpystrn(a->a_name, "unknown", PTH_TCB_NAMELEN);
89     a->a_dispatches = 0;
90     a->a_joinable = TRUE;
91     a->a_cancelstate = PTH_CANCEL_DEFAULT;
92     a->a_stacksize = 64*1024;
93     a->a_stackaddr = NULL;
94     return TRUE;
95 }
96 
pth_attr_get(pth_attr_t a,int op,...)97 int pth_attr_get(pth_attr_t a, int op, ...)
98 {
99     va_list ap;
100     int rc;
101 
102     va_start(ap, op);
103     rc = pth_attr_ctrl(PTH_ATTR_GET, a, op, ap);
104     va_end(ap);
105     return rc;
106 }
107 
pth_attr_set(pth_attr_t a,int op,...)108 int pth_attr_set(pth_attr_t a, int op, ...)
109 {
110     va_list ap;
111     int rc;
112 
113     va_start(ap, op);
114     rc = pth_attr_ctrl(PTH_ATTR_SET, a, op, ap);
115     va_end(ap);
116     return rc;
117 }
118 
pth_attr_ctrl(int cmd,pth_attr_t a,int op,va_list ap)119 intern int pth_attr_ctrl(int cmd, pth_attr_t a, int op, va_list ap)
120 {
121     if (a == NULL)
122         return pth_error(FALSE, EINVAL);
123     switch (op) {
124         case PTH_ATTR_PRIO: {
125             /* priority */
126             int val, *src, *dst;
127             if (cmd == PTH_ATTR_SET) {
128                 src = &val; val = va_arg(ap, int);
129                 dst = (a->a_tid != NULL ? &a->a_tid->prio : &a->a_prio);
130             }
131             else {
132                 src = (a->a_tid != NULL ? &a->a_tid->prio : &a->a_prio);
133                 dst = va_arg(ap, int *);
134             }
135             *dst = *src;
136             break;
137         }
138         case PTH_ATTR_NAME: {
139             /* name */
140             if (cmd == PTH_ATTR_SET) {
141                 char *src, *dst;
142                 src = va_arg(ap, char *);
143                 dst = (a->a_tid != NULL ? a->a_tid->name : a->a_name);
144                 pth_util_cpystrn(dst, src, PTH_TCB_NAMELEN);
145             }
146             else {
147                 char *src, **dst;
148                 src = (a->a_tid != NULL ? a->a_tid->name : a->a_name);
149                 dst = va_arg(ap, char **);
150                 *dst = src;
151             }
152             break;
153         }
154         case PTH_ATTR_DISPATCHES: {
155             /* incremented on every context switch */
156             int val, *src, *dst;
157             if (cmd == PTH_ATTR_SET) {
158                 src = &val; val = va_arg(ap, int);
159                 dst = (a->a_tid != NULL ? &a->a_tid->dispatches : &a->a_dispatches);
160             }
161             else {
162                 src = (a->a_tid != NULL ? &a->a_tid->dispatches : &a->a_dispatches);
163                 dst = va_arg(ap, int *);
164             }
165             *dst = *src;
166             break;
167         }
168         case PTH_ATTR_JOINABLE: {
169             /* detachment type */
170             int val, *src, *dst;
171             if (cmd == PTH_ATTR_SET) {
172                 src = &val; val = va_arg(ap, int);
173                 dst = (a->a_tid != NULL ? &a->a_tid->joinable : &a->a_joinable);
174             }
175             else {
176                 src = (a->a_tid != NULL ? &a->a_tid->joinable : &a->a_joinable);
177                 dst = va_arg(ap, int *);
178             }
179             *dst = *src;
180             break;
181         }
182         case PTH_ATTR_CANCEL_STATE: {
183             /* cancellation state */
184             unsigned int val, *src, *dst;
185             if (cmd == PTH_ATTR_SET) {
186                 src = &val; val = va_arg(ap, unsigned int);
187                 dst = (a->a_tid != NULL ? &a->a_tid->cancelstate : &a->a_cancelstate);
188             }
189             else {
190                 src = (a->a_tid != NULL ? &a->a_tid->cancelstate : &a->a_cancelstate);
191                 dst = va_arg(ap, unsigned int *);
192             }
193             *dst = *src;
194             break;
195         }
196         case PTH_ATTR_STACK_SIZE: {
197             /* stack size */
198             unsigned int val, *src, *dst;
199             if (cmd == PTH_ATTR_SET) {
200                 if (a->a_tid != NULL)
201                     return pth_error(FALSE, EPERM);
202                 src = &val; val = va_arg(ap, unsigned int);
203                 dst = &a->a_stacksize;
204             }
205             else {
206                 src = (a->a_tid != NULL ? &a->a_tid->stacksize : &a->a_stacksize);
207                 dst = va_arg(ap, unsigned int *);
208             }
209             *dst = *src;
210             break;
211         }
212         case PTH_ATTR_STACK_ADDR: {
213             /* stack address */
214             char *val, **src, **dst;
215             if (cmd == PTH_ATTR_SET) {
216                 if (a->a_tid != NULL)
217                     return pth_error(FALSE, EPERM);
218                 src = &val; val = va_arg(ap, char *);
219                 dst = &a->a_stackaddr;
220             }
221             else {
222                 src = (a->a_tid != NULL ? &a->a_tid->stack : &a->a_stackaddr);
223                 dst = va_arg(ap, char **);
224             }
225             *dst = *src;
226             break;
227         }
228         case PTH_ATTR_TIME_SPAWN: {
229             pth_time_t *dst;
230             pth_itime_t dst1;
231             if (cmd == PTH_ATTR_SET)
232                 return pth_error(FALSE, EPERM);
233             dst = va_arg(ap, pth_time_t *);
234             if (a->a_tid != NULL)
235                 pth_time_set(&dst1, &a->a_tid->spawned);
236             else
237                 pth_time_set(&dst1, PTH_TIME_ZERO);
238 	    pth_itime_to_time(dst, &dst1);
239             break;
240         }
241         case PTH_ATTR_TIME_LAST: {
242             pth_time_t *dst;
243             pth_itime_t dst1;
244             if (cmd == PTH_ATTR_SET)
245                 return pth_error(FALSE, EPERM);
246             dst = va_arg(ap, pth_time_t *);
247             if (a->a_tid != NULL)
248                 pth_time_set(&dst1, &a->a_tid->lastran);
249             else
250                 pth_time_set(&dst1, PTH_TIME_ZERO);
251 	    pth_itime_to_time(dst, &dst1);
252             break;
253         }
254         case PTH_ATTR_TIME_RAN: {
255             pth_time_t *dst;
256             pth_itime_t dst1;
257             if (cmd == PTH_ATTR_SET)
258                 return pth_error(FALSE, EPERM);
259             dst = va_arg(ap, pth_time_t *);
260             if (a->a_tid != NULL)
261                 pth_time_set(&dst1, &a->a_tid->running);
262             else
263                 pth_time_set(&dst1, PTH_TIME_ZERO);
264 	    pth_itime_to_time_iv(dst, &dst1);
265             break;
266         }
267         case PTH_ATTR_START_FUNC: {
268             void *(**dst)(void *);
269             if (cmd == PTH_ATTR_SET)
270                 return pth_error(FALSE, EPERM);
271             if (a->a_tid == NULL)
272                 return pth_error(FALSE, EACCES);
273             dst = (void *(**)(void *))va_arg(ap, void *);
274             *dst = a->a_tid->start_func;
275             break;
276         }
277         case PTH_ATTR_START_ARG: {
278             void **dst;
279             if (cmd == PTH_ATTR_SET)
280                 return pth_error(FALSE, EPERM);
281             if (a->a_tid == NULL)
282                 return pth_error(FALSE, EACCES);
283             dst = va_arg(ap, void **);
284             *dst = a->a_tid->start_arg;
285             break;
286         }
287         case PTH_ATTR_STATE: {
288             pth_state_t *dst;
289             if (cmd == PTH_ATTR_SET)
290                 return pth_error(FALSE, EPERM);
291             if (a->a_tid == NULL)
292                 return pth_error(FALSE, EACCES);
293             dst = va_arg(ap, pth_state_t *);
294             *dst = a->a_tid->state;
295             break;
296         }
297         case PTH_ATTR_EVENTS: {
298             pth_event_t *dst;
299             if (cmd == PTH_ATTR_SET)
300                 return pth_error(FALSE, EPERM);
301             if (a->a_tid == NULL)
302                 return pth_error(FALSE, EACCES);
303             dst = va_arg(ap, pth_event_t *);
304             *dst = a->a_tid->events;
305             break;
306         }
307         case PTH_ATTR_BOUND: {
308             int *dst;
309             if (cmd == PTH_ATTR_SET)
310                 return pth_error(FALSE, EPERM);
311             dst = va_arg(ap, int *);
312             *dst = (a->a_tid != NULL ? TRUE : FALSE);
313             break;
314         }
315         default:
316             return pth_error(FALSE, EINVAL);
317     }
318     return TRUE;
319 }
320 
321