Commit eb7e4bed authored by Christopher Friedt's avatar Christopher Friedt Committed by Fabio Baltieri
Browse files

posix: pthread_attr: use space in struct more efficiently

This change reduces the space occupied by struct pthread_attr
which is the internal type used for pthread_attr_t.

We cap the stack size at 16 bits (so up to 65536 bytes) and
since a stack size of 0 is invalid, we can encode the stack
size by simply subtracting 1 or adding 1 when setting or
getting.

The schedpolicy is capped at 2 bits and initialized,
cancellable, and detached are given 1 bit.

Signed-off-by: default avatarChristopher Friedt <cfriedt@meta.com>
parent 746a3b94
Loading
Loading
Loading
Loading
+6 −7
Changes for include/zephyr/posix/posix_types.h: 6 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -37,14 +37,13 @@ typedef unsigned long timer_t;

/* Thread attributes */
struct pthread_attr {
	int priority;
	void *stack;
	uint32_t stacksize;
	uint32_t flags;
	uint32_t delayedstart;
	uint32_t schedpolicy;
	int32_t detachstate;
	uint32_t initialized;
	uint16_t stacksize;
	int8_t priority;
	uint8_t schedpolicy: 2;
	bool initialized: 1;
	bool cancelstate: 1;
	bool detachstate: 1;
};
#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \
	|| defined(CONFIG_ARCMWDT_LIBC)
+8 −3
Changes for include/zephyr/posix/pthread.h: 8 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -19,9 +19,14 @@
extern "C" {
#endif

/* Pthread detach/joinable */
#define PTHREAD_CREATE_DETACHED 0
#define PTHREAD_CREATE_JOINABLE 1
/*
 * Pthread detach/joinable
 * Undefine possibly predefined values by external toolchain headers
 */
#undef PTHREAD_CREATE_DETACHED
#define PTHREAD_CREATE_DETACHED 1
#undef PTHREAD_CREATE_JOINABLE
#define PTHREAD_CREATE_JOINABLE 0

/* Pthread resource visibility */
#define PTHREAD_PROCESS_PRIVATE 0
+70 −68
Changes for lib/posix/pthread.c: 70 added lines, 68 removed lines.
Original line number Diff line number Diff line
@@ -18,6 +18,17 @@
#include <zephyr/sys/slist.h>
#include <zephyr/sys/util.h>

#define ZEPHYR_TO_POSIX_PRIORITY(_zprio)                                                           \
	(((_zprio) < 0) ? (-1 * ((_zprio) + 1)) : (CONFIG_NUM_PREEMPT_PRIORITIES - (_zprio)-1))

#define POSIX_TO_ZEPHYR_PRIORITY(_prio, _pol)                                                      \
	(((_pol) == SCHED_FIFO) ? (-1 * ((_prio) + 1))                                             \
				: (CONFIG_NUM_PREEMPT_PRIORITIES - (_prio)-1))

#define DEFAULT_PTHREAD_PRIORITY                                                                   \
	POSIX_TO_ZEPHYR_PRIORITY(K_LOWEST_APPLICATION_THREAD_PRIO, DEFAULT_PTHREAD_POLICY)
#define DEFAULT_PTHREAD_POLICY (IS_ENABLED(CONFIG_PREEMPT_ENABLED) ? SCHED_RR : SCHED_FIFO)

LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL);

#ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE
@@ -26,9 +37,18 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL);
#define DYNAMIC_STACK_SIZE 0
#endif

#define _pthread_cancel_pos LOG2(PTHREAD_CANCEL_DISABLE)
/* The maximum allowed stack size (for this implementation) */
#define PTHREAD_STACK_MAX (UINT16_MAX + 1)

static inline size_t __get_attr_stacksize(const struct pthread_attr *attr)
{
	return attr->stacksize + 1;
}

#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE
static inline void __set_attr_stacksize(struct pthread_attr *attr, size_t size)
{
	attr->stacksize = size - 1;
}

struct __pthread_cleanup {
	void (*routine)(void *arg);
@@ -45,6 +65,9 @@ enum posix_thread_qid {
	POSIX_THREAD_DONE_Q,
};

/* only 2 bits in struct pthread_attr for schedpolicy */
BUILD_ASSERT(SCHED_OTHER < BIT(2) && SCHED_FIFO < BIT(2) && SCHED_RR < BIT(2));

BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) &&
	     (PTHREAD_CREATE_DETACHED == 1 || PTHREAD_CREATE_JOINABLE == 1));

@@ -60,18 +83,13 @@ static struct k_spinlock pthread_pool_lock;
static int pthread_concurrency;

static const struct pthread_attr init_pthread_attrs = {
	.priority = 0,
	.stack = NULL,
	.stacksize = 0,
	.flags = PTHREAD_INIT_FLAGS,
	.delayedstart = 0,
#if defined(CONFIG_PREEMPT_ENABLED)
	.schedpolicy = SCHED_RR,
#else
	.schedpolicy = SCHED_FIFO,
#endif
	.detachstate = PTHREAD_CREATE_JOINABLE,
	.priority = DEFAULT_PTHREAD_PRIORITY,
	.schedpolicy = DEFAULT_PTHREAD_POLICY,
	.initialized = true,
	.cancelstate = PTHREAD_CANCEL_ENABLE,
	.detachstate = PTHREAD_CREATE_JOINABLE,
};

/*
@@ -201,35 +219,27 @@ static bool is_posix_policy_prio_valid(uint32_t priority, int policy)

static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy)
{
	uint32_t prio;

	if (z_prio < 0) {
		*policy = SCHED_FIFO;
		prio = -1 * (z_prio + 1);
		__ASSERT_NO_MSG(prio < CONFIG_NUM_COOP_PRIORITIES);
		__ASSERT_NO_MSG(z_prio < CONFIG_NUM_COOP_PRIORITIES);
	} else {
		*policy = SCHED_RR;
		prio = (CONFIG_NUM_PREEMPT_PRIORITIES - z_prio - 1);
		__ASSERT_NO_MSG(prio < CONFIG_NUM_PREEMPT_PRIORITIES);
		__ASSERT_NO_MSG(z_prio < CONFIG_NUM_PREEMPT_PRIORITIES);
	}

	return prio;
	*policy = (z_prio < 0) ? SCHED_FIFO : SCHED_RR;
	return ZEPHYR_TO_POSIX_PRIORITY(z_prio);
}

static int32_t posix_to_zephyr_priority(uint32_t priority, int policy)
{
	int32_t prio;

	if (policy == SCHED_FIFO) {
		/* Zephyr COOP priority starts from -1 */
		/* COOP: highest [CONFIG_NUM_COOP_PRIORITIES, -1] lowest */
		__ASSERT_NO_MSG(priority < CONFIG_NUM_COOP_PRIORITIES);
		prio = -1 * (priority + 1);
	} else {
		/* PREEMPT: lowest [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1] highest */
		__ASSERT_NO_MSG(priority < CONFIG_NUM_PREEMPT_PRIORITIES);
		prio = (CONFIG_NUM_PREEMPT_PRIORITIES - priority - 1);
	}

	return prio;
	return POSIX_TO_ZEPHYR_PRIORITY(priority, policy);
}

/**
@@ -242,8 +252,8 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param *
	struct pthread_attr *attr = (struct pthread_attr *)_attr;
	int priority = schedparam->sched_priority;

	if ((attr == NULL) || (attr->initialized == 0U) ||
	    (is_posix_policy_prio_valid(priority, attr->schedpolicy) == false)) {
	if (attr == NULL || !attr->initialized ||
	    is_posix_policy_prio_valid(priority, attr->schedpolicy == false)) {
		LOG_ERR("Invalid pthread_attr_t or sched_param");
		return EINVAL;
	}
@@ -266,8 +276,13 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi
		return EACCES;
	}

	if (stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) {
		LOG_ERR("Invalid stacksize %zu", stacksize);
		return EINVAL;
	}

	attr->stack = stackaddr;
	attr->stacksize = stacksize;
	__set_attr_stacksize(attr, stacksize);
	return 0;
}

@@ -279,8 +294,9 @@ static bool pthread_attr_is_valid(const struct pthread_attr *attr)
	}

	/* caller-provided thread stack */
	if (attr->initialized == 0U || attr->stack == NULL || attr->stacksize == 0) {
		LOG_ERR("pthread_attr_t is not initialized, has a NULL stack, or is of size 0");
	if (!attr->initialized || attr->stack == NULL || attr->stacksize == 0 ||
	    __get_attr_stacksize(attr) < PTHREAD_STACK_MIN) {
		LOG_ERR("pthread_attr_t is not initialized, has a NULL stack, or invalid size");
		return false;
	}

@@ -290,19 +306,6 @@ static bool pthread_attr_is_valid(const struct pthread_attr *attr)
		return false;
	}

	/* require a valid detachstate */
	if (!(attr->detachstate == PTHREAD_CREATE_JOINABLE ||
	      attr->detachstate == PTHREAD_CREATE_DETACHED)) {
		LOG_ERR("Invalid detachstate %d", attr->detachstate);
		return false;
	}

	/* we cannot create an essential thread (i.e. one that may not abort) */
	if ((attr->flags & K_ESSENTIAL) != 0) {
		LOG_ERR("Cannot create an essential thread");
		return false;
	}

	return true;
}

@@ -431,11 +434,12 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou

	if (attr == NULL) {
		attr = &attr_storage;
		attr->stacksize = DYNAMIC_STACK_SIZE;
		attr->stack =
			k_thread_stack_alloc(attr->stacksize, k_is_user_context() ? K_USER : 0);
		BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX);
		__set_attr_stacksize(attr, DYNAMIC_STACK_SIZE);
		attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr),
						   k_is_user_context() ? K_USER : 0);
		if (attr->stack == NULL) {
			LOG_ERR("Unable to allocate stack of size %u", attr->stacksize);
			LOG_ERR("Unable to allocate stack of size %u", DYNAMIC_STACK_SIZE);
			return EAGAIN;
		}
		LOG_DBG("Allocated thread stack %p", attr->stack);
@@ -454,9 +458,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou
		sys_dlist_append(&run_q, &t->q_node);
		t->qid = POSIX_THREAD_RUN_Q;
		t->detachstate = attr->detachstate;
		if ((BIT(_pthread_cancel_pos) & attr->flags) != 0) {
			t->cancel_state = PTHREAD_CANCEL_ENABLE;
		}
		t->cancel_state = attr->cancelstate;
		t->cancel_pending = false;
		sys_slist_init(&t->key_list);
		sys_slist_init(&t->cleanup_list);
@@ -491,10 +493,8 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou
	/* spawn the thread */
	k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper,
			(void *)arg, threadroutine,
			IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier)
								       : NULL,
			posix_to_zephyr_priority(attr->priority, attr->schedpolicy), attr->flags,
			K_MSEC(attr->delayedstart));
			IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) : NULL,
			posix_to_zephyr_priority(attr->priority, attr->schedpolicy), 0, K_NO_WAIT);

	if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) {
		/* wait for the spawned thread to cross our barrier */
@@ -664,15 +664,16 @@ int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_para
 *
 * See IEEE 1003.1
 */
int pthread_attr_init(pthread_attr_t *attr)
int pthread_attr_init(pthread_attr_t *_attr)
{
	struct pthread_attr *const attr = (struct pthread_attr *)_attr;

	if (attr == NULL) {
		LOG_ERR("Invalid attr pointer");
		return ENOMEM;
	}

	(void)memcpy(attr, &init_pthread_attrs, sizeof(pthread_attr_t));
	(void)memcpy(attr, &init_pthread_attrs, sizeof(struct pthread_attr));

	return 0;
}
@@ -747,7 +748,7 @@ void pthread_exit(void *retval)
		CODE_UNREACHABLE;
	}

	/* Make a thread as cancelable before exiting */
	/* Mark a thread as cancellable before exiting */
	key = k_spin_lock(&pthread_pool_lock);
	self->cancel_state = PTHREAD_CANCEL_ENABLE;
	k_spin_unlock(&pthread_pool_lock, key);
@@ -870,7 +871,7 @@ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate)
{
	const struct pthread_attr *attr = (const struct pthread_attr *)_attr;

	if ((attr == NULL) || (attr->initialized == 0U)) {
	if ((attr == NULL) || (attr->initialized == false)) {
		return EINVAL;
	}

@@ -887,8 +888,9 @@ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate)
{
	struct pthread_attr *attr = (struct pthread_attr *)_attr;

	if ((attr == NULL) || (attr->initialized == 0U) ||
	    (detachstate != PTHREAD_CREATE_DETACHED && detachstate != PTHREAD_CREATE_JOINABLE)) {
	if ((attr == NULL) || (attr->initialized == false) ||
	    ((detachstate != PTHREAD_CREATE_DETACHED) &&
	     (detachstate != PTHREAD_CREATE_JOINABLE))) {
		return EINVAL;
	}

@@ -939,11 +941,11 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize)
{
	const struct pthread_attr *attr = (const struct pthread_attr *)_attr;

	if ((attr == NULL) || (attr->initialized == 0U)) {
	if ((attr == NULL) || (attr->initialized == false)) {
		return EINVAL;
	}

	*stacksize = attr->stacksize;
	*stacksize = __get_attr_stacksize(attr);
	return 0;
}

@@ -960,11 +962,11 @@ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize)
		return EINVAL;
	}

	if (stacksize < PTHREAD_STACK_MIN) {
	if (stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) {
		return EINVAL;
	}

	attr->stacksize = stacksize;
	__set_attr_stacksize(attr, stacksize);
	return 0;
}

@@ -977,12 +979,12 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t
{
	const struct pthread_attr *attr = (const struct pthread_attr *)_attr;

	if ((attr == NULL) || (attr->initialized == 0U)) {
	if ((attr == NULL) || (attr->initialized == false)) {
		return EINVAL;
	}

	*stackaddr = attr->stack;
	*stacksize = attr->stacksize;
	*stacksize = __get_attr_stacksize(attr);
	return 0;
}

@@ -995,7 +997,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param *
{
	struct pthread_attr *attr = (struct pthread_attr *)_attr;

	if ((attr == NULL) || (attr->initialized == 0U)) {
	if ((attr == NULL) || (attr->initialized == false)) {
		return EINVAL;
	}