首先查找资料,发现没有这种写法,要不就是跑裸机,把各个外设初始化,然后进入while1中,执行各种计算,这是裸机系统,更高级一点的是使用了内部中断与外部中断,进行pc跳转,进入中断,返回的while1继续执行后续循环。 但是,这样的程序while中的逻辑与每个指令的调用次数的相同的,若有些计算不需要那么多的计算次数,而有些需要多次计算呢,解决办法是有的,有人会说,使用定时器中断啊,这确实是一个办法,但这种方式进行指针跳转,消耗的时间比较多,中断更适合进行一些flag标志类的触发条件,而系统大多是时间还是在while1中度过,我们使用的while1很多时间都是在延时中度过的,这样很不好,目前开源了很多实时操作系统,我看了一下,所有的属性已经封装好了,我们只需要调用封装好的函数和宏定义即可进行类如多线程的操作,比如32是单核cpu,跑的也像多核cpu一样,多个线程的while1极大提高了cpu的使用效率。 如果只是使用开源的代码进行使用,显然我是有些强迫症的,这个东西大佬们可以写出来,都是同行,我怎么就不可以呢,我也开始试着写一个属于我的操作系统,主要功能->实现对不同任务的等级不同,会自动分配该任务的执行时间,每个任务的时间是由自身在初始化时确定。
下面就是我的掉头发时间
首先,看一下我的主函数吧,是按照RTOS的样子仿照的
#include <stdio.h>
#include "list.h"
#include <stdio.h>
#include "cx_rtos.h"
int main()
{
CX_RTOS_Init();
Kernel_Start();
printf("return 0\n");
while(1)
{
}
return 0;
}
是不是感觉似曾相识呢,接下来是,初始化任务函数 主要思路为:由于linux内核使用了大量的链表,为了更加理解他的写作手法,进行仿制,linux系统开源了list.h的纯链表的函数与宏。首先创建一个纯链表,在创建一个线程任务链表,让任务链表包含纯链表,任务链表挂载任务函数
void CX_RTOS_Init(void)
{
static create_list(name1,task1,10);
list_add_tail(&(name1.list),&Head);
static create_list(name2,task2,5);
list_add_tail(&(name2.list),&Head);
static create_list(name3,task3,2);
list_add_tail(&(name3.list),&Head);
}
链表尾插也是使用的list.h文件函数 这里需要强调一下:是如何初始化一个链表的,是使用下面的宏来操作的,具体做法如下
#define LIST_HEAD_NODE(name,address,value) { value,address, &(name.list), &(name.list) }
#define create_list(name,address,value) \
struct node name = LIST_HEAD_NODE(name,address,value)
接下来是时间调度器函数,通过遍历纯链表,得到每个链表其所属于的结构体的地址,然后调用结构体内的函数指针,调用真正的函数
void Kernel_Start(void)
{
struct node *pos;
while(1)
{
for(int i = 0;i < MAX_ID;i++)
{
list_for_each_entry(pos,&Head,list){
if(counter < pos->ID)
{
printf("%d\n",pos->ID);
pos->pthread();
}
}
counter++;
if(counter > MAX_ID)
{
counter = 0;
}
}
}
}
遍历结构体的根本是使用了下面的宏定义实现的功能。很强大
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
创建了链表,并且可以调度这个链表函数,现在和正常跑裸机是一摸一样的。如上面说的,让不同的函数执行不同的时间(不能让一个函数for循环的执行,执行完执行其他,这样会很脱节),每个函数又理解为不同的线程函数, 在遍历每个节点的时候,每个节点都有一个特定的ID,这个ID有两个作用,一个是确定该节点,另一个则是通过ID来计算时间,当遍历的一遍链表后,链表上所有节点的线程都会被执行,但若不想让某个线程执行呢,可以通过条件判断,遍历到该节点后,若ID大于一个特定值时则执行,小于则不执行,就可以控制遍历后,每个线程的调用次数,代码在上面Kernel_Start()中 此时,若有三个线程函数
void task1(void)
{
printf("this is task1()...\n");
}
void task2(void)
{
printf("this is task2()...\n");
}
void task3(void)
{
printf("this is task3()...\n");
}
原理都是一个大的while1,里面有很多小的while1 执行 可以看到每个函数都被调用了,但是调用次数不同,这也就是我想要的结果啦
最后分享一下代码
|