Skip to content

Commit fcd139d

Browse files
committed
posix: pthread: support stack sizes larger than 65k
A previous size optimization capped the pthread_attr_t stacksize property at 65536. Some Zephyr users felt that was not large enough for specific use cases. Modify struct pthread_attr to support large stack sizes by default with the flexibility to allow users to vary the number of bits used for both stacksizes and guardsizes. The default guardsize remains zero sinze Zephyr's stack allocators already pad stacks with a guard area based on other config parameters, and since Zephyr is already designed to support both SW and HW stack protection at the kernel layer. Signed-off-by: Christopher Friedt <[email protected]>
1 parent beb43bd commit fcd139d

File tree

4 files changed

+70
-63
lines changed

4 files changed

+70
-63
lines changed

include/zephyr/posix/posix_types.h

+2-8
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,9 @@ typedef unsigned long timer_t;
3838
/* Thread attributes */
3939
struct pthread_attr {
4040
void *stack;
41-
uint16_t stacksize;
42-
uint16_t guardsize;
43-
int8_t priority;
44-
uint8_t schedpolicy: 2;
45-
uint8_t guardsize_msbit: 1;
46-
bool initialized: 1;
47-
bool cancelstate: 1;
48-
bool detachstate: 1;
41+
uint32_t details[2];
4942
};
43+
5044
#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \
5145
|| defined(CONFIG_ARCMWDT_LIBC)
5246
typedef struct pthread_attr pthread_attr_t;

lib/posix/Kconfig.pthread

+20-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,28 @@ config PTHREAD_RECYCLER_DELAY_MS
2727
Note: this option should be considered temporary and will likely be
2828
removed once a more synchronous solution is available.
2929

30+
config POSIX_PTHREAD_ATTR_STACKSIZE_BITS
31+
int "Significant bits for pthread_attr_t stacksize"
32+
range 8 31
33+
default 23
34+
help
35+
This value plays a part in determining the maximum supported
36+
pthread_attr_t stacksize. Valid stacksizes are in the range
37+
[1, N], where N = 1 << M, and M is this configuration value.
38+
39+
config POSIX_PTHREAD_ATTR_GUARDSIZE_BITS
40+
int "Significant bits for pthread_attr_t guardsize"
41+
range 1 31
42+
default 9
43+
help
44+
This value plays a part in determining the maximum supported
45+
pthread_attr_t guardsize. Valid guardsizes are in the range
46+
[0, N-1], where N = 1 << M, and M is this configuration value.
47+
48+
Actual guardsize values may be rounded-up.
49+
3050
config POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT
3151
int "Default size of stack guard area"
32-
range 0 65536
3352
default 0
3453
help
3554
This is the default amount of space to reserve at the overflow end of a

lib/posix/posix_internal.h

+12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222
*/
2323
#define PTHREAD_OBJ_MASK_INIT 0x80000000
2424

25+
struct posix_thread_attr {
26+
void *stack;
27+
/* the following two bitfields should combine to be 32-bits in size */
28+
uint32_t stacksize : CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS;
29+
uint16_t guardsize : CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS;
30+
int8_t priority;
31+
uint8_t schedpolicy: 2;
32+
bool initialized: 1;
33+
bool cancelstate: 1;
34+
bool detachstate: 1;
35+
};
36+
2537
struct posix_thread {
2638
struct k_thread thread;
2739

lib/posix/pthread.c

+36-54
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
POSIX_TO_ZEPHYR_PRIORITY(K_LOWEST_APPLICATION_THREAD_PRIO, DEFAULT_PTHREAD_POLICY)
3030
#define DEFAULT_PTHREAD_POLICY (IS_ENABLED(CONFIG_PREEMPT_ENABLED) ? SCHED_RR : SCHED_FIFO)
3131

32+
#define PTHREAD_STACK_MAX BIT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS)
33+
#define PTHREAD_GUARD_MAX BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS)
34+
3235
LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL);
3336

3437
#ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE
@@ -37,28 +40,14 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL);
3740
#define DYNAMIC_STACK_SIZE 0
3841
#endif
3942

40-
/* The maximum allowed stack size (for this implementation) */
41-
#define PTHREAD_STACK_MAX (UINT16_MAX + 1)
42-
43-
static inline size_t __get_attr_stacksize(const struct pthread_attr *attr)
43+
static inline size_t __get_attr_stacksize(const struct posix_thread_attr *attr)
4444
{
4545
return attr->stacksize + 1;
4646
}
4747

48-
static inline void __set_attr_stacksize(struct pthread_attr *attr, size_t size)
49-
{
50-
attr->stacksize = size - 1;
51-
}
52-
53-
static inline size_t __get_attr_guardsize(const struct pthread_attr *attr)
48+
static inline void __set_attr_stacksize(struct posix_thread_attr *attr, size_t stacksize)
5449
{
55-
return (attr->guardsize_msbit * BIT(16)) | attr->guardsize;
56-
}
57-
58-
static inline void __set_attr_guardsize(struct pthread_attr *attr, size_t size)
59-
{
60-
attr->guardsize_msbit = size == PTHREAD_STACK_MAX;
61-
attr->guardsize = size & BIT_MASK(16);
50+
attr->stacksize = stacksize - 1;
6251
}
6352

6453
struct __pthread_cleanup {
@@ -76,7 +65,7 @@ enum posix_thread_qid {
7665
POSIX_THREAD_DONE_Q,
7766
};
7867

79-
/* only 2 bits in struct pthread_attr for schedpolicy */
68+
/* only 2 bits in struct posix_thread_attr for schedpolicy */
8069
BUILD_ASSERT(SCHED_OTHER < BIT(2) && SCHED_FIFO < BIT(2) && SCHED_RR < BIT(2));
8170

8271
BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) &&
@@ -85,6 +74,9 @@ BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) &&
8574
BUILD_ASSERT((PTHREAD_CANCEL_ENABLE == 0 || PTHREAD_CANCEL_DISABLE == 0) &&
8675
(PTHREAD_CANCEL_ENABLE == 1 || PTHREAD_CANCEL_DISABLE == 1));
8776

77+
BUILD_ASSERT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS + CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS <=
78+
32);
79+
8880
static void posix_thread_recycle(void);
8981
static sys_dlist_t ready_q = SYS_DLIST_STATIC_INIT(&ready_q);
9082
static sys_dlist_t run_q = SYS_DLIST_STATIC_INIT(&run_q);
@@ -93,18 +85,6 @@ static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT];
9385
static struct k_spinlock pthread_pool_lock;
9486
static int pthread_concurrency;
9587

96-
static const struct pthread_attr init_pthread_attrs = {
97-
.stack = NULL,
98-
.stacksize = 0,
99-
.guardsize = (BIT_MASK(16) & CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT),
100-
.priority = DEFAULT_PTHREAD_PRIORITY,
101-
.schedpolicy = DEFAULT_PTHREAD_POLICY,
102-
.guardsize_msbit = (BIT(16) & CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT),
103-
.initialized = true,
104-
.cancelstate = PTHREAD_CANCEL_ENABLE,
105-
.detachstate = PTHREAD_CREATE_JOINABLE,
106-
};
107-
10888
/*
10989
* We reserve the MSB to mark a pthread_t as initialized (from the
11090
* perspective of the application). With a linear space, this means that
@@ -262,7 +242,7 @@ static int32_t posix_to_zephyr_priority(uint32_t priority, int policy)
262242
*/
263243
int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param *schedparam)
264244
{
265-
struct pthread_attr *attr = (struct pthread_attr *)_attr;
245+
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;
266246
int priority = schedparam->sched_priority;
267247

268248
if (attr == NULL || !attr->initialized ||
@@ -282,7 +262,7 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param *
282262
*/
283263
int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksize)
284264
{
285-
struct pthread_attr *attr = (struct pthread_attr *)_attr;
265+
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;
286266

287267
if (stackaddr == NULL) {
288268
LOG_ERR("NULL stack address");
@@ -299,7 +279,7 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi
299279
return 0;
300280
}
301281

302-
static bool pthread_attr_is_valid(const struct pthread_attr *attr)
282+
static bool pthread_attr_is_valid(const struct posix_thread_attr *attr)
303283
{
304284
/* auto-alloc thread stack */
305285
if (attr == NULL) {
@@ -438,19 +418,19 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou
438418
k_spinlock_key_t key;
439419
pthread_barrier_t barrier;
440420
struct posix_thread *t = NULL;
441-
struct pthread_attr attr_storage = init_pthread_attrs;
442-
struct pthread_attr *attr = (struct pthread_attr *)_attr;
421+
struct posix_thread_attr attr_storage;
422+
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;
443423

444424
if (!pthread_attr_is_valid(attr)) {
445425
return EINVAL;
446426
}
447427

448428
if (attr == NULL) {
449429
attr = &attr_storage;
430+
(void)pthread_attr_init((pthread_attr_t *)attr);
450431
BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX);
451432
__set_attr_stacksize(attr, DYNAMIC_STACK_SIZE);
452-
attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr) +
453-
__get_attr_guardsize(attr),
433+
attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr) + attr->guardsize,
454434
k_is_user_context() ? K_USER : 0);
455435
if (attr->stack == NULL) {
456436
LOG_ERR("Unable to allocate stack of size %u", DYNAMIC_STACK_SIZE);
@@ -505,7 +485,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou
505485
}
506486

507487
/* spawn the thread */
508-
k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper,
488+
k_thread_create(&t->thread, attr->stack, __get_attr_stacksize(attr), zephyr_thread_wrapper,
509489
(void *)arg, threadroutine,
510490
IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) : NULL,
511491
posix_to_zephyr_priority(attr->priority, attr->schedpolicy), 0, K_NO_WAIT);
@@ -680,14 +660,16 @@ int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_para
680660
*/
681661
int pthread_attr_init(pthread_attr_t *_attr)
682662
{
683-
struct pthread_attr *const attr = (struct pthread_attr *)_attr;
663+
struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr;
684664

685665
if (attr == NULL) {
686666
LOG_ERR("Invalid attr pointer");
687667
return ENOMEM;
688668
}
689669

690-
(void)memcpy(attr, &init_pthread_attrs, sizeof(struct pthread_attr));
670+
*attr = (struct posix_thread_attr){0};
671+
attr->guardsize = CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT;
672+
attr->initialized = true;
691673

692674
return 0;
693675
}
@@ -883,7 +865,7 @@ int pthread_detach(pthread_t pthread)
883865
*/
884866
int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate)
885867
{
886-
const struct pthread_attr *attr = (const struct pthread_attr *)_attr;
868+
const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr;
887869

888870
if ((attr == NULL) || (attr->initialized == false)) {
889871
return EINVAL;
@@ -900,7 +882,7 @@ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate)
900882
*/
901883
int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate)
902884
{
903-
struct pthread_attr *attr = (struct pthread_attr *)_attr;
885+
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;
904886

905887
if ((attr == NULL) || (attr->initialized == false) ||
906888
((detachstate != PTHREAD_CREATE_DETACHED) &&
@@ -919,7 +901,7 @@ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate)
919901
*/
920902
int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy)
921903
{
922-
const struct pthread_attr *attr = (const struct pthread_attr *)_attr;
904+
const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr;
923905

924906
if ((attr == NULL) || (attr->initialized == 0U)) {
925907
return EINVAL;
@@ -936,7 +918,7 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy)
936918
*/
937919
int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy)
938920
{
939-
struct pthread_attr *attr = (struct pthread_attr *)_attr;
921+
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;
940922

941923
if ((attr == NULL) || (attr->initialized == 0U) || !valid_posix_policy(policy)) {
942924
return EINVAL;
@@ -953,7 +935,7 @@ int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy)
953935
*/
954936
int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize)
955937
{
956-
const struct pthread_attr *attr = (const struct pthread_attr *)_attr;
938+
const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr;
957939

958940
if ((attr == NULL) || (attr->initialized == false)) {
959941
return EINVAL;
@@ -970,7 +952,7 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize)
970952
*/
971953
int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize)
972954
{
973-
struct pthread_attr *attr = (struct pthread_attr *)_attr;
955+
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;
974956

975957
if ((attr == NULL) || (attr->initialized == 0U)) {
976958
return EINVAL;
@@ -991,7 +973,7 @@ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize)
991973
*/
992974
int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t *stacksize)
993975
{
994-
const struct pthread_attr *attr = (const struct pthread_attr *)_attr;
976+
const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr;
995977

996978
if ((attr == NULL) || (attr->initialized == false)) {
997979
return EINVAL;
@@ -1004,26 +986,26 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t
1004986

1005987
int pthread_attr_getguardsize(const pthread_attr_t *ZRESTRICT _attr, size_t *ZRESTRICT guardsize)
1006988
{
1007-
struct pthread_attr *const attr = (struct pthread_attr *)_attr;
989+
struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr;
1008990

1009991
if (attr == NULL || guardsize == NULL || !attr->initialized) {
1010992
return EINVAL;
1011993
}
1012994

1013-
*guardsize = __get_attr_guardsize(attr);
995+
*guardsize = attr->guardsize;
1014996

1015997
return 0;
1016998
}
1017999

10181000
int pthread_attr_setguardsize(pthread_attr_t *_attr, size_t guardsize)
10191001
{
1020-
struct pthread_attr *const attr = (struct pthread_attr *)_attr;
1002+
struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr;
10211003

1022-
if (attr == NULL || !attr->initialized || guardsize > PTHREAD_STACK_MAX) {
1004+
if (attr == NULL || !attr->initialized || guardsize > PTHREAD_GUARD_MAX) {
10231005
return EINVAL;
10241006
}
10251007

1026-
__set_attr_guardsize(attr, guardsize);
1008+
attr->guardsize = guardsize;
10271009

10281010
return 0;
10291011
}
@@ -1035,7 +1017,7 @@ int pthread_attr_setguardsize(pthread_attr_t *_attr, size_t guardsize)
10351017
*/
10361018
int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param *schedparam)
10371019
{
1038-
struct pthread_attr *attr = (struct pthread_attr *)_attr;
1020+
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;
10391021

10401022
if ((attr == NULL) || (attr->initialized == false)) {
10411023
return EINVAL;
@@ -1052,7 +1034,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param *
10521034
*/
10531035
int pthread_attr_destroy(pthread_attr_t *_attr)
10541036
{
1055-
struct pthread_attr *attr = (struct pthread_attr *)_attr;
1037+
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;
10561038

10571039
if ((attr != NULL) && (attr->initialized != 0U)) {
10581040
attr->initialized = false;

0 commit comments

Comments
 (0)