Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: posix: auto allocate pthread stack if needed #16435

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/posix/pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ struct posix_thread {
enum pthread_state state;
pthread_mutex_t state_lock;
pthread_cond_t state_cond;

/* Auto-allocated stack */
void *auto_allocated_stack;
};

/* Pthread detach/joinable */
Expand Down Expand Up @@ -475,6 +478,7 @@ static inline int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
}

int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
Expand Down
9 changes: 9 additions & 0 deletions lib/posix/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ config MAX_PTHREAD_COUNT
help
Maximum number of simultaneously active threads in a POSIX application.

config DEFAULT_PTHREAD_STACK_SIZE
int "Default stack size used for pthreads"
default 2048 if COVERAGE_GCOV
default 1024
help
If pthread_create is called without attributes specifying that an externally
defined stack is to be used, the stack will be allocated automatically with
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"externally defined stack is to be used" might need an update now.

the size specified in this symbol.

config SEM_VALUE_MAX
int "Maximum semaphore limit"
default 32767
Expand Down
107 changes: 89 additions & 18 deletions lib/posix/pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
pthread_exit(NULL);
}

/* Helper function for stack allocation. */
static void pthread_setup_dynamic_stack(void **newstack, size_t *newsize)
{
/* If the requested size is 0, use the default stack size */
if (*newsize == 0) {
*newsize = CONFIG_DEFAULT_PTHREAD_STACK_SIZE;
}

*newstack = calloc(1, *newsize);
}

/**
* @brief Create a new thread.
*
Expand All @@ -135,14 +146,12 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *attr,
u32_t pthread_num;
pthread_condattr_t cond_attr;
struct posix_thread *thread;
void *newstack;
size_t newstacksize;
const struct pthread_attr_t *newattr;

/*
* FIXME: Pthread attribute must be non-null and it provides stack
* pointer and stack size. So even though POSIX 1003.1 spec accepts
* attrib as NULL but zephyr needs it initialized with valid stack.
*/
if ((attr == NULL) || (attr->initialized == 0U)
|| (attr->stack == NULL) || (attr->stacksize == 0)) {
if (attr != NULL && attr->initialized == 0U) {
/* Undefined behavior - don't try to do anything */
return EINVAL;
}

Expand All @@ -161,32 +170,69 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *attr,
return EAGAIN;
}

prio = posix_to_zephyr_priority(attr->priority, attr->schedpolicy);
if (attr == NULL) {
/* Use the default parameters */
newattr = &init_pthread_attrs;

/* Allocate default stack */
newstacksize = CONFIG_DEFAULT_PTHREAD_STACK_SIZE;
pthread_setup_dynamic_stack(&newstack, &newstacksize);

if (newstack == NULL) {
return EAGAIN;
}

thread->auto_allocated_stack = newstack;
} else {
/* Use the parameters from user */
newattr = attr;

if (attr->stack == NULL) {
newstacksize = attr->stacksize;
pthread_setup_dynamic_stack(&newstack, &newstacksize);

if (newstack == NULL) {
return EAGAIN;
}

thread->auto_allocated_stack = newstack;
} else {
newstack = attr->stack;
newstacksize = attr->stacksize;

thread->auto_allocated_stack = NULL;
}
}

prio = posix_to_zephyr_priority(newattr->priority,
newattr->schedpolicy);

thread = &posix_thread_pool[pthread_num];
pthread_mutex_init(&thread->state_lock, NULL);
pthread_mutex_init(&thread->cancel_lock, NULL);

pthread_mutex_lock(&thread->cancel_lock);
thread->cancel_state = (1 << _PTHREAD_CANCEL_POS) & attr->flags;
thread->cancel_state = (1 << _PTHREAD_CANCEL_POS) & newattr->flags;
thread->cancel_pending = 0;
pthread_mutex_unlock(&thread->cancel_lock);

pthread_mutex_lock(&thread->state_lock);
thread->state = attr->detachstate;
thread->state = newattr->detachstate;
pthread_mutex_unlock(&thread->state_lock);

pthread_cond_init(&thread->state_cond, &cond_attr);
sys_slist_init(&thread->key_list);

*newthread = (pthread_t) k_thread_create(&thread->thread, attr->stack,
attr->stacksize,
(k_thread_entry_t)
zephyr_thread_wrapper,
(void *)arg, NULL,
threadroutine, prio,
(~K_ESSENTIAL & attr->flags),
attr->delayedstart);
*newthread =
(pthread_t) k_thread_create(&thread->thread,
newstack,
newstacksize,
(k_thread_entry_t)
zephyr_thread_wrapper,
(void *)arg, NULL,
threadroutine, prio,
(~K_ESSENTIAL & newattr->flags),
newattr->delayedstart);
return 0;
}

Expand Down Expand Up @@ -248,6 +294,10 @@ int pthread_cancel(pthread_t pthread)
}
pthread_mutex_unlock(&thread->state_lock);

if (thread->auto_allocated_stack != NULL) {
free(thread->auto_allocated_stack);
}

k_thread_abort((k_tid_t) thread);
}

Expand Down Expand Up @@ -382,6 +432,11 @@ void pthread_exit(void *retval)
}

pthread_mutex_unlock(&self->state_lock);

if (self->auto_allocated_stack != NULL) {
free(self->auto_allocated_stack);
}

k_thread_abort((k_tid_t)self);
}

Expand Down Expand Up @@ -546,6 +601,22 @@ int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)

}

/**
* @brief Set stack size attribute in thread attributes object.
*
* See IEEE 1003.1
*/
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
if ((attr == NULL) || (attr->initialized == 0U)) {
return EINVAL;
}

attr->stacksize = stacksize;
return 0;

}

/**
* @brief Get stack attributes in thread attributes object.
*
Expand Down
1 change: 1 addition & 0 deletions tests/posix/common/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ CONFIG_SEM_VALUE_MAX=32767
CONFIG_POSIX_MQUEUE=y
CONFIG_HEAP_MEM_POOL_SIZE=4096
CONFIG_MAX_THREAD_BYTES=4
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=4096

CONFIG_SMP=n
17 changes: 15 additions & 2 deletions tests/posix/common/src/pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,23 @@

#define N_THR_E 3
#define N_THR_T 4
#define N_THR_T_AUTO_STACK 1
#define BOUNCES 64
#define STACKS (1024 + CONFIG_TEST_EXTRA_STACKSIZE)
#define THREAD_PRIORITY 3
#define ONE_SECOND 1

#if CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE < STACKS * N_THR_T_AUTO_STACK
#error "Insufficient malloc arena size"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to hit for 119 tests or so... ;-).

#endif

/* Macros to test invalid states */
#define PTHREAD_CANCEL_INVALID -1
#define SCHED_INVALID -1
#define PRIO_INVALID -1

K_THREAD_STACK_ARRAY_DEFINE(stack_e, N_THR_E, STACKS);
K_THREAD_STACK_ARRAY_DEFINE(stack_t, N_THR_T, STACKS);
K_THREAD_STACK_ARRAY_DEFINE(stack_t, N_THR_T - N_THR_T_AUTO_STACK, STACKS);

void *thread_top_exec(void *p1);
void *thread_top_term(void *p1);
Expand Down Expand Up @@ -386,7 +391,15 @@ void test_posix_pthread_termination(void)

schedparam.sched_priority = 2;
pthread_attr_setschedparam(&attr[i], &schedparam);
pthread_attr_setstack(&attr[i], &stack_t[i][0], STACKS);

if (i < N_THR_T - N_THR_T_AUTO_STACK) {
pthread_attr_setstack(&attr[i],
&stack_t[i][0],
STACKS);
} else {
pthread_attr_setstacksize(&attr[i], STACKS);
}

ret = pthread_create(&newthread[i], &attr[i], thread_top_term,
(void *)i);

Expand Down