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

posix: implement pthread_attr_getinheritsched() and pthread_attr_setinheritsched() #68470

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/services/portability/posix/option_groups/index.rst
Expand Up @@ -502,10 +502,10 @@ _POSIX_THREAD_PRIORITY_SCHEDULING
:header: API, Supported
:widths: 50,10

pthread_attr_getinheritsched(),
pthread_attr_getinheritsched(),yes
pthread_attr_getschedpolicy(),yes
pthread_attr_getscope(),yes
pthread_attr_setinheritsched(),
pthread_attr_setinheritsched(),yes
pthread_attr_setschedpolicy(),yes
pthread_attr_setscope(),yes
pthread_getschedparam(),yes
Expand Down
8 changes: 8 additions & 0 deletions include/zephyr/posix/pthread.h
Expand Up @@ -45,6 +45,12 @@ extern "C" {
#undef PTHREAD_SCOPE_SYSTEM
#define PTHREAD_SCOPE_SYSTEM 0

/* Pthread inherit scheduler */
#undef PTHREAD_INHERIT_SCHED
#define PTHREAD_INHERIT_SCHED 0
#undef PTHREAD_EXPLICIT_SCHED
#define PTHREAD_EXPLICIT_SCHED 1

/* Passed to pthread_once */
#define PTHREAD_ONCE_INIT {0}

Expand Down Expand Up @@ -423,6 +429,8 @@ int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
size_t stacksize);
int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope);
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
#ifdef CONFIG_PTHREAD_IPC
int pthread_once(pthread_once_t *once, void (*initFunc)(void));
#endif
Expand Down
1 change: 1 addition & 0 deletions lib/posix/options/posix_internal.h
Expand Up @@ -30,6 +30,7 @@ struct posix_thread_attr {
int8_t priority;
uint8_t schedpolicy: 2;
bool contentionscope: 1;
bool inheritsched: 1;
union {
bool caller_destroys: 1;
bool initialized: 1;
Expand Down
50 changes: 49 additions & 1 deletion lib/posix/options/pthread.c
Expand Up @@ -414,7 +414,7 @@ int pthread_attr_setscope(pthread_attr_t *_attr, int contentionscope)
return EINVAL;
}
if (!(contentionscope == PTHREAD_SCOPE_PROCESS ||
contentionscope == PTHREAD_SCOPE_SYSTEM)) {
contentionscope == PTHREAD_SCOPE_SYSTEM)) {
LOG_DBG("%s contentionscope %d", "Invalid", contentionscope);
return EINVAL;
}
Expand All @@ -427,6 +427,45 @@ int pthread_attr_setscope(pthread_attr_t *_attr, int contentionscope)
return 0;
}

/**
* @brief Get inherit scheduler attributes in thread attributes object.
*
* See IEEE 1003.1
*/
int pthread_attr_getinheritsched(const pthread_attr_t *_attr, int *inheritsched)
{
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;

if (!__attr_is_initialized(attr) || inheritsched == NULL) {
return EINVAL;
}
*inheritsched = attr->inheritsched;
return 0;
}

/**
* @brief Set inherit scheduler attributes in thread attributes object.
*
* See IEEE 1003.1
*/
int pthread_attr_setinheritsched(pthread_attr_t *_attr, int inheritsched)
{
struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr;

if (!__attr_is_initialized(attr)) {
LOG_DBG("attr %p is not initialized", attr);
return EINVAL;
}

if (inheritsched != PTHREAD_INHERIT_SCHED && inheritsched != PTHREAD_EXPLICIT_SCHED) {
LOG_DBG("Invalid inheritsched %d", inheritsched);
return EINVAL;
}

attr->inheritsched = inheritsched;
return 0;
}

static void posix_thread_recycle_work_handler(struct k_work *work)
{
ARG_UNUSED(work);
Expand Down Expand Up @@ -599,6 +638,14 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou
t->attr = *(struct posix_thread_attr *)_attr;
}

if (t->attr.inheritsched == PTHREAD_INHERIT_SCHED) {
int pol;

t->attr.priority =
zephyr_to_posix_priority(k_thread_priority_get(k_current_get()), &pol);
t->attr.schedpolicy = pol;
}

/* spawn the thread */
k_thread_create(
&t->thread, t->attr.stack, __get_attr_stacksize(&t->attr) + t->attr.guardsize,
Expand Down Expand Up @@ -841,6 +888,7 @@ int pthread_attr_init(pthread_attr_t *_attr)
*attr = (struct posix_thread_attr){0};
attr->guardsize = CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT;
attr->contentionscope = PTHREAD_SCOPE_SYSTEM;
attr->inheritsched = PTHREAD_INHERIT_SCHED;

if (DYNAMIC_STACK_SIZE > 0) {
attr->stack = k_thread_stack_alloc(DYNAMIC_STACK_SIZE + attr->guardsize,
Expand Down
130 changes: 126 additions & 4 deletions tests/posix/common/src/pthread_attr.c
Expand Up @@ -33,7 +33,8 @@ static void *thread_entry(void *arg)
return NULL;
}

static void create_thread_common(const pthread_attr_t *attrp, bool expect_success, bool joinable)
static void create_thread_common_entry(const pthread_attr_t *attrp, bool expect_success,
bool joinable, void *(*entry)(void *arg), void *arg)
{
pthread_t th;

Expand All @@ -42,9 +43,9 @@ static void create_thread_common(const pthread_attr_t *attrp, bool expect_succes
}

if (expect_success) {
zassert_ok(pthread_create(&th, attrp, thread_entry, UINT_TO_POINTER(joinable)));
zassert_ok(pthread_create(&th, attrp, entry, arg));
} else {
zassert_not_ok(pthread_create(&th, attrp, thread_entry, UINT_TO_POINTER(joinable)));
zassert_not_ok(pthread_create(&th, attrp, entry, arg));
return;
}

Expand All @@ -66,6 +67,12 @@ static void create_thread_common(const pthread_attr_t *attrp, bool expect_succes
zassert_true(detached_thread_has_finished, "detached thread did not seem to finish");
}

static void create_thread_common(const pthread_attr_t *attrp, bool expect_success, bool joinable)
{
create_thread_common_entry(attrp, expect_success, joinable, thread_entry,
UINT_TO_POINTER(joinable));
}

static inline void can_create_thread(const pthread_attr_t *attrp)
{
create_thread_common(attrp, true, true);
Expand Down Expand Up @@ -470,7 +477,8 @@ ZTEST(pthread_attr, test_pthread_attr_setscope)
zassert_equal(pthread_attr_setscope(NULL, PTHREAD_SCOPE_SYSTEM), EINVAL);
zassert_equal(pthread_attr_setscope(NULL, contentionscope), EINVAL);
zassert_equal(pthread_attr_setscope((pthread_attr_t *)&uninit_attr,
contentionscope), EINVAL);
contentionscope),
EINVAL);
}
zassert_equal(pthread_attr_setscope(&attr, 3), EINVAL);
}
Expand All @@ -481,6 +489,120 @@ ZTEST(pthread_attr, test_pthread_attr_setscope)
zassert_equal(contentionscope, PTHREAD_SCOPE_SYSTEM);
}

ZTEST(pthread_attr, test_pthread_attr_getinheritsched)
{
int inheritsched = BIOS_FOOD;

/* degenerate cases */
{
if (false) {
/* undefined behaviour */
zassert_equal(pthread_attr_getinheritsched(NULL, NULL), EINVAL);
zassert_equal(pthread_attr_getinheritsched(NULL, &inheritsched), EINVAL);
zassert_equal(pthread_attr_getinheritsched(&uninit_attr, &inheritsched),
EINVAL);
}
zassert_equal(pthread_attr_getinheritsched(&attr, NULL), EINVAL);
}

zassert_ok(pthread_attr_getinheritsched(&attr, &inheritsched));
zassert_equal(inheritsched, PTHREAD_INHERIT_SCHED);
}

static void *inheritsched_entry(void *arg)
{
int prio;
int inheritsched;
int pprio = POINTER_TO_INT(arg);

zassert_ok(pthread_attr_getinheritsched(&attr, &inheritsched));

prio = k_thread_priority_get(k_current_get());

if (inheritsched == PTHREAD_INHERIT_SCHED) {
/*
* There will be numerical overlap between posix priorities in different scheduler
* policies so only check the Zephyr priority here. The posix policy and posix
* priority are derived from the Zephyr priority in any case.
*/
zassert_equal(prio, pprio, "actual priority: %d, expected priority: %d", prio,
pprio);
return NULL;
}

/* inheritsched == PTHREAD_EXPLICIT_SCHED */
int act_prio;
int exp_prio;
int act_policy;
int exp_policy;
struct sched_param param;

/* get the actual policy, param, etc */
zassert_ok(pthread_getschedparam(pthread_self(), &act_policy, &param));
act_prio = param.sched_priority;

/* get the expected policy, param, etc */
zassert_ok(pthread_attr_getschedpolicy(&attr, &exp_policy));
zassert_ok(pthread_attr_getschedparam(&attr, &param));
exp_prio = param.sched_priority;

/* compare actual vs expected */
zassert_equal(act_policy, exp_policy, "actual policy: %d, expected policy: %d", act_policy,
exp_policy);
zassert_equal(act_prio, exp_prio, "actual priority: %d, expected priority: %d", act_prio,
exp_prio);

return NULL;
}

static void test_pthread_attr_setinheritsched_common(bool inheritsched)
{
int prio;
int policy;
struct sched_param param;

extern int zephyr_to_posix_priority(int priority, int *policy);

prio = k_thread_priority_get(k_current_get());
zassert_not_equal(prio, K_LOWEST_APPLICATION_THREAD_PRIO);

/*
* values affected by inheritsched are policy / priority / contentionscope
*
* we only support PTHREAD_SCOPE_SYSTEM, so no need to set contentionscope
*/
prio = K_LOWEST_APPLICATION_THREAD_PRIO;
param.sched_priority = zephyr_to_posix_priority(prio, &policy);

zassert_ok(pthread_attr_setschedpolicy(&attr, policy));
zassert_ok(pthread_attr_setschedparam(&attr, &param));
zassert_ok(pthread_attr_setinheritsched(&attr, inheritsched));
create_thread_common_entry(&attr, true, true, inheritsched_entry,
UINT_TO_POINTER(k_thread_priority_get(k_current_get())));
}

ZTEST(pthread_attr, test_pthread_attr_setinheritsched)
{
/* degenerate cases */
{
if (false) {
/* undefined behaviour */
zassert_equal(pthread_attr_setinheritsched(NULL, PTHREAD_EXPLICIT_SCHED),
EINVAL);
zassert_equal(pthread_attr_setinheritsched(NULL, PTHREAD_INHERIT_SCHED),
EINVAL);
zassert_equal(pthread_attr_setinheritsched((pthread_attr_t *)&uninit_attr,
PTHREAD_INHERIT_SCHED),
EINVAL);
}
zassert_equal(pthread_attr_setinheritsched(&attr, 3), EINVAL);
}

/* valid cases */
test_pthread_attr_setinheritsched_common(PTHREAD_INHERIT_SCHED);
test_pthread_attr_setinheritsched_common(PTHREAD_EXPLICIT_SCHED);
}

ZTEST(pthread_attr, test_pthread_attr_large_stacksize)
{
size_t actual_size;
Expand Down
8 changes: 4 additions & 4 deletions tests/posix/headers/src/pthread_h.c
Expand Up @@ -34,8 +34,8 @@ ZTEST(posix_headers, test_pthread_h)
zassert_not_equal(-1, PTHREAD_CREATE_DETACHED);
zassert_not_equal(-1, PTHREAD_CREATE_JOINABLE);

/* zassert_not_equal(-1, PTHREAD_EXPLICIT_SCHED); */ /* not implemented */
/* zassert_not_equal(-1, PTHREAD_INHERIT_SCHED); */ /* not implemented */
zassert_not_equal(-1, PTHREAD_EXPLICIT_SCHED);
zassert_not_equal(-1, PTHREAD_INHERIT_SCHED);

zassert_not_equal(-1, PTHREAD_MUTEX_DEFAULT);
zassert_not_equal(-1, PTHREAD_MUTEX_ERRORCHECK);
Expand Down Expand Up @@ -65,7 +65,7 @@ ZTEST(posix_headers, test_pthread_h)
zassert_not_null(pthread_attr_destroy);
zassert_not_null(pthread_attr_getdetachstate);
zassert_not_null(pthread_attr_getguardsize);
/* zassert_not_null(pthread_attr_getinheritsched); */ /* not implemented */
zassert_not_null(pthread_attr_getinheritsched);
zassert_not_null(pthread_attr_getschedparam);
zassert_not_null(pthread_attr_getschedpolicy);
zassert_not_null(pthread_attr_getscope);
Expand All @@ -74,7 +74,7 @@ ZTEST(posix_headers, test_pthread_h)
zassert_not_null(pthread_attr_init);
zassert_not_null(pthread_attr_setdetachstate);
zassert_not_null(pthread_attr_setguardsize);
/* zassert_not_null(pthread_attr_setinheritsched); */ /* not implemented */
zassert_not_null(pthread_attr_setinheritsched);
zassert_not_null(pthread_attr_setschedparam);
zassert_not_null(pthread_attr_setschedpolicy);
zassert_not_null(pthread_attr_setscope);
Expand Down