ardix/kernel/sched.c

185 lines
3.6 KiB
C
Raw Normal View History

/* See the end of this file for copyright, license, and warranty information. */
2021-07-31 19:39:51 +02:00
#include <arch-generic/sched.h>
#include <arch-generic/watchdog.h>
2020-11-30 02:26:17 +01:00
#include <ardix/atomic.h>
2021-08-04 03:29:52 +02:00
#include <ardix/kevent.h>
2020-11-30 02:26:17 +01:00
#include <ardix/malloc.h>
#include <ardix/sched.h>
#include <ardix/types.h>
2020-11-30 02:26:17 +01:00
#include <errno.h>
#include <stddef.h>
#include <string.h>
extern uint32_t _sstack;
extern uint32_t _estack;
2021-08-01 23:32:12 +02:00
static struct task *tasktab[CONFIG_SCHED_MAXTASK];
struct task *current;
2021-08-04 03:25:04 +02:00
static struct task idle_task;
2021-08-05 16:14:18 +02:00
int need_resched = 0;
2021-07-31 15:58:29 +02:00
static void task_destroy(struct kent *kent)
{
struct task *task = container_of(kent, struct task, kent);
2021-08-01 23:32:12 +02:00
tasktab[task->pid] = NULL;
free(task);
}
int sched_init(void)
{
int i;
2021-08-01 23:32:12 +02:00
current = malloc(sizeof(*current));
if (current == NULL)
2020-11-30 02:26:17 +01:00
return -ENOMEM;
2021-08-01 23:32:12 +02:00
current->kent.parent = kent_root;
current->kent.destroy = task_destroy;
i = kent_init(&current->kent);
2021-08-04 03:25:04 +02:00
if (i != 0)
goto out;
2021-08-04 03:25:04 +02:00
current->sp = &_sstack;
current->stack_bottom = &_estack;
current->pid = 0;
current->state = TASK_READY;
tasktab[0] = current;
2021-08-04 03:25:04 +02:00
for (i = 1; i < CONFIG_SCHED_MAXTASK; i++)
tasktab[i] = NULL;
2021-08-04 03:25:04 +02:00
i = arch_watchdog_init();
if (i != 0)
goto out;
i = arch_sched_hwtimer_init(CONFIG_SCHED_FREQ);
if (i != 0)
goto out;
i = arch_idle_task_init(&idle_task);
if (i != 0)
goto out;
/*
* we don't really need to deallocate resources on error because we
* are going to panic anyways if the scheduler fails to initialize.
*/
2021-08-04 03:25:04 +02:00
out:
return i;
}
2021-08-05 16:14:18 +02:00
#include <arch/debug.h>
2020-06-14 05:51:01 +02:00
/**
2021-08-05 16:14:18 +02:00
* @brief Determine whether the specified task is a candidate for execution.
2020-06-14 05:51:01 +02:00
*
2021-08-05 16:14:18 +02:00
* @param task The task
2021-02-01 00:07:45 +01:00
* @returns whether `task` could be run next
2020-06-14 05:51:01 +02:00
*/
2021-08-04 03:25:04 +02:00
static inline bool can_run(const struct task *task)
2020-06-14 05:51:01 +02:00
{
2021-08-05 16:14:18 +02:00
switch (task->state) {
case TASK_SLEEP:
return tick - task->last_tick > task->sleep;
case TASK_QUEUE:
case TASK_READY:
return true;
case TASK_DEAD:
case TASK_IOWAIT:
return false;
}
return false; /* this shouldn't be reached */
2020-06-14 05:51:01 +02:00
}
2021-08-05 16:14:18 +02:00
void *sched_switch(void *curr_sp)
{
2021-02-01 00:07:45 +01:00
struct task *tmp;
2021-08-04 03:25:04 +02:00
int i;
2021-08-01 23:32:12 +02:00
pid_t nextpid = current->pid;
current->sp = curr_sp;
2021-08-05 16:14:18 +02:00
//__breakpoint;
2021-08-04 03:29:52 +02:00
kevents_process();
2021-08-01 23:32:12 +02:00
if (current->state != TASK_SLEEP && current->state != TASK_IOWAIT)
current->state = TASK_QUEUE;
2020-06-14 05:51:01 +02:00
2021-08-04 03:25:04 +02:00
for (i = 0; i < CONFIG_SCHED_MAXTASK; i++) {
2021-08-05 16:14:18 +02:00
//__breakpoint;
2020-11-30 02:26:17 +01:00
nextpid++;
2021-02-01 00:07:45 +01:00
nextpid %= CONFIG_SCHED_MAXTASK;
2021-08-01 23:32:12 +02:00
tmp = tasktab[nextpid];
2021-08-04 03:25:04 +02:00
if (tmp != NULL && can_run(tmp)) {
2021-08-01 23:32:12 +02:00
current = tmp;
break;
}
}
2021-08-04 03:25:04 +02:00
if (i == CONFIG_SCHED_MAXTASK)
current = &idle_task;
2021-08-01 23:32:12 +02:00
current->state = TASK_READY;
2021-08-05 16:14:18 +02:00
current->last_tick = tick;
//__breakpoint;
2021-08-01 23:32:12 +02:00
return current->sp;
}
struct task *sched_fork(struct task *parent)
{
pid_t pid;
struct task *child = malloc(sizeof(*child));
if (child == NULL)
goto err_alloc;
for (pid = 0; pid < CONFIG_SCHED_MAXTASK; pid++) {
2021-08-01 23:32:12 +02:00
if (tasktab[pid] == NULL)
break;
}
if (pid == CONFIG_SCHED_MAXTASK)
goto err_maxtask;
child->kent.parent = &parent->kent;
2021-07-31 15:58:29 +02:00
child->kent.destroy = task_destroy;
if (kent_init(&child->kent) != 0)
goto err_kent;
child->pid = pid;
return child;
err_kent:
err_maxtask:
free(child);
err_alloc:
return NULL;
}
2021-08-05 16:14:18 +02:00
void msleep(unsigned long int ms)
{
//__breakpoint;
current->sleep = ms_to_ticks(ms);
yield(TASK_SLEEP);
//__breakpoint;
}
2020-10-11 19:35:30 +02:00
/*
* This file is part of Ardix.
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
2020-10-11 19:35:30 +02:00
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
2020-10-11 19:35:30 +02:00
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
2020-10-11 19:35:30 +02:00
*/