/* Check if a thread is blocked, using volatile to ensure re-read */ staticbool thread_is_blocked(volatile thread_t* thread) { return thread->state == THREAD_BLOCKED;
}
/* Note thread as started so main thread sees which CPUs are available */
smpt->started = true;
uint cpu = arch_curr_cpu_num(); if (cpu != expected_cpu) { /* Warn if the thread starts on another CPU than it was pinned to */
printf("%s: thread %d started on wrong cpu: %d\n", __func__, i, cpu);
smpt->error_count++;
}
while (true) {
THREAD_LOCK(state1);
get_current_thread()->state = THREAD_BLOCKED;
thread_block();
cpu = arch_curr_cpu_num(); if (cpu != expected_cpu) { /* Don't update any state if the thread runs on the wrong CPU. */
printf("%s: thread %d ran on wrong cpu: %d\n", __func__, i, cpu);
smpt->error_count++; continue;
}
/* Sleep to allow other threads to block */
thread_sleep(THREAD_DELAY_MS);
THREAD_LOCK(state2);
/* Find and unblock the next started cpu */ for (uint next_cpu = i + 1; next_cpu < SMP_MAX_CPUS; next_cpu++) { if (smptest_thread[next_cpu].started) {
thread_t* next = smptest_thread[next_cpu].thread;
/* Next CPU should be blocked; wake it up */ if (thread_is_blocked(next)) {
thread_unblock(next, false);
} else {
printf("%s: thread %d not blocked\n", __func__, i + 1);
smpt->error_count++;
}
TEST(smptest, check_cpu_active) {
uint active_cpu_count = 0; for (uint i = 0; i < SMP_MAX_CPUS; i++) { if (mp_is_cpu_active(i)) {
active_cpu_count++;
}
}
EXPECT_GE(active_cpu_count, SMPTEST_MIN_CPU_COUNT);
}
TEST(smptest, run) { bool wait_for_cpus = false;
for (uint i = 0; i < SMP_MAX_CPUS; i++) { if (!thread_is_blocked(smptest_thread[i].thread)) {
unittest_printf("[ INFO ] thread %d not ready\n", i);
wait_for_cpus = true;
}
}
/* *test-runnercanstartthetestbeforeallCPUshavefinishedbooting. *WaitanothersecondforalltheCPUsweneedtobereadyifneeded.
*/ if (wait_for_cpus) {
unittest_printf("[ INFO ] waiting for threads to be ready\n");
thread_sleep(1000);
}
for (uint i = 0; i < SMP_MAX_CPUS; i++) {
ASSERT_EQ(!mp_is_cpu_active(i) ||
thread_is_blocked(smptest_thread[i].thread), true, "thread %d not ready\n", i);
}
for (uint i = 0; i < SMP_MAX_CPUS; i++) {
smptest_thread[i].unblock_count = 0;
smptest_thread[i].error_count = 0;
smptest_thread[i].done_count = 0;
}
if (j == SMPTEST_CYCLES - 1) {
unittest_printf( "[ INFO ] smptest cpu %d ran %d times\n", cpu,
SMPTEST_CYCLES);
}
} else {
EXPECT_EQ(mp_is_cpu_active(cpu), false, "cpu %d active but not running", cpu);
EXPECT_EQ(unblock_count, 0, "cpu %d FAILED block count\n", cpu);
EXPECT_EQ(error_count, 0, "cpu %d FAILED error count\n", cpu);
EXPECT_EQ(done_count, 0, "cpu %d FAILED done count\n", cpu);
}
}
}
test_abort:;
}
staticvoid smptest_setup(uint level) { /* Create a thread for each possible CPU */ for (uint cpu = 0; cpu < SMP_MAX_CPUS; cpu++) { struct smptest_thread* smpt = &smptest_thread[cpu]; char thread_name[32];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.