1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2010-10-26 Bernard the first version
9 */
10
11 #include <rtthread.h>
12 #include "pthread.h"
13 #include "sched.h"
14 #include <string.h>
15
16 #define DEFAULT_STACK_SIZE 2048
17 #define DEFAULT_PRIORITY (RT_THREAD_PRIORITY_MAX/2 + RT_THREAD_PRIORITY_MAX/4)
18
19 const pthread_attr_t pthread_default_attr =
20 {
21 0, /* stack base */
22 DEFAULT_STACK_SIZE, /* stack size */
23
24 PTHREAD_INHERIT_SCHED, /* Inherit parent prio/policy */
25 SCHED_FIFO, /* scheduler policy */
26 {
27 DEFAULT_PRIORITY, /* scheduler priority */
28 },
29 PTHREAD_CREATE_JOINABLE, /* detach state */
30 };
31
32 /**
33 * @brief This function will initialize thread attributes object.
34 *
35 * @note The pthread_attr_t type should be treated as opaque: any access to the object other
36 * than via pthreads functions is nonportable and produces undefined results.
37 * The resulting attribute object (possibly modified by setting individual attribute values),
38 * when used by pthread_create(), defines the attributes of the thread created. A single attributes
39 * object can be used in multiple simultaneous calls to pthread_create().
40 *
41 * @see pthread_create()
42 *
43 * @param attr is a thread attributes object.
44 *
45 * @return Upon successful completion, pthread_attr_init() return a value of 0.
46 * Otherwise, it means that the event detach failed.
47 *
48 * @warning This function will fail if attr is null.
49 */
pthread_attr_init(pthread_attr_t * attr)50 int pthread_attr_init(pthread_attr_t *attr)
51 {
52 RT_ASSERT(attr != RT_NULL);
53
54 *attr = pthread_default_attr;
55
56 return 0;
57 }
58 RTM_EXPORT(pthread_attr_init);
59
60 /**
61 * @brief This function will destroy thread attributes object.
62 *
63 * @note When a thread attributes object is no longer required, it should be destroyed
64 * using the pthread_attr_destroy() function. Destroying a thread attributes object
65 * has no effect on threads that were created using that object.
66 * Once a thread attributes object has been destroyed, it can be reinitialized using pthread_attr_init().
67 * Any other use of a destroyed thread attributes object has undefined results.
68 *
69 * @see pthread_attr_init(), pthread_attr_getdetachstate(), pthread_create()
70 *
71 * @param attr is a thread attributes object.
72 *
73 * @return Upon successful completion, pthread_attr_destroy() and shall return a value of 0;
74 * Otherwise, an error number shall be returned to indicate the error.
75 *
76 * @warning This function will fail if attr is null.
77 */
pthread_attr_destroy(pthread_attr_t * attr)78 int pthread_attr_destroy(pthread_attr_t *attr)
79 {
80 RT_ASSERT(attr != RT_NULL);
81
82 memset(attr, 0, sizeof(pthread_attr_t));
83
84 return 0;
85 }
86 RTM_EXPORT(pthread_attr_destroy);
87
88 /**
89 * @brief This function set detach state attribute in thread attributes object.
90 *
91 * @note This function sets the detach state attribute of the thread attributes object
92 * referred to by attr to the value specified in detachstate. The detach state
93 * attribute determines whether a thread created using the thread attributes
94 * object attr will be created in a joinable or a detached state.
95 *
96 * @see pthread_attr_init(), pthread_create(), pthread_detach(), pthread_join(), pthreads()
97 *
98 * @param attr is a thread attributes object.
99 *
100 * @param state is attribute in the attr object.
101 * attribute controls whether the thread is created in a detached state.
102 * The detachstate can be ONE of the following values:
103 *
104 * PTHREAD_CREATE_DETACHED It causes all threads created with attr to be in the detached state.
105 *
106 * PTHREAD_CREATE_JOINABLE Default value, it causes all threads created with attr to be in the joinable state.
107 *
108 * @return Upon successful completion, pthread_attr_setdetachstate() and return a value of 0.
109 * Otherwise, an error number is returned to indicate the error.
110 *
111 * @warning The pthread_attr_setdetachstate() function will fail if:
112 * [EINVAL]
113 * The value of detach state was not valid
114 */
pthread_attr_setdetachstate(pthread_attr_t * attr,int state)115 int pthread_attr_setdetachstate(pthread_attr_t *attr, int state)
116 {
117 RT_ASSERT(attr != RT_NULL);
118
119 if (state != PTHREAD_CREATE_JOINABLE && state != PTHREAD_CREATE_DETACHED)
120 return EINVAL;
121
122 attr->detachstate = state;
123
124 return 0;
125 }
126 RTM_EXPORT(pthread_attr_setdetachstate);
127
128 /**
129 * @brief This function get detach state attribute in thread attributes object.
130 *
131 * @note The detachstate attribute controls whether the thread is created in a detached state.
132 * If the thread is created detached, then use of the ID of the newly created thread by
133 * the pthread_detach() or pthread_join() function is an error.
134 *
135 * @see pthread_attr_destroy(), pthread_attr_getstackaddr(), pthread_attr_getstacksize(), pthread_create()
136 *
137 * @param attr is a thread attributes object.
138 *
139 * @param state is attribute in the attr object.
140 * attribute controls whether the thread is created in a detached state.
141 * The detachstate can be ONE of the following values:
142 *
143 * PTHREAD_CREATE_DETACHED It causes all threads created with attr to be in the detached state.
144 *
145 * PTHREAD_CREATE_JOINABLE Default value, it causes all threads created with attr to be in the joinable state.
146 *
147 * @return Upon successful completion, pthread_attr_getdetachstate() and shall return a value of 0;
148 * otherwise, an error number shall be returned to indicate the error.
149 *
150 * The pthread_attr_getdetachstate() function stores the value of the detachstate
151 * attribute in detachstate if successful.
152 */
pthread_attr_getdetachstate(pthread_attr_t const * attr,int * state)153 int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state)
154 {
155 RT_ASSERT(attr != RT_NULL);
156
157 *state = (int)attr->detachstate;
158
159 return 0;
160 }
161 RTM_EXPORT(pthread_attr_getdetachstate);
162
163 /**
164 * @brief This function sets schedpolicy attribute.
165 *
166 * @note The function function sets the scheduling policy attribute of the thread
167 * attributes object referred to by attr to the value specified in policy.
168 *
169 * @see pthread_attr_init(), pthread_attr_setscope(), pthread_attr_setinheritsched(), pthread_attr_setschedparam(), pthread_create()
170 *
171 * @param attr is a thread attributes object.
172 *
173 * @param policy is attribute in the attr object.
174 * The policy can be ONE of the following values:
175 *
176 * SCHED_FIFO First in-first out scheduling.
177 *
178 * SCHED_RR Round-robin scheduling.
179 *
180 * SCHED_OTHER Default Linux time-sharing scheduling.
181 *
182 * @return On success, these functions return 0.
183 */
pthread_attr_setschedpolicy(pthread_attr_t * attr,int policy)184 int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
185 {
186 RT_ASSERT(attr != RT_NULL);
187
188 attr->schedpolicy = policy;
189
190 return 0;
191 }
192 RTM_EXPORT(pthread_attr_setschedpolicy);
193
194 /**
195 * @brief This function gets schedpolicy attribute.
196 *
197 * @note The function gets the schedpolicy attribute in the attr argument.
198 *
199 * @see pthread_attr_destroy(), pthread_attr_getscope(), pthread_attr_getinheritsched(), pthread_attr_getschedparam(), pthread_create()
200 *
201 * @param attr is a thread attributes object.
202 *
203 * @param policy is attribute in the attr object.
204 * The policy can be ONE of the following values:
205 *
206 * SCHED_FIFO First in-first out scheduling.
207 *
208 * SCHED_RR Round-robin scheduling.
209 *
210 * SCHED_OTHER Default Linux time-sharing scheduling.
211 *
212 * @return On success, these functions return 0.
213 */
pthread_attr_getschedpolicy(pthread_attr_t const * attr,int * policy)214 int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy)
215 {
216 RT_ASSERT(attr != RT_NULL);
217
218 *policy = (int)attr->schedpolicy;
219
220 return 0;
221 }
222 RTM_EXPORT(pthread_attr_getschedpolicy);
223
224 /**
225 * @brief This function set the scheduling parameter attributes in the attr argument.
226
227 * @see pthread_attr_init(), pthread_attr_setscope(), pthread_attr_setinheritsched(), pthread_attr_setschedpolicy()
228 *
229 * @param attr is a thread attributes object.
230 *
231 * @param param is scheduling parameter attributes in the attr argument.
232 * The contents of the param structure are defined in <pthread.h>.
233 * For the SCHED_FIFO and SCHED_RR policies, the only required member of param is sched_priority.
234 *
235 * @return On success, these functions return 0.
236 */
pthread_attr_setschedparam(pthread_attr_t * attr,struct sched_param const * param)237 int pthread_attr_setschedparam(pthread_attr_t *attr,
238 struct sched_param const *param)
239 {
240 RT_ASSERT(attr != RT_NULL);
241 RT_ASSERT(param != RT_NULL);
242
243 attr->schedparam.sched_priority = param->sched_priority;
244
245 return 0;
246 }
247 RTM_EXPORT(pthread_attr_setschedparam);
248
249 /**
250 * @brief This function get the scheduling parameter attributes in the attr argument.
251
252 * @see pthread_attr_init(), pthread_attr_setscope(), pthread_attr_setinheritsched(), pthread_attr_setschedpolicy()
253 *
254 * @param attr is a thread attributes object.
255 *
256 * @param param is scheduling parameter attributes in the attr argument.
257 * The contents of the param structure are defined in <pthread.h>.
258 * For the SCHED_FIFO and SCHED_RR policies, the only required member of param is sched_priority.
259 *
260 * @return On success, these functions return 0.
261 */
pthread_attr_getschedparam(pthread_attr_t const * attr,struct sched_param * param)262 int pthread_attr_getschedparam(pthread_attr_t const *attr,
263 struct sched_param *param)
264 {
265 RT_ASSERT(attr != RT_NULL);
266 RT_ASSERT(param != RT_NULL);
267
268 param->sched_priority = attr->schedparam.sched_priority;
269
270 return 0;
271 }
272 RTM_EXPORT(pthread_attr_getschedparam);
273
274 /**
275 * @brief This function set the thread creation stacksize attribute in the attr object.
276 *
277 * @see pthread_attr_init(), pthread_attr_setstackaddr(), pthread_attr_setdetachstate()
278 *
279 * @param attr is a thread attributes object.
280 *
281 * @param stack_size is the minimum stack size (in bytes) allocated for the created threads stack.
282 *
283 * @return Upon successful completion, This function return a value of 0.
284 */
pthread_attr_setstacksize(pthread_attr_t * attr,size_t stack_size)285 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size)
286 {
287 RT_ASSERT(attr != RT_NULL);
288
289 attr->stacksize = stack_size;
290
291 return 0;
292 }
293 RTM_EXPORT(pthread_attr_setstacksize);
294
295 /**
296 * @brief This function get the thread creation stacksize attribute in the attr object.
297 *
298 * @see pthread_attr_init(), pthread_attr_getstackaddr(), pthread_attr_getdetachstate()
299 *
300 * @param attr is a thread attributes object.
301 *
302 * @param stack_size is the minimum stack size (in bytes) allocated for the created threads stack.
303 *
304 * @return Upon successful completion, This function return a value of 0.
305 */
pthread_attr_getstacksize(pthread_attr_t const * attr,size_t * stack_size)306 int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size)
307 {
308 RT_ASSERT(attr != RT_NULL);
309
310 *stack_size = attr->stacksize;
311
312 return 0;
313 }
314 RTM_EXPORT(pthread_attr_getstacksize);
315
316 /**
317 * @brief This function sets the thread creation stackaddr attribute in the attr object.
318 *
319 * @see pthread_attr_init(), pthread_attr_setdetachstate(), pthread_attr_setstacksize()
320 *
321 * @param attr is a thread attributes object.
322 *
323 * @param The stack_addr attribute specifies the location of storage to be used for the created
324 * thread's stack.
325 *
326 * @return Upon successful completion, This function return a value of 0.
327 */
pthread_attr_setstackaddr(pthread_attr_t * attr,void * stack_addr)328 int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr)
329 {
330 RT_ASSERT(attr != RT_NULL);
331
332 return EOPNOTSUPP;
333 }
334 RTM_EXPORT(pthread_attr_setstackaddr);
335
336 /**
337 * @brief This function gets the thread creation stackaddr attribute in the attr object.
338 *
339 * @see pthread_attr_init(), pthread_attr_setdetachstate(), pthread_attr_setstacksize()
340 *
341 * @param attr is a thread attributes object.
342 *
343 * @param The stack_addr attribute specifies the location of storage to be used for the created
344 * thread's stack.
345 *
346 * @return Upon successful completion, This function return a value of 0.
347 */
pthread_attr_getstackaddr(pthread_attr_t const * attr,void ** stack_addr)348 int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr)
349 {
350 RT_ASSERT(attr != RT_NULL);
351
352 return EOPNOTSUPP;
353 }
354 RTM_EXPORT(pthread_attr_getstackaddr);
355
356 /**
357 * @brief This function set the thread creation stack attributes stackaddr and stacksize in the attr object.
358 *
359 * @note The stack attributes specify the area of storage to be used for the created thread's stack.
360 * The base (lowest addressable byte) of the storage shall be stack_base, and the size of the storage
361 * shall be stack_size bytes.
362 * All pages within the stack described by stackaddr and stacksize shall be both readable
363 * and writable by the thread.
364 *
365 * @see pthread_attr_destroy, pthread_attr_getdetachstate, pthread_attr_getstacksize, pthread_create
366 *
367 * @param attr is a thread attributes object.
368 *
369 * @param stack_base is the base (lowest addressable byte) of the storage.
370 *
371 * @param stack_size is the size of the storage.
372 *
373 * @return Upon successful completion, these functions shall return a value of 0;
374 * otherwise, an error number shall be returned to indicate the error.
375 *
376 * @warning The behavior is undefined if the value specified by the attr argument to or pthread_attr_setstack()
377 * does not refer to an initialized thread attributes object.
378 */
pthread_attr_setstack(pthread_attr_t * attr,void * stack_base,size_t stack_size)379 int pthread_attr_setstack(pthread_attr_t *attr,
380 void *stack_base,
381 size_t stack_size)
382 {
383 RT_ASSERT(attr != RT_NULL);
384
385 attr->stackaddr = stack_base;
386 attr->stacksize = RT_ALIGN_DOWN(stack_size, RT_ALIGN_SIZE);
387
388 return 0;
389 }
390 RTM_EXPORT(pthread_attr_setstack);
391
392 /**
393 * @brief This function shall get the thread creation stack attributes stackaddr and stacksize in the attr object.
394 *
395 * @note The stack attributes specify the area of storage to be used for the created thread's stack.
396 * The base (lowest addressable byte) of the storage shall be stack_base, and the size of the storage
397 * shall be stack_size bytes.
398 * All pages within the stack described by stack_base and stack_size shall be both readable
399 * and writable by the thread.
400 *
401 * @see pthread_attr_destroy, pthread_attr_getdetachstate, pthread_attr_getstacksize, pthread_create
402 *
403 * @param attr is a thread attributes object.
404 *
405 * @param stack_base is the base (lowest addressable byte) of the storage.
406 *
407 * @param stack_size is the size of the storage.
408 *
409 * @return Upon successful completion, these functions shall return a value of 0;
410 * otherwise, an error number shall be returned to indicate the error.
411 * This function shall store the stack attribute values in stack_base and stack_size if successful.
412 */
pthread_attr_getstack(pthread_attr_t const * attr,void ** stack_base,size_t * stack_size)413 int pthread_attr_getstack(pthread_attr_t const *attr,
414 void **stack_base,
415 size_t *stack_size)
416 {
417 RT_ASSERT(attr != RT_NULL);
418
419 *stack_base = attr->stackaddr;
420 *stack_size = attr->stacksize;
421
422 return 0;
423 }
424 RTM_EXPORT(pthread_attr_getstack);
425
426 /**
427 * @brief This function shall set the guardsize attribute in the attr object.
428 *
429 * @note The guardsize attribute controls the size of the guard area for the created thread's stack.
430 * The guardsize attribute provides protection against overflow of the stack pointer.
431 * If a thread's stack is created with guard protection, the implementation allocates extra
432 * memory at the overflow end of the stack as a buffer against stack overflow of the stack pointer.
433 * If an application overflows into this buffer an error shall result (possibly in a SIGSEGV signal
434 * being delivered to the thread).
435 *
436 * @see <pthread.h>, <sys/mman.h>
437 *
438 * @param attr is a thread attributes object.
439 *
440 * @param guard_size is the size of the guard area for the created thread's stack.
441 *
442 * @return Upon successful completion, these functions shall return a value of 0;
443 *
444 * @warning The guardsize attribute is provided to the application for two reasons:
445 *
446 * 1. Overflow protection can potentially result in wasted system resources.
447 * An application that creates a large number of threads, and which knows its threads
448 * never overflow their stack, can save system resources by turning off guard areas.
449 *
450 * 2. When threads allocate large data structures on the stack, large guard areas may be
451 * needed to detect stack overflow.
452 *
453 * The default size of the guard area is left implementation-defined since on systems
454 * supporting very large page sizes, the overhead might be substantial if at least one guard
455 * page is required by default.
456 */
pthread_attr_setguardsize(pthread_attr_t * attr,size_t guard_size)457 int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard_size)
458 {
459 return EOPNOTSUPP;
460 }
461
462 /**
463 * @brief This function get the guardsize attribute in the attr object.
464 * This attribute shall be returned in the guard_size parameter.
465 *
466 * @note The guardsize attribute controls the size of the guard area for the created thread's stack.
467 * The guardsize attribute provides protection against overflow of the stack pointer.
468 * If a thread's stack is created with guard protection, the implementation allocates extra
469 * memory at the overflow end of the stack as a buffer against stack overflow of the stack pointer.
470 *
471 * @see <pthread.h>, <sys/mman.h>
472 *
473 * @param attr is a thread attributes object.
474 *
475 * @param guard_size is the size of the guard area for the created thread's stack.
476 *
477 * @return Upon successful completion, these functions shall return a value of 0;
478 *
479 * @warning The guardsize attribute is provided to the application for two reasons:
480 *
481 * 1. Overflow protection can potentially result in wasted system resources.
482 * An application that creates a large number of threads, and which knows its threads
483 * never overflow their stack, can save system resources by turning off guard areas.
484 *
485 * 2. When threads allocate large data structures on the stack, large guard areas may be
486 * needed to detect stack overflow.
487 *
488 * The default size of the guard area is left implementation-defined since on systems
489 * supporting very large page sizes, the overhead might be substantial if at least one guard
490 * page is required by default.
491 */
pthread_attr_getguardsize(pthread_attr_t const * attr,size_t * guard_size)492 int pthread_attr_getguardsize(pthread_attr_t const *attr, size_t *guard_size)
493 {
494 return EOPNOTSUPP;
495 }
496 RTM_EXPORT(pthread_attr_getguardsize);
497
498 /**
499 * @brief This function sets inherit-scheduler attribute in thread attributes object.
500 *
501 * @note The function sets the inherit-scheduler attribute of the thread attributes object
502 * referred to by attr to the value specified in inheritsched.
503 * The inherit-scheduler attribute determines whether a thread created using the thread
504 * attributes object attr will inherit its scheduling attributes from the calling thread
505 * or whether it will take them from attr.
506 *
507 * @see pthread_attr_init(), pthread_attr_setschedpolicy(), pthread_attr_setschedparam()
508 *
509 * @param attr is a thread attributes object.
510 *
511 * @param inheritsched the inheritsched attribute determines how the other scheduling attributes of the created thread are to be set:
512 * The policy can be ONE of the following values:
513 *
514 * PTHREAD_INHERIT_SCHED Specifies that the scheduling policy and associated attributes are
515 * to be inherited from the creating thread, and the scheduling attributes
516 * in this attr argument are to be ignored.
517 *
518 * PTHREAD_EXPLICIT_SCHED Specifies that the scheduling policy and associated attributes are to be
519 * set to the corresponding values from this attribute object.
520 *
521 * @return Upon successful completion, these functions shall return a value of 0;
522 */
pthread_attr_setinheritsched(pthread_attr_t * attr,int inheritsched)523 int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched)
524 {
525 RT_ASSERT(attr != RT_NULL);
526
527 attr->inheritsched = inheritsched;
528
529 return 0;
530 }
531 RTM_EXPORT(pthread_attr_setinheritsched);
532
533 /**
534 * @brief This function get and set the inheritsched attribute in the attr argument.
535 *
536 * @note The function sets the inherit-scheduler attribute of the thread attributes object
537 * referred to by attr to the value specified in inheritsched.
538 * The inherit-scheduler attribute determines whether a thread created using the thread
539 * attributes object attr will inherit its scheduling attributes from the calling thread
540 * or whether it will take them from attr.
541 *
542 * @see pthread_attr_init(), pthread_attr_getschedpolicy(), pthread_attr_getschedparam()
543 *
544 * @param attr is a thread attributes object.
545 *
546 * @param inheritsched the inheritsched attribute determines how the other scheduling attributes of the created thread are to be set:
547 * The inheritsched can be ONE of the following values:
548 *
549 * PTHREAD_INHERIT_SCHED Specifies that the scheduling policy and associated attributes are
550 * to be inherited from the creating thread, and the scheduling attributes
551 * in this attr argument are to be ignored.
552 *
553 * PTHREAD_EXPLICIT_SCHED Specifies that the scheduling policy and associated attributes are to be
554 * set to the corresponding values from this attribute object.
555 *
556 * @return Upon successful completion, these functions shall return a value of 0;
557 */
pthread_attr_getinheritsched(const pthread_attr_t * attr,int * inheritsched)558 int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched)
559 {
560 RT_ASSERT(attr != RT_NULL);
561
562 *inheritsched = attr->inheritsched;
563
564 return 0;
565 }
566 RTM_EXPORT(pthread_attr_getinheritsched);
567
568 /**
569 * @brief This function set contentionscope attribute.
570 *
571 * @note The function are used to set the contentionscope attribute in the attr object.
572 *
573 * @param attr is a thread attributes object.
574 *
575 * @param scope is the value of contentionscope attribute.
576 * The scope can be ONE of the following values:
577 *
578 * PTHREAD_SCOPE_SYSTEM signifying system scheduling contention scope.
579 *
580 * PTHREAD_SCOPE_PROCESS signifying process scheduling contention scope.
581 *
582 * @return Upon successful completion, these functions shall return a value of 0;
583 */
pthread_attr_setscope(pthread_attr_t * attr,int scope)584 int pthread_attr_setscope(pthread_attr_t *attr, int scope)
585 {
586 if (scope == PTHREAD_SCOPE_SYSTEM)
587 return 0;
588 if (scope == PTHREAD_SCOPE_PROCESS)
589 return EOPNOTSUPP;
590
591 return EINVAL;
592 }
593 RTM_EXPORT(pthread_attr_setscope);
594
595 /**
596 * @brief This function get contentionscope attribute.
597 *
598 * @note The function are used to get the contentionscope attribute in the attr object.
599 *
600 * @param attr is a thread attributes object.
601 *
602 * @param scope is the value of contentionscope attribute.
603 * The scope can be ONE of the following values:
604 *
605 * PTHREAD_SCOPE_SYSTEM signifying system scheduling contention scope.
606 *
607 * PTHREAD_SCOPE_PROCESS signifying process scheduling contention scope.
608 *
609 * @return Upon successful completion, these functions shall return a value of 0;
610 */
pthread_attr_getscope(pthread_attr_t const * attr,int * scope)611 int pthread_attr_getscope(pthread_attr_t const *attr, int *scope)
612 {
613 return PTHREAD_SCOPE_SYSTEM;
614 }
615 RTM_EXPORT(pthread_attr_getscope);
616