tests: posix: ensure that min and max priority are schedulable

Verify that threads are actually schedulable for min and max
scheduler priority for both `SCHED_RR` (preemptive) and
`SCHED_FIFO` (cooperative).

Fixes #56729

Signed-off-by: Chris Friedt <cfriedt@meta.com>
This commit is contained in:
Chris Friedt 2023-04-23 22:33:49 -04:00 committed by jgl-meta
parent 2b2cbf8107
commit ad71b78770

View file

@ -598,3 +598,132 @@ ZTEST(posix_apis, test_pthread_descriptor_leak)
zassert_ok(pthread_join(pthread1, &unused), "unable to join thread %zu", i);
}
}
ZTEST(posix_apis, test_sched_policy)
{
/*
* TODO:
* 1. assert that _POSIX_PRIORITY_SCHEDULING is defined
* 2. if _POSIX_SPORADIC_SERVER or _POSIX_THREAD_SPORADIC_SERVER are defined,
* also check SCHED_SPORADIC
* 3. SCHED_OTHER is mandatory (but may be equivalent to SCHED_FIFO or SCHED_RR,
* and is implementation defined)
*/
int pmin;
int pmax;
pthread_t th;
pthread_attr_t attr;
struct sched_param param;
static const int policies[] = {
SCHED_FIFO,
SCHED_RR,
SCHED_INVALID,
};
static const char *const policy_names[] = {
"SCHED_FIFO",
"SCHED_RR",
"SCHED_INVALID",
};
static const bool policy_enabled[] = {
IS_ENABLED(CONFIG_COOP_ENABLED),
IS_ENABLED(CONFIG_PREEMPT_ENABLED),
false,
};
static int nprio[] = {
CONFIG_NUM_COOP_PRIORITIES,
CONFIG_NUM_PREEMPT_PRIORITIES,
42,
};
const char *const prios[] = {"pmin", "pmax"};
BUILD_ASSERT(!(SCHED_INVALID == SCHED_FIFO || SCHED_INVALID == SCHED_RR),
"SCHED_INVALID is itself invalid");
for (int policy = 0; policy < ARRAY_SIZE(policies); ++policy) {
if (!policy_enabled[policy]) {
/* test degenerate cases */
errno = 0;
zassert_equal(-1, sched_get_priority_min(policies[policy]),
"expected sched_get_priority_min(%s) to fail",
policy_names[policy]);
zassert_equal(EINVAL, errno, "sched_get_priority_min(%s) did not set errno",
policy_names[policy]);
errno = 0;
zassert_equal(-1, sched_get_priority_max(policies[policy]),
"expected sched_get_priority_max(%s) to fail",
policy_names[policy]);
zassert_equal(EINVAL, errno, "sched_get_priority_max(%s) did not set errno",
policy_names[policy]);
continue;
}
/* get pmin and pmax for policies[policy] */
for (int i = 0; i < 2; ++i) {
errno = 0;
if (i == 0) {
pmin = sched_get_priority_min(policies[policy]);
param.sched_priority = pmin;
} else {
pmax = sched_get_priority_max(policies[policy]);
param.sched_priority = pmax;
}
zassert_not_equal(-1, param.sched_priority,
"sched_get_priority_%s(%s) failed: %d",
i == 0 ? "min" : "max", policy_names[policy], errno);
zassert_ok(errno, "sched_get_priority_%s(%s) set errno to %s",
i == 0 ? "min" : "max", policy_names[policy], errno);
}
/*
* IEEE 1003.1-2008 Section 2.8.4
* conforming implementations should provide a range of at least 32 priorities
*
* Note: we relax this requirement
*/
zassert_true(pmax > pmin, "pmax (%d) <= pmin (%d)", pmax, pmin,
"%s min/max inconsistency: pmin: %d pmax: %d", policy_names[policy],
pmin, pmax);
/*
* Getting into the weeds a bit (i.e. whitebox testing), Zephyr
* cooperative threads use [-CONFIG_NUM_COOP_PRIORITIES,-1] and
* preemptive threads use [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1],
* where the more negative thread has the higher priority. Since we
* cannot map those directly (a return value of -1 indicates error),
* we simply map those to the positive space.
*/
zassert_equal(pmin, 0, "unexpected pmin for %s", policy_names[policy]);
zassert_equal(pmax, nprio[policy] - 1, "unexpected pmax for %s",
policy_names[policy]); /* test happy paths */
for (int i = 0; i < 2; ++i) {
/* create threads with min and max priority levels */
zassert_ok(pthread_attr_init(&attr),
"pthread_attr_init() failed for %s (%d) of %s", prios[i],
param.sched_priority, policy_names[policy]);
zassert_ok(pthread_attr_setschedpolicy(&attr, policies[policy]),
"pthread_attr_setschedpolicy() failed for %s (%d) of %s",
prios[i], param.sched_priority, policy_names[policy]);
zassert_ok(pthread_attr_setschedparam(&attr, &param),
"pthread_attr_setschedparam() failed for %s (%d) of %s",
prios[i], param.sched_priority, policy_names[policy]);
zassert_ok(pthread_attr_setstack(&attr, &stack_e[0][0], STACKS),
"pthread_attr_setstack() failed for %s (%d) of %s", prios[i],
param.sched_priority, policy_names[policy]);
zassert_ok(pthread_create(&th, &attr, create_thread1, NULL),
"pthread_create() failed for %s (%d) of %s", prios[i],
param.sched_priority, policy_names[policy]);
zassert_ok(pthread_join(th, NULL),
"pthread_join() failed for %s (%d) of %s", prios[i],
param.sched_priority, policy_names[policy]);
}
}
}