📄 sched.c
字号:
#include <sched.h>
#include <s3c2410.h>
#include <interrupt.h>
#include <init.h>
#include <mmu.h>
#include <string.h>
#include <serial.h>
struct task_struct task[TASK_NR];
struct task_struct* current = NULL;
extern void __switch_to(struct task_struct *pcur,struct task_struct *pnext);
/*****************************************************************************
* 初始化task数组
* 初始化任务0,即task[0]
*****************************************************************************/
void sched_init(void)
{
struct task_struct *p = &task[0];
int i,j;
DPRINTK(KERNEL_DEBUG,"\n\rkernel:sched_init,create task 0\n\r");
for(i = 0; i < TASK_NR; i++,p++){
p->pid = -1;
p->state = TASK_UNALLOCATE;
p->count = 0;
p->priority = 0;
for(j = 0; j < 1024; j++){
p->kernelstack[j] = 0;
}
}
p = &task[0];
p->pid = 0;
p->state = TASK_RUNNING;
p->count = 5;
p->priority = 5;
p->content[0] = (unsigned long)(&task[1]);
p->content[1] = 0x5f; /*cpsr*/
p->content[2] = 0x30100000-1024; /*usr/sys模式堆栈*/
p->content[3] = 0x13; /*svc模式*/
p->content[17]= 0; /*pc*/
current = &task[0];
}
/*****************************************************************************
* 切换到task数组中处于运行状态的、count值最大的任务
* 如果所有任务的count值都为0,则重新计算count = count / 2 + priority
* 进程0不参与竞争
*****************************************************************************/
void schedule(void)
{
long max = -1;
long i = 0, next = 0;
struct task_struct * ptmp_tsk = NULL;
DPRINTK(KERNEL_DEBUG,"kernel:schedule\n\r");
while(1){
for(i = 1; i < TASK_NR; i++){
if((task[i].state == TASK_RUNNING)&&(max < (long)task[i].count)){
max = (long)task[i].count;
next = i;
}
}
/*如果所有任务都不处于就绪状态,max = -1,next = 0,跳出循环执行任务0*/
/*如果max = 0,则进行下面的计算count值*/
/*如果max > 0,则跳出循环...*/
/*这种方法太妙了,摘自linux0.11*/
if(max)break;
for(i = 0; i < TASK_NR; i++){
if(task[i].state == TASK_RUNNING)
task[i].count = task[i].priority;
// task[i].count = (task[i].count >> 1) + task[i].priority;
}
}
if(current == &task[next])
return;
if(task[next].pid < 0)
return;
ptmp_tsk = current;
current = &task[next];
DPRINTK(KERNEL_DEBUG,"kernel:__switch_to\n\r");
__switch_to(ptmp_tsk,&task[next]);
DPRINTK(KERNEL_DEBUG,"kernel:return from __switch_to\n\r");
}
/*****************************************************************************
* 当前进程count减1
* 如果当前进程不处于可运行状态,或count=0,调度进程
*****************************************************************************/
void do_timer(void)
{
int i = 0, b_wakeup = 0;
DPRINTK(KERNEL_DEBUG,"kernel:do_timer\n\r");
if(!current){
DPRINTK(KERNEL_DEBUG,"kernel:leaving do_timer,hasn't init task\n\r");
return;
}
for(i = 1; i < TASK_NR; i++){
if(task[i].state == TASK_SLEEPING){
if(!(--task[i].timer)){
task[i].state = TASK_RUNNING;
b_wakeup = 1;
}
}
}
if(current->count){
current->count--;
}
if((current->state != TASK_RUNNING)|| !current->count || b_wakeup){
schedule();
}
DPRINTK(KERNEL_DEBUG,"kernel:leaving do_timer\n\r");
}
/*******************************************************************************
* linux下,在控制台下如此运行程序:file param0 param1 ...
* 其中的file param0 param1 ...作为参数传递给int main(int argc, char **argc)
* argc为参数个数,即file,param0,param1...的个数
* argv[0]为file字串的地址,argv[1]为param0字串的地址...
*
* OSCreateProcess中参数含义为:
* 1. nand_start_addr:本进程代码存在nand flash中的位置,len:代码大小,通过这两个参数来
* 确定一个文件file
* 2. parameters为"param0 param1 param2 ...",各参数间以空格分开
* 请注意,进程main函数中的file参数就没什么用处了,我随便设为pid了
* 3. priority:进程优先级
*
* 本函数用于从nand flash中读处代码,设置其main函数执行前的环境:堆栈、参数,设置相应的任务数据结构
**********************************************************************************/
int OSCreateProcess(unsigned long nand_start_addr, unsigned long len, char *parameters, long priority)
{
unsigned long i = 1,pid,j,argc = 0;
unsigned long *p_VA;
char *pDes;
DPRINTK(KERNEL_DEBUG,"kernel:OSCreateProcess\n\r");
for(; i < TASK_NR; i++){
if(!(task[i].state == TASK_UNALLOCATE && VALIDE_TASK_INDEX(i)))
continue;
OS_ENTER_CRITICAL();
pid = i;
/*从NAND Flash中复制代码到进程号i对应的物理地址*/
/*虚拟地址SDRAM_RAW_RW_VA_BASE + i*0x100000指向PID=i的进程的1M内存,并且此虚拟地址>32M,所以与PID无关*/
DPRINTK(KERNEL_DEBUG,"kernel:OSCreateProcess::nand_read_ll\n\r");
p_VA = (unsigned long *)(SDRAM_RAW_RW_VA_BASE + pid*0x100000);
//清0
for( j = 0; j < 0x100000/4; j++)
p_VA[j] = 0;
nand_read_ll((unsigned char*)p_VA, nand_start_addr,len);
/****************************************************************************************
* 设置用户函数int main(int argc, char **argc)的参数
* 进程i的1M地址的最后1k空间用于存放参数(地址向上依次为):
* argc,argv[0],argv[1],...,argv[argc-1],NULL,"argv[0]对应的string","argv[1]对应的string",...
*****************************************************************************************/
DPRINTK(KERNEL_DEBUG,"kernel:OSCreateProcess::set the new process's parameters\n\r");
//放参数
p_VA = (unsigned long *)(SDRAM_RAW_RW_VA_BASE + pid*0x100000 + 0x100000 - 1024);
argc = 0;
j = 0;
/*计算paramters中参数个数*/
if(parameters){
while(parameters[j]){
while(parameters[j] == ' ')j++; //吃掉空格
if(!parameters[j])
break;
argc++;
while(parameters[j] && ( parameters[j] != ' '))j++; //吃掉非空格
if(!parameters[j])
break;
}
}
*p_VA++ = argc + 1; /*main函数中的argc*/
*p_VA++ = pid; /*argv[0]*/
pDes = (char *)(p_VA + argc + 1); /*pDes指向"...,argc[argc-1],NULL"后面,用来存放argv[...]对应的字符串*/
for(i = 0, j = 0; i < argc; i++){
*p_VA++ = (unsigned long)pDes -(SDRAM_RAW_RW_VA_BASE + pid*0x100000);
while(parameters[j] == ' ')j++; //吃掉空格
if(!parameters[j])
break;
while(parameters[j] && ( parameters[j] != ' ')){//复制参数
*pDes = parameters[j];
pDes++;
j++;
}
*pDes = '\0';
pDes = (char *)(((unsigned long)pDes + 4)&(~0x3)); //对齐
if(!parameters[j])
break;
}
/************************************************************************************
* 设置参数:
* 进程刚开始处于usr/sys模式
* 参考sched.S中保存进程上下文的顺序为:
* sp_svc,cpsr,sp_usr/sys,0x13(表示svc),r0-r12,lr
**************************************************************************************/
DPRINTK(KERNEL_DEBUG,"kernel:OSCreateProcess::set the new process's content\n\r");
task[pid].pid = pid;
task[pid].state = TASK_RUNNING;
task[pid].count = 15;
task[pid].priority = priority;
task[pid].content[0] = (unsigned long)(&task[pid+1]);
task[pid].content[1] = 0x5f; /*cpsr*/
task[pid].content[2] = 0x100000-1024; /*usr/sys模式堆栈*/
task[pid].content[3] = 0x13; /*svc模式*/
task[pid].content[17]= 0; /*pc*/
OS_EXIT_CRITICAL();
return 1;
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -