-
Notifications
You must be signed in to change notification settings - Fork 0
Scheduling implementation
The first step is define a task, that contains the following fields:
typedef struct task{
struct cpu_context myContext; //Context
tid tid; //Task IDentifier
task_info myInfo; //Some statics
int quantumLeft; //Quantum left
bool preemption_enable; //True for avoid context switch
enum state state; //Actual state of the task (RUN, READY, BLOCKED)
}task;Once a task is definite , we need to create the task. A task is defined by the code/instructions and the arguments/parameters, so the interface:
sys_response init_task(void * fn, void * data);Here, I'm forcing the number of arguments for a tasks to one. The 'user' must use a pointer and manage inside the task if he want to pass more than one argument.
In addition the task managment, we need some structures and policy for the scheduling process:
- Ready queue : Here the task wait in order to a quantum of CPU.
- Next task policy : In this case, the next in the ready queue. The
sched_next_rr()search in this queue for the next task to be executed. - Number of tasks : A counter for design a unique TID to all the new tasks.
- Quantum left : Remaining quantum for a context switch. In every timer tick, this variable is decremented.
- Need replacement : Condition for search the next task. In this case, is the quantum is 0 and the preemption is enabled. The
needs_sched_rr()implements this feature. - Idle task: This task is the one if we need a replacement and the ready queue is empty.
The init_schedulign() method initialize all the necessary structures.
For perform a context switch, I use the assembler entry cpu_switch_to(prev, next), this assembler instructions restore all the registers saved before. Here is the code.
In order to maintain the structures updated, the task switch manages the states and the ready queue.
Finally, a couple of details are need to achieve the scheduling process:
The system, at this develop time, have physical memory access, so I divided the address space in sections of 4KBytes (pages) and we can get a page for a new task with get_free_page() method.
The init_task(...) grabs one page for each task.
The CPU have a program counter for the address of the instruction we ask to run, but arguments are passed in order through x0-x10 and this registers are not saved by the task struct. However, we can create something in a assembler to solve this:
In the init_task, I saved the real function and data to some register and set the PC to ret_from_fork, here I can move the arguments to the x0 and call the with the real PC:
.globl ret_from_fork
ret_from_fork:
mov x0, x20
blr x19This method is defined in entry.S
All the schedule logic is inside taskscheduling.c and taskscheduling.h files.
Powered by GreenTreeData