sched: use proper UNIX® terminology

io-wait
Felix Kopp 3 years ago
parent 61ebad5231
commit 56c76d8b4b
No known key found for this signature in database
GPG Key ID: C478BA0A85F75728

@ -9,6 +9,8 @@
#include <ardix/string.h>
#include <ardix/sched.h>
extern struct task *_sched_current_task;
void irq_sys_tick(void)
{
/*
@ -55,10 +57,10 @@ int arch_sched_hwtimer_init(unsigned int freq)
return 0;
}
void arch_sched_process_init(struct process *process, void (*entry)(void))
void arch_sched_task_init(struct task *task, void (*entry)(void))
{
struct reg_snapshot *regs = process->stack_bottom - sizeof(*regs);
process->sp = regs;
struct reg_snapshot *regs = task->stack_bottom - sizeof(*regs);
task->sp = regs;
memset(regs, 0, sizeof(*regs));
regs->hw.pc = entry;
@ -66,10 +68,10 @@ void arch_sched_process_init(struct process *process, void (*entry)(void))
regs->sw.lr = (void *)0xFFFFFFF9U;
}
void sched_yield(enum proc_state state)
void sched_yield(enum task_state state)
{
REG_SYSTICK_VAL = 0U; /* Reset timer */
_current_process->state = state;
_sched_current_task->state = state;
arch_irq_invoke(IRQNO_PEND_SV);
}

@ -3,19 +3,17 @@
#pragma once
#include <arch/hardware.h>
#include <ardix/list.h>
#include <ardix/types.h>
#ifndef CONFIG_SCHED_MAXPROC
/** The maximum number of processes. */
#define CONFIG_SCHED_MAXPROC 8
#endif /* SCHED_MAXPROC */
#ifndef CONFIG_SCHED_MAXTASK
/** The maximum number of tasks. */
#define CONFIG_SCHED_MAXTASK 8
#endif
#if CONFIG_SCHED_MAXPROC > 64
#warning "CONFIG_SCHED_MAXPROC is > 64, this could have a significant impact on performance"
#endif /* CONFIG_SCHED_MAXPROC > 64 */
#if CONFIG_SCHED_MAXTASK > 64
#warning "CONFIG_SCHED_MAXTASK is > 64, this could have a significant performance impact"
#endif
#ifndef CONFIG_SCHED_INTR_FREQ
/** Frequency (in Hertz) at which a scheduling interrupt should be fired */
@ -23,42 +21,38 @@
#endif
#ifndef CONFIG_STACKSZ
/** Per-process stack size in bytes */
/** Per-task stack size in bytes */
#define CONFIG_STACKSZ 4096U
#endif /* CONFIG_STACKSZ */
#endif
enum proc_state {
/** Process is dead / doesn't exist */
PROC_DEAD,
/** Process is ready for execution or currently running. */
PROC_READY,
/** Process is waiting for its next time share. */
PROC_QUEUE,
/** Process is sleeping, `sleep_until` specifies when to wake it up. */
PROC_SLEEP,
/** Process is waiting for I/O to flush buffers. */
PROC_IOWAIT,
enum task_state {
/** Task is dead / doesn't exist */
TASK_DEAD,
/** Task is ready for execution or currently running. */
TASK_READY,
/** Task is waiting for its next time share. */
TASK_QUEUE,
/** Task is sleeping, `sleep_until` specifies when to wake it up. */
TASK_SLEEP,
/** Task is waiting for I/O to flush buffers. */
TASK_IOWAIT,
};
/** Stores an entire process image. */
struct process {
/** Stack pointer. */
struct task {
/** current stack pointer (only gets updated for task switching) */
void *sp;
/** Bottom of the stack (i.e. the highest address). */
/** first address of the stack (highest if the stack grows downwards) */
void *stack_bottom;
/** If `state` is `PROC_SLEEP`, the last execution time. */
/** if `state` is `TASK_SLEEP`, the last execution time */
unsigned long int lastexec;
/** If `state` is `PROC_SLEEP`, the amount of us to sleep in total. */
/** if `state` is `TASK_SLEEP`, the amount of us to sleep in total */
unsigned long int sleep_usecs;
/** Process ID. */
enum task_state state;
pid_t pid;
/** Process state. */
enum proc_state state;
};
/** The currently executing process. */
extern struct process *_current_process;
/**
* Initialize the scheduler subsystem.
* This sets up a hardware interrupt timer (SysTick for Cortex-M3).
@ -66,41 +60,32 @@ extern struct process *_current_process;
int sched_init(void);
/**
* Switch to the next process (atomic / interrupt handler context only).
* Switch to the next task (interrupt context only).
* Must be called directly from within an interrupt routine.
* Takes care of the following stuff:
*
* - Selecting a new process to run, or putting the CPU to sleep
* - Updating the `_current_process` pointer
* - Setting the `state` member of both the old and new process to the
* appropriate value
* This selects a new task to be run and updates the old and new task's `state`
* field to the appropriate value.
*
* To avoid the horrors of inline assembly, the stack pointer is modified in
* actual assembler files rather than here.
*
* @param curr_sp: The stack pointer of the current process.
* @returns The stack pointer of the new process.
* @param curr_sp: stack pointer of the current task
* @returns stack pointer of the new task
*/
void *sched_process_switch(void *curr_sp);
void *sched_switch(void *curr_sp);
/**
* Create a new process.
*
* @param entry: The process entry point.
* @returns A pointer to the new process, or `NULL` if something went wrong.
* Create a copy of the current process image and return it.
*
* TODO: make something like errno to tell what *exactly* went wrong
* @param task: the task to make a copy of
* @returns the new (child) task copy, or `NULL` on failure
*/
struct process *sched_process_create(void (*entry)(void));
struct task *sched_task_clone(struct task *dest);
/**
* Request the scheduler be invoked early, resulting in the current process to
* Request the scheduler be invoked early, resulting in the current task to
* be suspended.
*
* @param state The state the process should enter.
* Allowed values are `PROC_SLEEP` and `PROC_IOWAIT`.
* @param state: State the task should enter.
* Allowed values are `TASK_SLEEP` and `TASK_IOWAIT`.
*/
void sched_yield(enum proc_state state);
void sched_yield(enum task_state state);
/*
* Copyright (c) 2020 Felix Kopp <sandtler@sandtler.club>

@ -16,45 +16,45 @@
extern uint32_t _sstack;
extern uint32_t _estack;
struct process *proc_table[CONFIG_SCHED_MAXPROC];
struct process *_current_process;
static struct task *_sched_tasktab[CONFIG_SCHED_MAXTASK];
struct task *_sched_current_task;
int sched_init(void)
{
int i;
_current_process = malloc(sizeof(*_current_process));
if (_current_process == NULL)
_sched_current_task = malloc(sizeof(*_sched_current_task));
if (_sched_current_task == NULL)
return -ENOMEM;
_current_process->sp = &_sstack;
_current_process->stack_bottom = &_estack;
_current_process->pid = 0;
_current_process->state = PROC_READY;
proc_table[0] = _current_process;
_sched_current_task->sp = &_sstack;
_sched_current_task->stack_bottom = &_estack;
_sched_current_task->pid = 0;
_sched_current_task->state = TASK_READY;
_sched_tasktab[0] = _sched_current_task;
for (i = 1; i < CONFIG_SCHED_MAXPROC; i++)
proc_table[i] = NULL;
for (i = 1; i < CONFIG_SCHED_MAXTASK; i++)
_sched_tasktab[i] = NULL;
i = arch_watchdog_init();
if (i == 0)
i = arch_sched_hwtimer_init(CONFIG_SCHED_MAXPROC);
i = arch_sched_hwtimer_init(CONFIG_SCHED_MAXTASK);
return i;
}
/**
* Determine whether the specified process should be executed next.
* Determine whether the specified task is a candidate for execution.
*
* @param proc: The process.
* @returns Whether `proc` should be next in line for the scheduler.
* @param task: the task
* @returns whether `task` could be run next
*/
static inline bool sched_proc_should_run(const struct process *proc)
static inline bool sched_task_should_run(const struct task *task)
{
enum proc_state state = proc->state;
enum task_state state = task->state;
if (state == PROC_QUEUE || state == PROC_READY || state == PROC_IOWAIT)
if (state == TASK_QUEUE || state == TASK_READY || state == TASK_IOWAIT)
return true;
return false;
@ -62,60 +62,26 @@ static inline bool sched_proc_should_run(const struct process *proc)
void *sched_process_switch(void *curr_sp)
{
pid_t nextpid = _current_process->pid;
_current_process->sp = curr_sp;
struct task *tmp;
pid_t nextpid = _sched_current_task->pid;
_sched_current_task->sp = curr_sp;
if (_current_process->state != PROC_SLEEP && _current_process->state != PROC_IOWAIT)
_current_process->state = PROC_QUEUE;
if (_sched_current_task->state != TASK_SLEEP && _sched_current_task->state != TASK_IOWAIT)
_sched_current_task->state = TASK_QUEUE;
while (1) {
nextpid++;
nextpid %= CONFIG_SCHED_MAXPROC;
if (proc_table[nextpid] != NULL && sched_proc_should_run(proc_table[nextpid])) {
_current_process = proc_table[nextpid];
nextpid %= CONFIG_SCHED_MAXTASK;
tmp = &_sched_tasktab[nextpid];
if (tmp != NULL && sched_task_should_run(_sched_current_task)) {
_sched_current_task = tmp;
break;
}
/* TODO: Add idle thread */
}
_current_process->state = PROC_READY;
return _current_process->sp;
}
struct process *sched_process_create(void (*entry)(void))
{
pid_t pid;
struct process *proc = malloc(sizeof(*proc));
if (proc == NULL)
return NULL;
atomic_enter();
for (pid = 1; pid < CONFIG_SCHED_MAXPROC; pid++) {
if (proc_table[pid] == NULL)
break;
}
if (pid == CONFIG_SCHED_MAXPROC) {
/* max number of processess exceeded */
free(proc);
atomic_leave();
return NULL;
}
proc->pid = pid;
proc->stack_bottom = &_estack - (pid * (signed)CONFIG_STACKSZ);
proc->lastexec = 0;
proc->sleep_usecs = 0;
proc->state = PROC_QUEUE;
arch_sched_process_init(proc, entry);
proc_table[pid] = proc;
atomic_leave();
return proc;
_sched_current_task->state = TASK_READY;
return _sched_current_task->sp;
}
/*

Loading…
Cancel
Save