第24章 任务中定时器的设计与实现

目标:实现定时器功能,实现系统调用sleep。

定时器的定义如下所示,系统使用定时器链表管理定时器。

struct timer{
    struct task_struct *task;
    struct timer *next, *prev;
    int time_slice;
};

struct timer_list{
    unsigned long timer_nr;
    struct timer *head, *tail;
};


任务调用sleep(int ms)函数时,会在定时器链表上插入一个定时器,然后任务挂起。每次时钟中断,内核都会检查定时器链表上的定时器,假如定时器到点,则删除定时器,并唤醒与该定时器关联的任务。定时器插入算法就是遍历链表,算法复杂度为O(n)。定时器检查算法的复杂度为O(1)。

假设

  • 任务A睡20秒
  • 任务B睡5秒
  • 任务C睡9秒
  • 任务D睡2秒
  • 任务E睡14秒
  • 任务F睡40秒
任务 D B C E A F
时刻 2 5 9 14 20 40
定时器的时间长度值 2 3 4 5 6 20

也就是在定时器链表上,第1个定时器的时间值是2秒,对应的任务是D;第2个定时器的时间值是3秒,对应的任务是B;

定时器插入函数如下所示

//把定时器插入到定时器链表中
//每个定时器代表一段距离,表示离左边定时器的时间片距离
struct timer * add_timer(struct timer *t)
{
   if(!t)
      return NULL;

   //当定时器链表为空时
   if(task_timer_list.head == NULL)
   {
    task_timer_list.head = task_timer_list.tail = t;
    ++task_timer_list.timer_nr;
    return t;
   }

   //当定时器不为空时
   struct timer *p = NULL;
   p = task_timer_list.head;
   while(p && p->time_slice <= t->time_slice)
   {
    t->time_slice -= p->time_slice;
    p = p->next;
   }

   if(p == task_timer_list.head) //插在最前面
   {
        p->time_slice -= t->time_slice;

    p->prev = t;
    t->next = p;
    t->prev = NULL;
    task_timer_list.head = t;
   }
   else if(p == NULL) //插在最后面
   {
    task_timer_list.tail->next = t;
    t->prev = task_timer_list.tail;
    t->next = NULL;
    task_timer_list.tail = t;
   }
   else  //插在中间
   {
        p->time_slice -= t->time_slice;
    
    p->prev->next = t;
    t->next = p;
    t->prev = p->prev;
    p->prev = t;    
   }

   ++task_timer_list.timer_nr;

   return t;
}

定时器检查函数如下所示

void check_timer()
{

    struct timer *p = NULL , *tmp = NULL;
    p = task_timer_list.head;
    //检查定时器链表
    if(p)    //链表上有定时器
    {
    //定时器到点
    if(--(p->time_slice) == 0)
    {
        //可能有多个定时器到点
        while(p && p->time_slice == 0)
        {
    
        if(p->next == NULL)    //只剩下一个定时器
        {
            task_timer_list.head = task_timer_list.tail = NULL;
        }
        else     //剩下多个定时器
        {
           task_timer_list.head = p->next;
           task_timer_list.head->prev = NULL; 
        }

            
        //定时器的任务为空可能是因为该任务已被删除(sys_remove_task)
        //定时器指定的任务有可能已经被其他任务唤醒了(使用resume_task系统调用)
        if(p->task && p->task->state == TASK_STATE_SUSPEND)
        {
            //从挂起队列中移除任务
            remove_task_from_suspend(p->task);

            //把任务插入到运行队列
            insert_task_to_running(p->task, cpu0.expired);
        }
            
        tmp = p;
        p = p->next;
        
        //初始化定时器
        init_task_timer(tmp);
        }
    }


    }
}

timer.c源代码如下所示

#include "asm.h"
#include "io.h"
#include "idt.h"
#include "video.h"
#include "kernel.h"
#include "8259.h"
#include "timer.h"
#include "task.h"


void init_timer(unsigned int hz)
{
    unsigned int divisor = CLOCK_RATE/hz;
    outportb(0x43, 0x36);        //选择计数器0,输出模式3
    outportb(0x40, divisor&0xff);   //把初始值的低字节写入LSB中
    outportb(0x40, (divisor>>8)&0xff);    //把初始值的高字节写入MSB中
}

volatile unsigned long  timer_ticks = 0;
void do_timer(void)
{
    timer_ticks++;
    //检查定时器链表
    check_timer();

    //管理当前任务的时间片
    manage_time_slice();

    outportb(M_PIC, EOI);   //告诉PIC1,中断处理函数已经结束,可以处理新来的中断。
                //因为定时器是连接到PIC1的IRQ0上,所以不许要通知PIC2
    //调度
    scheduler();
}

最终的task.c源代码如下所示

#include "define.h"
#include "task.h"
#include "kernel.h"
#include "asm.h"
#include "video.h"

static unsigned long task0_stack[1024] = {0};

struct task_struct task0 = {
    //tss
    {
    //back_link
    0,
    //esp0, ss0
    (unsigned int)&(task0_stack[1023]), DATA_SEL,
    //esp1, ss1
    0, 0,
    //esp2, ss2
    0, 0,
    //cr3
    0,
    //eip
    0,
    //eflags
    0,
    //eax,ecx,edx,ebx
    0, 0, 0, 0,
    //esp,ebp
    0, 0,
    //esi,edi
    0, 0,
    //es,cs,ss,ds,fs,gs
    USER_DATA_SEL, USER_CODE_SEL, USER_DATA_SEL, USER_DATA_SEL, USER_DATA_SEL, USER_DATA_SEL,
    //ldt
    0x20,
    //trace_iobitmap
    0x0
    },
    //tss_descriptor
    0,
    //ldt_descriptor
    0,
    //ldt[2];
    {DEFAULT_LDT_CODE, DEFAULT_LDT_DATA},
    //task_function
    0,
    //stack0
    NULL,
    //stack3
    NULL,
    //stack0_size
    0,
    //stack3_size
    0,
    //state
    TASK_STATE_RUNNING,    
    //priority
    0,
    //time_slice
    INITIAL_TIME_SLICE,
    //pid
    0,
    //ppid
    0,
    //next
    NULL,
    //prev
    NULL,
    //hnext
    NULL,
    //hprev
    NULL,
    //prio_array *
    NULL,
    //timer
    {
    //strcut task_struct *task
    NULL,
    //struct timer *next, *prev
    NULL,NULL,
    //int slice
    0
    },
    //msgbox
    {
    //msg_nr
    0,
    //msg_start
    0,
    //msg_end
    0,
    //box
    {}
    }
};

struct task_struct *current = &task0;
struct run cpu0;

static int newpid = 0;

static int get_newpid()
{
    return ++newpid;
}

unsigned long long set_tss(unsigned long long tss_offset)
{
    unsigned long long tss_descriptor = 0x0000890000000067ULL;
    tss_descriptor |= (tss_offset<<16)&0xffffff0000ULL;
    tss_descriptor |= (tss_offset<<32)&0xff00000000000000ULL;
    return ((unsigned long long *)GDT_ADDR)[CURRUENT_TASK_TSS] = tss_descriptor;
}


unsigned long long set_ldt(unsigned long long ldt_offset)
{
    unsigned long long ldt_descriptor = 0x000082000000000fULL;
    ldt_descriptor |= (ldt_offset<<16)&0xffffff0000ULL;
    ldt_descriptor |= (ldt_offset<<32)&0xff00000000000000ULL;
    return ((unsigned long long *)GDT_ADDR)[CURRUENT_TASK_LDT] = ldt_descriptor;
}


unsigned long long get_tss(void)
{
    return ((unsigned long long *)GDT_ADDR)[CURRUENT_TASK_TSS];
}

unsigned long long get_ldt(void)
{
    return ((unsigned long long *)GDT_ADDR)[CURRUENT_TASK_LDT];
}


void init_task_timer(struct timer *timer)
{
    if(!timer)
    return NULL;
    timer->task = NULL;  //表示当前定时器非使用状态
    timer->next = timer->prev = NULL;
    timer->time_slice = 0;
}

struct timer_list task_timer_list = {0, NULL, NULL};

//初始化定时器链表
void init_task_timer_list()
{
    task_timer_list.timer_nr = 0;
    task_timer_list.head = task_timer_list.tail = NULL;
}

//把定时器插入到定时器链表中
//每个定时器代表一段距离,表示离左边定时器的时间片距离
struct timer * add_timer(struct timer *t)
{
   if(!t)
      return NULL;

   //当定时器链表为空时
   if(task_timer_list.head == NULL)
   {
    task_timer_list.head = task_timer_list.tail = t;
    ++task_timer_list.timer_nr;
    return t;
   }

   //当定时器不为空时
   struct timer *p = NULL;
   p = task_timer_list.head;
   while(p && p->time_slice <= t->time_slice)
   {
    t->time_slice -= p->time_slice;
    p = p->next;
   }

   if(p == task_timer_list.head) //插在最前面
   {
        p->time_slice -= t->time_slice;

    p->prev = t;
    t->next = p;
    t->prev = NULL;
    task_timer_list.head = t;
   }
   else if(p == NULL) //插在最后面
   {
    task_timer_list.tail->next = t;
    t->prev = task_timer_list.tail;
    t->next = NULL;
    task_timer_list.tail = t;
   }
   else  //插在中间
   {
        p->time_slice -= t->time_slice;
    
    p->prev->next = t;
    t->next = p;
    t->prev = p->prev;
    p->prev = t;    
   }

   ++task_timer_list.timer_nr;

   return t;
}


//从定时器链表上移除指定任务的定时器
//被sys_delete_task sys_resume_task sys_suspend_task 函数调用
void remove_task_timer(struct task_struct *task)
{
    if(!task)
    return ;
    if(!(task->timer.task))
    return ;
    //定时器在链表中的位置有三种:表头;表尾;表中间
    if(task_timer_list.head == &(task->timer)) //表头
    {
    if(task_timer_list.tail == &(task->timer))
    {
        task_timer_list.head = task_timer_list.tail = NULL;
    }
    else
    {
        task_timer_list.head = task->timer.next;
        task_timer_list.head->prev = NULL;
        task_timer_list.head->time_slice += task->timer.time_slice;  //这条语句是必须的
    }

    }
    else if(task_timer_list.tail == &(task->timer))  //表尾
    {
    task_timer_list.tail = task->timer.prev;
    task_timer_list.tail->next = NULL;
    }
    else  //表中间
    {
    task->timer.prev->next = task->timer.next;
    task->timer.next->prev = task->timer.prev;
    task->timer.next->time_slice += task->timer.time_slice;  //这条语句是必须的
    }

    init_task_timer(&(task->timer));
}

//添加任务到任务链表尾部
void add_task(struct list_pcd * list, struct task_struct *task)
{
    
    if(list->head == NULL) //队列为空
    {
    list->head = list->tail = task;
    task->next = task->prev = NULL;
    }
    else    //队列不为空
    {
    list->tail->next = task;
    task->prev = list->tail;
    task->next = NULL;
    list->tail = task;
    }
}


//从任务链表中删除任务
void remove_task(struct list_pcd * list, struct task_struct *task)
{

    //该任务在队列中有三种情况:队头;队尾;队中
    if(list->head == task)  //队头
    {
    if(task->next)//队列有多个任务
    {
        list->head = task->next;
        list->head->prev = NULL;
    }
    else //队列只有一个任务
    {
        list->head = list->tail = NULL;
    }

    }
    else if(list->tail == task) //队尾
    {
    if(task->prev) //队列有多个任务
    {
        list->tail = task->prev;
        list->tail->next = NULL;
    }
    else //队列只有一个任务
    {
        list->head = list->tail = NULL;
    }
    }
    else //队中
    {
    task->prev->next = task->next;
    task->next->prev = task->prev;
    }    

}


//把任务插入优先级数组中
//被sys_create_task()和manage_time_slice()函数调用
//本函数访问共享资源cpu0,因此要保证调用本函数时不能被打断
void insert_task_to_running(struct task_struct *task, struct prio_array *py)
{

    //都是把任务插在链表尾部
    add_task(py->queue + task->priority, task);

    //更新任务结构
    task->py = py;
    task->state = TASK_STATE_RUNNING;

    //更新优先级数组
    ++(py->task_nr);
    py->bitmap |= (1 << task->priority);
}

//把任务从优先级数组上移除
void remove_task_from_running(struct task_struct* task)
{
    if(task->state != TASK_STATE_RUNNING)
    return;
    struct list_pcd *list = NULL;
    list = (struct list_pcd*)(task->py->queue + task->priority);
    //把任务从运行队列中移除
    remove_task(list, task);
    
    
    //更新优先级数组
    --(task->py->task_nr);

    //假如任务所在的优先级链表已空,则更新优先级位图
    if(list->head == NULL)
    task->py->bitmap &= ~(1 << task->priority);    
}

//初始化CPU0,把任务0插入active优先级数组中
void init_cpu0(void)
{
    struct list_pcd * list_pcd_ptr = NULL;
    int i = 0, j = 0;
    for(i = 0; i < 2; i++)
    {
    cpu0.pa[i].task_nr = 0;
    cpu0.pa[i].bitmap = 0x0;
    for(j = 0; j < PRIO_NR; j++)
    {
        cpu0.pa[i].queue[j].head = NULL;
        cpu0.pa[i].queue[j].tail = NULL;
    }
    }
    
    cpu0.active = cpu0.pa;
    cpu0.expired = cpu0.pa+1;
    
    //把任务0插入active优先级数组中去,一定要插入active优先级数组,这很重要
    insert_task_to_running(&task0, cpu0.active);
    
    //把任务0插到任务HASH表中去
    add_task_to_hash(&task0);
}

void init_tasks(void)
{
    //设置GDT中的TSS和LDT
    set_tss((unsigned long long)&(task0.tss));
    set_ldt((unsigned long long)&(task0.ldt));
    __asm__("ltrw %%ax\n\t"::"a"(TSS_SEL));
    __asm__("lldt %%ax\n\t"::"a"(LDT_SEL));

    //初始化CPU0,把任务0插入expired优先级数组中
    init_cpu0();

    //初始化定时器链表
    init_task_timer_list();

}

//系统调用,创建新的任务
//返回新任务的PID
int  sys_create_task(unsigned int task_function, unsigned int stack0_size, unsigned int stack3_size)
{
    int pid = 0;
    struct task_struct *task = NULL;
    void *stack0 = NULL, *stack3 = NULL;

    stack0_size = (stack0_size ? stack0_size : DEFAULT_STACK_SIZE);
    stack3_size = (stack3_size ? stack3_size : DEFAULT_STACK_SIZE);

    task = (struct task_struct *)malloc(sizeof(struct task_struct));
    stack0 = malloc(stack0_size);
    stack3 = malloc(stack3_size);
    if(!task || !stack0 || !stack3)
    {
    free(task);
    free(stack0);
    free(stack3);
    return -1;
    }

    *task = task0;

    task->tss.esp0 = stack0 + stack0_size;
    task->tss.eip = task_function;
    //task->tss.eflags = 0x3202;    // I(中断位)=1,使能INTR引脚,开中断
                        // IOPL(i/o优先级)=3,当任务的优先级高于或等于IOPL时,I/O指令才能顺利执行。
    task->tss.eflags = 0x202;        //不需要设置IOPL了,通过系统调用执行I/O指令
    task->tss.esp = stack3 + stack3_size;

    task->task_function = task_function;
    task->stack0 = stack0 + stack0_size;
    task->stack3 = stack3 + stack3_size;
    task->stack0_size = stack0_size;
    task->stack3_size = stack3_size;

    task->state = TASK_STATE_RUNNING;
    //设置时间片
    task->time_slice = INITIAL_TIME_SLICE;

    //设置PID和PPID
    pid = task->pid = get_newpid();
    task->ppid = current->pid;

    //设置优先级
    task->priority = ( task->pid % PRIO_NR);
    //task->priority = INITIAL_PRIO;

    //初始化定时器
    init_task_timer(&(task->timer));

    //初始化任务的信箱
    task->msgbox.msg_nr = 0;
    task->msgbox.msg_start = task->msgbox.msg_end = 0;

    //插入到cpu0中的expired优先级数组中
    cli();
    insert_task_to_running(task, cpu0.expired);
    
    //插到任务HASH表中
    add_task_to_hash(task);
    sti();


    return pid;
}

//计算当前任务的时间片,假如当前任务的时间片用完,则从新分配时间片,并把任务插入到expired优先级数组中
//这里存在一个假设,即当前任务是所在优先级队列的第一个任务;
//本函数需要访问共享资源cpu0,因此需要保证该调用该函数时不能被打断
void manage_time_slice(void)
{
    struct list_pcd * list_pcd_ptr = NULL;
    list_pcd_ptr = cpu0.active->queue + current->priority;  //指向当前任务所在的优先级队列

    //计算当前任务的时间片
    if(--current->time_slice > 0) //当前任务还有时间片
    {
    if(list_pcd_ptr->head != list_pcd_ptr->tail) //该优先级上还有>1个任务
    {
        //轮转算法,把当前任务插到队尾
        list_pcd_ptr->head = current->next;
        list_pcd_ptr->tail->next = current;
        current->prev = list_pcd_ptr->tail;
        list_pcd_ptr->tail = current;
        current->next = NULL;
        list_pcd_ptr->head->prev = NULL;
    }
    }
    else  //当前任务没有时间片,从队列中摘掉该任务
    {
    //摘取当前任务
    if(list_pcd_ptr->head != list_pcd_ptr->tail) //该优先级上还有>1个任务
    {
        list_pcd_ptr->head = current->next;
        list_pcd_ptr->head->prev = NULL;
    }
    else    //该优先级上只有当前任务
    {
        list_pcd_ptr->head = list_pcd_ptr->tail = NULL;
        //更新优先级数组位图
        cpu0.active->bitmap &= ~(1 << current->priority);
    }

    //更替新优先级数组
    --(cpu0.active->task_nr);
    //重新给任务分配时间片
    current->time_slice = INITIAL_TIME_SLICE;
    //把任务插入expired优先级数组中
    insert_task_to_running(current,cpu0.expired);
    }


}

static inline unsigned long  sched_find_first_bit(const unsigned long word)
{
    unsigned long index = word;
    __asm__ ("bsfl %1, %0 \n\t" \
    :"=r"(index):"rm"(index));
    return index;
}

//时间片轮转调度算法
//本函数需要访问共享资源cpu0,因此需要保证该调用该函数时不能被打断,该函数必须在临界区内,不能开中断。
//而且scheduler调用的函数也不能开中断
void scheduler(void)
{
    struct task_struct *v = NULL;
    struct list_pcd * list_pcd_ptr = NULL;
    struct prio_array *py = NULL;
    unsigned long index = 0;

    //加入active优先级数组中没有可运行的任务,则调换active和expired的指针。

    py = cpu0.active;
    if(py->task_nr == 0)
    {
    cpu0.active = cpu0.expired;
    cpu0.expired = py;
    py = cpu0.active;
    }

    if(py->task_nr == 0)
    {
        sys_kprint(char_attr(BLACK,RED),"\tScheduler Error: no running task in priority array.\n");
        while(1);
    }

    //在active优先级数组中找到具有任务的优先级最高的任务队列,取得任务队列的头个任务
    index = sched_find_first_bit(py->bitmap);
    list_pcd_ptr = py->queue + index;
    v = list_pcd_ptr->head;


    if(v != current)
    {
    current->tss_descriptor = get_tss();
    current->ldt_descriptor = get_ldt();
    v->tss_descriptor = set_tss((unsigned long long)&(v->tss));
    v->ldt_descriptor = set_ldt((unsigned long long)&(v->ldt));
    current = v;
    __asm__ volatile("ljmp  {1}quot; TSS_SEL_STR ", $0\n\t");
    }
}

//挂起任务队列
struct task_list suspend_tasks;
//死亡任务队列
struct task_list  dead_tasks;


void init_suspend_tasks()
{
    suspend_tasks.task_nr = 0;
    suspend_tasks.list.head = NULL;
    suspend_tasks.list.tail = NULL;
}

void init_dead_tasks()
{
    dead_tasks.task_nr = 0;
    dead_tasks.list.head = NULL;
    dead_tasks.list.tail = NULL;
}

//插入任务到挂起任务队列队尾
void insert_task_to_suspend(struct task_struct *task)
{
    task->state = TASK_STATE_SUSPEND;
    add_task(&(suspend_tasks.list), task);
    ++suspend_tasks.task_nr;
}






//插入任务到死亡任务队列队尾
void insert_task_to_dead(struct task_struct *task)
{

    task->state = TASK_STATE_DEAD;
    add_task(&(dead_tasks.list), task);
    ++dead_tasks.task_nr;

}

//从挂起任务队列中删除指定的任务
void remove_task_from_suspend(struct task_struct *task)
{
    if(task->state != TASK_STATE_SUSPEND)
    return ;
    remove_task(&(suspend_tasks.list), task);
    --suspend_tasks.task_nr;
}

void remove_task_from_dead(struct task_struct *task)
{
    if(task->state != TASK_STATE_DEAD)
    return ;
    remove_task(&(dead_tasks.list), task);
    --dead_tasks.task_nr;
}


struct task_hash tasks_hash;
void init_tasks_hash()
{
    tasks_hash.task_nr = 0;
    int i = 0;
    for(i = 0; i < TASK_HASH_NR;i++)
    {
    tasks_hash.table[i].head = tasks_hash.table[i].tail = NULL;
    }
}

void add_task_to_hash(struct task_struct *task)
{
    
    struct list_pcd *list = NULL;
    list = &(tasks_hash.table[task->pid%TASK_HASH_NR]);
    if(list->head == NULL) //队列为空
    {
    list->head = list->tail = task;
    task->hnext = task->hprev = NULL;
    }
    else    //队列不为空
    {
    list->tail->hnext = task;
    task->hprev = list->tail;
    task->hnext = NULL;
    list->tail = task;
    }

    ++tasks_hash.task_nr;
}

void remove_task_from_hash(struct task_struct *task)
{
    struct list_pcd *list = NULL;
    list = &(tasks_hash.table[task->pid%TASK_HASH_NR]);
    //该任务在队列中有三种情况:队头;队尾;队中
    if(list->head == task)  //队头
    {
    if(task->hnext)//队列有多个任务
    {
        list->head = task->hnext;
        list->head->hprev = NULL;
    }
    else //队列只有一个任务
    {
        list->head = list->tail = NULL;
    }

    }
    else if(list->tail == task) //队尾
    {
    if(task->hprev) //队列有多个任务
    {
        list->tail = task->hprev;
        list->tail->hnext = NULL;
    }
    else //队列只有一个任务
    {
        list->head = list->tail = NULL;
    }
    }
    else //队中
    {
    task->hprev->hnext = task->hnext;
    task->hnext->hprev = task->hprev;
    }    
    --tasks_hash.task_nr;    
}

struct task_struct * query_task_from_hash(int pid)
{
    struct task_struct *t;
    t = tasks_hash.table[pid%TASK_HASH_NR].head;
    for(; t; t = t->hnext )
    {
    if(t->pid == pid)
        return t;    
    }

    return NULL;
}

//挂起任务
//该函数访问共享资源,因此需要关中断
int sys_suspend_task(int pid)
{
    int ret = 0;
    struct task_struct *task = NULL;

    cli();
    if(pid < 0)
    {
    ret = 1;
    goto end;
    }
    
    //查询是否存在这个pid的任务
    task = query_task_from_hash(pid);
    if(!task)
    {
    ret = 2;
    goto end;
    }
    
    //判断该任务的状态,是否是RUNNING态
    if(task->state != TASK_STATE_RUNNING)
    {
    ret = 3;
    goto end;
    }

    //把该任务从运行队列移除
    remove_task_from_running(task);    
    
    //把该任务添加到挂起队列
    insert_task_to_suspend(task);
    
    //判断当前运行队列是否为空,假如为空则唤醒任务0
    if(cpu0.active->task_nr == 0 && cpu0.expired->task_nr == 0)
    {
    //把该任务从挂起队列删除
    remove_task_from_suspend(&task0);    

    //删除任务0上的定时器
    remove_task_timer(&task0);
    
        //把该任务添加到运行队列
    insert_task_to_running(&task0, cpu0.expired);

    }
    //判断该PID是否是当前任务的PID
    if(task == current)
    {
    scheduler();
    }
    
end:
    sti();
    return ret;
}

//把任务从挂起态唤醒
//该函数访问共享资源,因此需要关中断
int sys_resume_task(int pid)
{
    int ret = 0;
    struct task_struct *task = NULL;

    cli();
    if(pid < 0)
    {
    ret = 1;
    goto end;
    }
    
    //查询是否存在这个pid的任务
    task = query_task_from_hash(pid);
    if(!task)
    {
    ret = 2;
    goto end;
    }
    
    //判断该任务的状态,是否是SUSPEND态
    if(task->state != TASK_STATE_SUSPEND)
    {
    ret = 3;
    goto end;
    }

    //把该任务从挂起队列删除
    remove_task_from_suspend(task);    

    //删除任务上的定时器
    remove_task_timer(task);
    
    //把该任务添加到运行队列
    insert_task_to_running(task, cpu0.expired);
    
    
end:
    sti();
    return ret;
}


//删除任务
//该函数访问共享资源,因此需要关中断
int sys_delete_task(int pid)
{
    int ret = 0;
    struct task_struct *task = NULL;

    cli();
    if(pid <= 0)  //不能删除任务0,因为任务0有回收死亡任务的作用  
    {
    ret = 1;
    goto end;
    }
    
    //查询是否存在这个pid的任务
    task = query_task_from_hash(pid);
    if(!task)
    {
    ret = 2;
    goto end;
    }
    
    //判断该任务的状态
    switch(task->state)
    {
    case TASK_STATE_RUNNING:
        //把该任务从运行队列移除
        remove_task_from_running(task);    
        break;

    case TASK_STATE_SUSPEND:
        //把该任务从挂起队列删除
        remove_task_from_suspend(task);
        break;

    case TASK_STATE_DEAD:
        ret = 3;
        goto end;
        break;

    default:
        break;
    }
    

    //删除该任务上的定时器
    remove_task_timer(task);

    //把该任务添加到死亡队列
    insert_task_to_dead(task);


    //判断当前运行队列是否为空,假如为空则唤醒任务0
    if(cpu0.active->task_nr == 0 && cpu0.expired->task_nr == 0)
    {
    //把该任务从挂起队列删除
    remove_task_from_suspend(&task0);    
    
    //删除任务0上的定时器
    remove_task_timer(&task0);

        //把该任务添加到运行队列
    insert_task_to_running(&task0, cpu0.expired);

    }
    
    //判断该PID是否是当前任务的PID
    if(task == current)
    {
    scheduler();
    }
    
end:
    sti();
    return ret;
}



//移除死亡任务,从任务HASH表上删除,并释放任务所占的资源(比如内存)
//该函数访问共享资源,因此需要关中断
int sys_clear_dead_task()
{
    //关中断
    cli();

    int ret = 0;    
    //查看死亡队列是否为空
    if(dead_tasks.list.head == NULL)
    {
    ret = 1;
    goto end;
    }

    //遍历死亡队列
    struct task_struct *p = dead_tasks.list.head;
    struct task_struct *tmp = NULL;
    while(p)
    {
    printf("clear dead task pid=%d\n", p->pid);
    //从hash表中移除该任务
    remove_task_from_hash(p);

    //从死亡队列中移除该任务
    remove_task_from_dead(p);
    
    //回收死亡任务所占的资源
    //回收内存
    free((void*)(p->stack0 - p->stack0_size));
    free((void*)(p->stack3 - p->stack3_size));
    tmp = p;
    p = p->next;
    free((void*)tmp);
    }

end:

    //开中断
    sti();
    return ret;
}



//睡眠函数,已ms为单位 1s = 1000ms
//参数ms == 0时表示该任务需要挂起,然后等待其他任务唤醒
int sys_sleep(int ms)
{
    int ret = 0;
    if(ms < 0)
        return 1;

    //先把睡眠时间转换为时间片
    int time_slice = 0;
    time_slice = ms*HZ/1000;
    if(time_slice == 0)
    time_slice = 1;

    //初始化定时器
    current->timer.task = current;
    current->timer.next = current->timer.prev = NULL;
    current->timer.time_slice = time_slice;

    //关中断
    cli();

    //把定时器插入定时器链表
    add_timer(&(current->timer));

    //调用sys_suspend_task函数,把自己挂起
    ret = sys_suspend_task(current->pid);

    //开中断
    sti();

    return ret;
}

void check_timer()
{

    struct timer *p = NULL , *tmp = NULL;
    p = task_timer_list.head;
    //检查定时器链表
    if(p)    //链表上有定时器
    {
    //定时器到点
    if(--(p->time_slice) == 0)
    {
        //可能有多个定时器到点
        while(p && p->time_slice == 0)
        {
    
        if(p->next == NULL)    //只剩下一个定时器
        {
            task_timer_list.head = task_timer_list.tail = NULL;
        }
        else     //剩下多个定时器
        {
           task_timer_list.head = p->next;
           task_timer_list.head->prev = NULL; 
        }

            
        //定时器的任务为空可能是因为该任务已被删除(sys_remove_task)
        //定时器指定的任务有可能已经被其他任务唤醒了(使用resume_task系统调用)
        if(p->task && p->task->state == TASK_STATE_SUSPEND)
        {
            //从挂起队列中移除任务
            remove_task_from_suspend(p->task);

            //把任务插入到运行队列
            insert_task_to_running(p->task, cpu0.expired);
        }
            
        tmp = p;
        p = p->next;
        
        //初始化定时器
        init_task_timer(tmp);
        }
    }


    }
}


int sys_send_msg(int pid, struct msg *msg)
{
    
    int ret = 0;
    struct task_struct *task = NULL;

    cli();
    if(pid < 0 || !msg)
    {
    ret = 1;
    goto end;
    }
    
    //查询是否存在这个pid的任务
    task = query_task_from_hash(pid);
    if(!task)
    {
    ret = 2;
    goto end;
    }

    //查看任务的信箱是否有空位
    if(task->msgbox.msg_nr < TASK_MSG_NR) //有空位
    {
    //复制消息到任务的信箱的空位中
    task->msgbox.msg_end = ++(task->msgbox.msg_end)%TASK_MSG_NR;
    task->msgbox.box[task->msgbox.msg_end] = *msg;

    //消息数目增1
    ++(task->msgbox.msg_nr); 
    }
    else //无空位
    {
    ret = 3;
    goto end;
    }
end:
    sti();
    return ret;
}


int sys_receive_msg(struct msg *msg)
{
    int ret = 0;

    cli();
    if(!msg)
    {
    ret = 1;
    goto end;
    }

    //查看任务的信箱是否有消息
    if(current->msgbox.msg_nr > 0) //有消息
    {
    //复制任务信箱中的消息到msg中
    current->msgbox.msg_start = ++(current->msgbox.msg_start)%TASK_MSG_NR;
        *msg =     current->msgbox.box[current->msgbox.msg_start];

    //消息数目减1
    --(current->msgbox.msg_nr); 
    }
    else //无消息
    {
    ret = 2;
    goto end;
    }
end:
    sti();
    return ret;
}

Leave a Reply

Your email address will not be published. Required fields are marked *