Skip to content

Commit

Permalink
sched, smp: assign tasks to independent, per-CPU task lists
Browse files Browse the repository at this point in the history
Signed-off-by: Pawel Wieczorkiewicz <[email protected]>
  • Loading branch information
wipawel committed Jul 16, 2022
1 parent 66466d0 commit 323a49a
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 79 deletions.
2 changes: 2 additions & 0 deletions common/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ static void init_cpu(cpu_t *cpu, unsigned int id, bool bsp, bool enabled) {
cpu->id = id;
cpu->bsp = bsp;
cpu->enabled = enabled;
cpu->scheduled = false;
cpu->done = false;

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
8 changes: 5 additions & 3 deletions common/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,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 @@ -63,11 +64,12 @@ void kernel_main(void) {
}

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

run_tasks(smp_processor_id());
run_tasks(cpu);

wait_for_all_tasks();
wait_for_all_cpus();

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

Expand Down
118 changes: 56 additions & 62 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 @@ -86,13 +84,8 @@ static task_t *create_task(void) {
memset(task, 0, sizeof(*task));
task->id = next_tid++;
task->gid = TASK_GROUP_ALL;
task->cpu = INVALID_CPU;
set_task_state(task, TASK_STATE_NEW);

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

return task;
}

Expand All @@ -101,10 +94,9 @@ 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);
}

Expand All @@ -113,9 +105,6 @@ static int prepare_task(task_t *task, const char *name, task_func_t func, void *
if (!task)
return -EINVAL;

if (get_task_by_name(name))
return -EEXIST;

BUG_ON(get_task_state(task) > TASK_STATE_READY);

task->name = name;
Expand Down Expand Up @@ -148,51 +137,37 @@ task_t *new_task(const char *name, task_func_t func, void *arg, task_type_t type
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;
cpu->scheduled = true;
set_task_state(task, TASK_STATE_SCHEDULED);
spin_unlock(&cpu->lock);

return 0;
}

static void run_task(task_t *task) {
Expand All @@ -201,21 +176,21 @@ 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_ALL && task->gid != group)
continue;
Expand All @@ -229,21 +204,40 @@ 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;
}
cpu_relax();
spin_lock(&cpu->lock);
if (!cpu->scheduled) {
cpu->done = true;
spin_unlock(&cpu->lock);
return;
}
spin_unlock(&cpu->lock);

while (list_is_empty(&cpu->task_queue))
cpu_relax();

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();
}
} while (!list_is_empty(&cpu->task_queue));

spin_lock(&cpu->lock);
cpu->done = true;
spin_unlock(&cpu->lock);
}
8 changes: 6 additions & 2 deletions drivers/acpi/acpica/osl.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,12 +374,16 @@ ACPI_STATUS AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Functio
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
4 changes: 3 additions & 1 deletion include/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ struct cpu {
list_head_t list;

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

percpu_t *percpu;

spinlock_t lock;

list_head_t task_queue;
};
typedef struct cpu cpu_t;

Expand Down
17 changes: 9 additions & 8 deletions include/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef KTF_SCHED_H
#define KTF_SCHED_H

#include <cpu.h>
#include <ktf.h>
#include <lib.h>
#include <list.h>
Expand Down Expand Up @@ -66,7 +67,7 @@ struct task {
task_group_t gid;
task_state_t state;

unsigned int cpu;
cpu_t *cpu;

const char *name;
task_func_t func;
Expand All @@ -79,19 +80,19 @@ typedef struct task task_t;
/* External declarations */

extern void init_tasks(void);
extern task_t *get_task_by_id(tid_t id);
extern task_t *get_task_by_name(const char *name);
extern task_t *get_task_for_cpu(unsigned int cpu);
extern void schedule_task(task_t *task, unsigned int cpu);
extern void run_tasks(unsigned int cpu);
extern void wait_for_task_group(task_group_t group);
extern task_t *get_task_by_name(cpu_t *cpu, const char *name);
extern task_t *new_task(const char *name, task_func_t func, void *arg, task_type_t type);
extern int schedule_task(task_t *task, cpu_t *cpu);
extern void run_tasks(cpu_t *cpu);
extern void wait_for_task_group(const cpu_t *cpu, task_group_t group);

/* Static declarations */

static inline void set_task_group(task_t *task, task_group_t gid) { task->gid = gid; }

static inline void wait_for_all_tasks(void) { wait_for_task_group(TASK_GROUP_ALL); }
static inline void wait_for_cpu_tasks(cpu_t *cpu) {
wait_for_task_group(cpu, TASK_GROUP_ALL);
}

static inline task_t *new_kernel_task(const char *name, task_func_t func, void *arg) {
return new_task(name, func, arg, TASK_TYPE_KERNEL);
Expand Down
2 changes: 0 additions & 2 deletions include/smp/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
#include <lib.h>
#include <processor.h>

#define INVALID_CPU (~0U)

/* External declarations */

extern void init_smp(void);
Expand Down
2 changes: 1 addition & 1 deletion smp/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void __noreturn ap_startup(void) {
ap_callin = true;
smp_wmb();

run_tasks(cpu->id);
run_tasks(cpu);

while (true)
halt();
Expand Down

0 comments on commit 323a49a

Please sign in to comment.