(9)从1开始写一个操作系统

第九章

任务函数的补充

前面讲的代码基本已经把我们的内核全部都实现完了,有一些需要有的函数没有在前面讲到,在这一章我们统一补充一下,让我们的内核更加完善。

让出CPU

当存在同级优先级任务的时候,任务希望把CPU让给其它同级优先级,担忧不想自己进入非就绪态的时候需要提供一个函数,来实现既能让出CPU,CPU又不改变自己的就绪状态。其实实现起来非常简单,就是任务调度函数,但是我们的void OS_TASK_SW(void)函数是一个操作系统的私有函数,并不暴露给用户,所以我们需要将它再封装一个给用户使用的让出CPU函数。

void os_task_abandon(void)
{
    OS_TASK_SW();
}

退出任务

我们正常的任务都应该是一个while 1的永不退出的循环,但是可能我们在某些条件下需要让任务退出,或者写一些之需要单次运行的任务。根据之前的任务切换原理我们知道,如果一个任务函数真的结束了,SP指针是无法进行切换的,这样会让单片机进入异常,通常会被复位。所以我们需要一个退出的函数,来告诉操作系统去调度这个任务,并且去做一些事情善后。

首先我们要把当前任务的状态设置为OS_STAT_DEAD

我在写这个函数的时候就在思考,要不要做成像linux那样的kill可以终止其它任务的样子,后来之所以没有做是因为这个函数实在是太“毒”了,直接把就绪态改为死亡态,如果能够杀死其它任务,那么被杀死的任务没有机会再次运行,如果那个任务占用了一些资源,都没有办法进行释放。所以我觉得如果有这样的功能需要实现可以使用后面的事件机制来实现异步的通知,要比这样的杀死好的多。

void os_task_exit(void)
{
    os_tcb[os_task_running_ID].OSTCBTimeQuantaCtr = 0;
    os_tcb[os_task_running_ID].OSTCBStatus = OS_STAT_DEAD;
    OS_TASK_SW();
}

系统资源统计

既然是操作系统,那么就会有任务对系统资源的统计概念,如果不实现一个查看的方法好像这个系统就缺点什么,当然了这种东西有些人可能并不会关心,所以我们参照堆栈使用的方法,做一个宏定义来控制它是否参与编译。

#ifdef SYSTEM_DETECT_MODE
    u8             *OSTCBStkBottomPtr;      /* 堆栈的底部指针                                          */
    u8              OSTCBCyclesTot;         /* 当前任务运行的节拍数                                    */
    u8              OSTCBStkSize;           /* 堆栈的大小                                              */
#endif

我们从操作系统开始后在中断中进行计数,每切换1次进行正在运行的任务+1,当到达100次后就整体清空,并赋值给记录用的数组,这样就能统计出每100次的CPU使用率。

在中断中添加

#ifdef SYSTEM_DETECT_MODE
    if (++int_count == 100) {
        u8 i = 0;
        os_tcb[os_task_running_ID].OSTCBCyclesTot++;
        for (; i<TASK_SIZE; i++) {
            sys_stat[i].OSSSStatus = os_tcb[i].OSTCBStatus;
            sys_stat[i].OSSSCyclesTot = os_tcb[i].OSTCBCyclesTot;
            sys_stat[i].OSSSMaxUsedStk = get_stack_used(os_tcb[i].OSTCBStkBottomPtr, os_tcb[i].OSTCBStkSize);
        }
        int_count = 0;
    }
    else {
        os_tcb[os_task_running_ID].OSTCBCyclesTot++;
    }
#endif

然后我们提供一个数组来存放系统查询出来的消息

OS_SS sys_stat[TASK_SIZE]

结构体在rt_os.h中

typedef struct sys_statistics {
    u8              OSSSStatus;             /* 任务状态                                                */
    u8              OSSSCyclesTot;          /* 每100个时钟周期占用的节拍数                             */
    u8              OSSSMaxUsedStk;         /* 堆栈的最大使用量                                        */
} OS_SS;

应用程序可以自己统计该数组如下:

        printf("ID\tCPU\tSTATUS\tUSED STACK\r\n");
        for (i=0; i<TASK_SIZE; i++) {
            if (ss[i].OSSSStatus != OS_STAT_DEFAULT) {//任务已启动
                printf("%bu\t%bu%%\t%bu\t%bu\r\n", i, ss[i].OSSSCyclesTot, ss[i].OSSSStatus, ss[i].OSSSMaxUsedStk);
            }
        }

下面我们修改一下任务函数,这样可以看出统计的内容

void app_task_3(void)
{
    while (1) {
        printf("app_task_3\r\n");
        delay_ms(20);
        os_tick_sleep(100);
    }
}

void app_task_1(void)
{
    while (1) {
        printf("app_task_1\r\n");
        delay_ms(30);
        os_tick_sleep(100);
    }
}

void app_task_2(void)
{
#ifdef SYSTEM_DETECT_MODE
    OS_SS *ss = get_sys_statistics();
#endif
    while (1) {
#ifdef SYSTEM_DETECT_MODE
        u8 i;
        printf("ID\tCPU\tSTATUS\tUSED STACK\r\n");
        for (i=0; i<TASK_SIZE; i++) {
            if (ss[i].OSSSStatus != OS_STAT_DEFAULT) {//任务已启动
                printf("%bu\t%bu%%\t%bu\t%bu\r\n", i, ss[i].OSSSCyclesTot, ss[i].OSSSStatus, ss[i].OSSSMaxUsedStk);
            }
        }
#else
        debug_print("app_task_2\r\n");
#endif
        os_tick_sleep(100);
    }
}

输出如下:

[2019-09-11 19:51:11.259]# RECV ASCII>
app_task_1
[2019-09-11 19:51:11.391]# RECV ASCII>
app_task_3
[2019-09-11 19:51:11.487]# RECV ASCII>
ID   CPU  STATUS   USED STACK
0    78%  1    19
1    13%  4    23
2    1%   4    23
3    8%   4    21
[2019-09-11 19:51:12.392]# RECV ASCII>
app_task_1
[2019-09-11 19:51:12.522]# RECV ASCII>
app_task_3
[2019-09-11 19:51:12.617]# RECV ASCII>
ID   CPU  STATUS   USED STACK
0    78%  1    19
1    13%  4    23
2    1%   4    23
3    8%   4    21
[2019-09-11 19:51:13.523]# RECV ASCII>
app_task_1
[2019-09-11 19:51:13.652]# RECV ASCII>
app_task_3
[2019-09-11 19:51:13.750]# RECV ASCII>
ID   CPU  STATUS   USED STACK
0    81%  2    19
1    13%  4    23
2    0%   2    23
3    6%   1    23

至此,我们的操作系统基本功能就都已经实现完成了,我们下面要在这个基础上进行补充了。下面会分别加入任务间通讯和内存管理。

©️2020 CSDN 皮肤主题: 点我我会动 设计师:上身试试 返回首页