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

Prerequisites for the user tasks: task types, per-CPU task lists #267

Merged
merged 4 commits into from
Jul 19, 2022
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions common/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,16 @@ static void init_cpu(cpu_t *cpu, unsigned int id, bool is_bsp, bool enabled) {
cpu->id = id;
cpu->bsp = is_bsp;
cpu->enabled = enabled;
cpu->done = false;

init_cpu_runstate(cpu);
if (is_bsp)
set_cpu_unblocked(cpu);

cpu->percpu = get_percpu_page(id);
BUG_ON(!cpu->percpu);

cpu->lock = SPINLOCK_INIT;
list_init(&cpu->task_queue);
}

cpu_t *init_cpus(void) {
Expand Down Expand Up @@ -98,15 +102,23 @@ void for_each_cpu(void (*func)(cpu_t *cpu)) {
func(cpu);
}

void unblock_all_cpus(void) {
cpu_t *cpu;

list_for_each_entry (cpu, &cpus, list)
set_cpu_unblocked(cpu);
}

void wait_for_all_cpus(void) {
cpu_t *cpu, *safe;

do {
list_for_each_entry_safe (cpu, safe, &cpus, list) {
spin_lock(&cpu->lock);
if (cpu->done)
if (is_cpu_finished(cpu)) {
spin_lock(&cpu->lock);
list_unlink(&cpu->list);
spin_unlock(&cpu->lock);
spin_unlock(&cpu->lock);
}
}
} while (!list_is_empty(&cpus));
}
12 changes: 7 additions & 5 deletions common/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
#include <percpu.h>
#include <sched.h>
#include <setup.h>
#include <smp/smp.h>
#ifdef KTF_PMU
#include <perfmon/pfmlib.h>
#endif
Expand All @@ -53,6 +52,7 @@ static void __noreturn echo_loop(void) {

void kernel_main(void) {
task_t *tests_task;
cpu_t *cpu;

printk("\nKTF - Kernel Test Framework!\n");

Expand All @@ -62,12 +62,14 @@ void kernel_main(void) {
display_multiboot_mmap();
}

tests_task = new_task("tests", test_main, NULL);
schedule_task(tests_task, smp_processor_id());
tests_task = new_kernel_task("tests", test_main, NULL);
cpu = get_bsp_cpu();

run_tasks(smp_processor_id());
schedule_task(tests_task, cpu);

wait_for_all_tasks();
run_tasks(cpu);
unblock_all_cpus();
wait_for_all_cpus();

printk("All tasks done.\n");

Expand Down
118 changes: 51 additions & 67 deletions common/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <console.h>
#include <cpu.h>
#include <errno.h>
#include <ktf.h>
#include <lib.h>
Expand All @@ -36,15 +37,12 @@

#include <mm/slab.h>

static list_head_t tasks;
static tid_t next_tid;

static spinlock_t lock = SPINLOCK_INIT;

void init_tasks(void) {
printk("Initializing tasks\n");

list_init(&tasks);
next_tid = 0;
}

static const char *task_state_names[] = {
Expand Down Expand Up @@ -85,14 +83,9 @@ static task_t *create_task(void) {

memset(task, 0, sizeof(*task));
task->id = next_tid++;
task->gid = TASK_GROUP_UNSPECIFIED;
task->cpu = INVALID_CPU;
task->gid = TASK_GROUP_ALL;
set_task_state(task, TASK_STATE_NEW);

spin_lock(&lock);
list_add(&task->list, &tasks);
spin_unlock(&lock);

return task;
}

Expand All @@ -101,25 +94,23 @@ static void destroy_task(task_t *task) {
if (!task)
return;

spin_lock(&lock);
spin_lock(&task->cpu->lock);
list_unlink(&task->list);
spin_unlock(&lock);

spin_unlock(&task->cpu->lock);
kfree(task);
}

static int prepare_task(task_t *task, const char *name, task_func_t func, void *arg) {
static int prepare_task(task_t *task, const char *name, task_func_t func, void *arg,
task_type_t type) {
if (!task)
return -EINVAL;

if (get_task_by_name(name))
return -EEXIST;

BUG_ON(get_task_state(task) > TASK_STATE_READY);

task->name = name;
task->func = func;
task->arg = arg;
task->type = type;
set_task_state(task, TASK_STATE_READY);
return ESUCCESS;
}
Expand All @@ -132,65 +123,50 @@ static void wait_for_task_state(task_t *task, task_state_t state) {
cpu_relax();
}

task_t *new_task(const char *name, task_func_t func, void *arg) {
task_t *new_task(const char *name, task_func_t func, void *arg, task_type_t type) {
task_t *task = create_task();

if (!task)
return NULL;

if (unlikely(prepare_task(task, name, func, arg) != ESUCCESS)) {
if (unlikely(prepare_task(task, name, func, arg, type) != ESUCCESS)) {
destroy_task(task);
return NULL;
}

return task;
}

task_t *get_task_by_id(tid_t id) {
task_t *task;

list_for_each_entry (task, &tasks, list) {
if (task->id == id)
return task;
}

return NULL;
}

task_t *get_task_by_name(const char *name) {
task_t *get_task_by_name(cpu_t *cpu, const char *name) {
task_t *task;

list_for_each_entry (task, &tasks, list) {
list_for_each_entry (task, &cpu->task_queue, list) {
if (string_equal(task->name, name))
return task;
}

return NULL;
}

task_t *get_task_for_cpu(unsigned int cpu) {
task_t *task;

list_for_each_entry (task, &tasks, list) {
if (task->cpu == cpu)
return task;
}

return NULL;
}

void schedule_task(task_t *task, unsigned int cpu) {
int schedule_task(task_t *task, cpu_t *cpu) {
ASSERT(task);

if (cpu > get_nr_cpus() - 1)
panic("CPU[%u] does not exist.\n", cpu);
if (!cpu) {
printk("Unable to schedule task: %s. CPU does not exist.", task->name);
return -EEXIST;
}

BUG_ON(get_task_state(task) != TASK_STATE_READY);

printk("CPU[%u]: Scheduling task %s[%u]\n", cpu, task->name, task->id);
printk("CPU[%u]: Scheduling task %s[%u]\n", cpu->id, task->name, task->id);

spin_lock(&cpu->lock);
list_add_tail(&task->list, &cpu->task_queue);
task->cpu = cpu;
set_task_state(task, TASK_STATE_SCHEDULED);
spin_unlock(&cpu->lock);

return 0;
}

static void run_task(task_t *task) {
Expand All @@ -199,23 +175,23 @@ static void run_task(task_t *task) {

wait_for_task_state(task, TASK_STATE_SCHEDULED);

printk("CPU[%u]: Running task %s[%u]\n", task->cpu, task->name, task->id);
printk("CPU[%u]: Running task %s[%u]\n", task->cpu->id, task->name, task->id);

set_task_state(task, TASK_STATE_RUNNING);
task->result = task->func(task->arg);
set_task_state(task, TASK_STATE_DONE);
}

void wait_for_task_group(task_group_t group) {
task_t *task;
void wait_for_task_group(const cpu_t *cpu, task_group_t group) {
task_t *task, *safe;
bool busy;

do {
busy = false;

list_for_each_entry (task, &tasks, list) {
list_for_each_entry_safe (task, safe, &cpu->task_queue, list) {
/* When group is unspecified the functions waits for all tasks. */
if (group != TASK_GROUP_UNSPECIFIED && task->gid != group)
if (group != TASK_GROUP_ALL && task->gid != group)
continue;

if (get_task_state(task) != TASK_STATE_DONE) {
Expand All @@ -227,21 +203,29 @@ void wait_for_task_group(task_group_t group) {
} while (busy);
}

void run_tasks(unsigned int cpu) {
task_t *task;
void run_tasks(cpu_t *cpu) {
task_t *task, *safe;

while ((task = get_task_for_cpu(cpu))) {
switch (task->state) {
case TASK_STATE_DONE:
printk("Task '%s' finished with result %lu\n", task->name, task->result);
destroy_task(task);
break;
case TASK_STATE_SCHEDULED:
run_task(task);
break;
default:
break;
wait_cpu_unblocked(cpu);

do {
list_for_each_entry_safe (task, safe, &cpu->task_queue, list) {
switch (task->state) {
case TASK_STATE_DONE:
printk("%s task '%s' finished on CPU[%u] with result %ld\n",
task->type == TASK_TYPE_KERNEL ? "Kernel" : "User", task->name,
cpu->id, task->result);
destroy_task(task);
break;
case TASK_STATE_SCHEDULED:
run_task(task);
break;
default:
BUG();
}
cpu_relax();
}
cpu_relax();
}
} while (!list_is_empty(&cpu->task_queue));

set_cpu_finished(cpu);
}
10 changes: 7 additions & 3 deletions drivers/acpi/acpica/osl.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,17 +369,21 @@ ACPI_STATUS AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Functio

cb.Function = Function;
cb.Context = Context;
task = new_task(name, _osd_exec_cb_wrapper, &cb);
task = new_kernel_task(name, _osd_exec_cb_wrapper, &cb);
if (!task)
return AE_NO_MEMORY;

set_task_group(task, TASK_GROUP_ACPI);
schedule_task(task, cpu->id);
schedule_task(task, cpu);

return AE_OK;
}

void AcpiOsWaitEventsComplete(void) { wait_for_task_group(TASK_GROUP_ACPI); }
void AcpiOsWaitEventsComplete(void) {
cpu_t *cpu = get_cpu(smp_processor_id());

wait_for_task_group(cpu, TASK_GROUP_ACPI);
}

/* Synchronization and locking functions */

Expand Down
36 changes: 35 additions & 1 deletion include/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,29 @@
#ifndef KTF_CPU_H
#define KTF_CPU_H

#include <atomic.h>
#include <ktf.h>
#include <lib.h>
#include <list.h>
#include <percpu.h>
#include <spinlock.h>

#define CPU_UNBLOCKED (1 << 0)
#define CPU_FINISHED (1 << 1)

struct cpu {
list_head_t list;

unsigned int id;
unsigned int bsp : 1, enabled : 1, done : 1;
unsigned int bsp : 1, enabled : 1;

atomic_t run_state;

percpu_t *percpu;

spinlock_t lock;

list_head_t task_queue;
};
typedef struct cpu cpu_t;

Expand All @@ -51,6 +59,32 @@ extern cpu_t *get_cpu(unsigned int id);
extern cpu_t *get_bsp_cpu(void);
extern unsigned int get_nr_cpus(void);
extern void for_each_cpu(void (*func)(cpu_t *cpu));
extern void unblock_all_cpus(void);
extern void wait_for_all_cpus(void);

/* Static declarations */

static inline void init_cpu_runstate(cpu_t *cpu) { atomic_set(&cpu->run_state, 0); }

static inline bool is_cpu_finished(cpu_t *cpu) {
return atomic_test_bit(CPU_FINISHED, &cpu->run_state);
}

static inline void set_cpu_finished(cpu_t *cpu) {
atomic_test_and_set_bit(CPU_FINISHED, &cpu->run_state);
}

static inline bool is_cpu_unblocked(cpu_t *cpu) {
return atomic_test_bit(CPU_UNBLOCKED, &cpu->run_state);
}

static inline void set_cpu_unblocked(cpu_t *cpu) {
atomic_test_and_set_bit(CPU_UNBLOCKED, &cpu->run_state);
}

static inline void wait_cpu_unblocked(cpu_t *cpu) {
while (!is_cpu_unblocked(cpu))
cpu_relax();
}

#endif /* KTF_CPU_H */
Loading