打印

RT-Thread源代码分析 1

[复制链接]
6125|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
byeyear|  楼主 | 2012-12-8 22:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 byeyear 于 2012-12-8 22:07 编辑

[
你可以任意转载本文,但转载请保留本段声明。
作者将尽量追求内容的正确,但不对正确性作出保证。
未经作者许可,不得用于商业目的。
作者:byeyear/告别年代
Email: byeyear@hotmail.com
]

RT-Thread是一个嵌入式实时操作系统核心,采用GPLv2授权。我从09年开始知道有RT-Thread这个东西,当时其功能与uc/OS类似,如今三年多过去,RT-Thread已经成长为哥斯拉了。其支持的arch和芯片大大增加,并且其外围组件也相当丰富,包括GUI、TCP/IP、FileSystem,支持模块动态加载,有兴趣的可以访问其网址:
www.rt-thread.org

写在前面
在我阅读一些代码分析的**时,经常发生的情况是,代码能看明白,知道这段代码是做什么的,但就是不明白为什么要这么做。本文希望能做到的一点是,不仅要分析代码“做了什么”,还要分析“为什么要这么做”。

为什么要做代码分析的工作
学习,并在学习中更好的理解,从而能够更好的使用。

RT-Thread官网已经对RTT的内核做了简要介绍,参见:
http://www.rt-thread.org/dokuwiki/doku.php?id=rt-thread%E7%BC%96%E7%A8%8B%E6%8C%87%E5%8D%97
对于上述文档已经介绍过的内容,本文将不再介绍。建议先看上述文档,本文使用的一些名词和术语直接引自上文。在上述文档的基础上,本文希望挖掘出一些更细节的东西。

分析过程尽量不涉及具体的硬件平台。在必要时,使用AT91SAM7X 这个BSP作为例子,KEIL对该CPU实现了完善的软件仿真,可以一边分析一边在模拟器上跑。

我假定您熟悉使用RT-Thread进行开发的基本过程,能够使用RT-Thread完成一个简单的应用。

开始
我们从内核对象开始。
RT-Thread操作系统的所有内核对象定义于rtdef.h。所有内核对象有一个公共成员rt_object,定义如下:


struct rt_object
{
  /* name of kernel object */
  char       name[RT_NAME_MAX];
  /* type of kernel object  */
  rt_uint8_t  type;
  /* flag of kernel object */
  rt_uint8_t  flag;
  /* list pointer of kernel object  */
  rt_list_t list;
};


为什么要给对象命名?
name保存着对象的名字。尽管就操作系统自身的运行而言,对象名称并不是必须的,但为其命名可以使我们在调试时区分各个对象。FinSH组件可以打印出对象名称。

建议的命名规则
以下是我在使用RTT和其他一些RTOS(如uc/OS)的过程中自己使用的一套对象命名规则:
对象类型+对象名称
对象类型使用两个字符表示。例如,td表示threadmx表示mutex
假如我有一个Thread,函数名为PollUserInput,那么我给这个thread命名为tdPUI。这样,一方面防止对象名重复,另一方面,在使用FinSH调试时,可以根据对象名知道该对象的用途。


flag有什么用?
例如,flag中有一位表示该对象是系统对象(静态分配)还是动态对象。当一个对象不再使用时,将根据这一位决定是否释放对象所占据的内存。


list
有了这个成员,各个相同类型的对象就可以形成链表,以便管理。


rt_object成员一般放置于各对象的开头。例如:

struct rt_ipc_object
{
  struct rt_object parent;
  rt_list_t suspend_thread;
};

为什么要把rt_object放在开头?
这就保证了各对象的起始地址同样就是嵌入在该对象头部的rt_object的起始地址。这样我们就可以方便的使用指针统一访问各对象,而不管该对象是什么类型。

下面这条语句访问某内核对象内嵌的rt_object对象中的list成员,而不管该对象是什么类型:
((struct rt_object *)(&some_kernel_obj))->list;


初步了解内核对象后,我们来看一个操作系统最基础的设施:线程和线程调度。
线程对象由struct rt_thread描述,定义于rtdef.h中。这里就不再将该结构体列出,直接分析其成员。作用比较明显的成员不再一一分析,仅分析比较关键的几个成员。


开头的4个成员(name, type, flags, list)实际上就是rt_object结构的成员。绝大多数内核对象(rt_sem)在其头部嵌入一个公共的rt_object结构,唯有rt_thread将这四个成员复制过来,应该是出于效率方面的考虑。


接下来的tlist成员也是一个链表项,根据线程状态的不同,将利用该表项将线程对象挂到不同的链表中去。例如,如果线程处于ready状态,就将
通过tlist将该线程挂到ready线程链表;如果线程处于suspend状态,就通过tlist将线程挂到suspend线程链表。


current_priorityinit_priority
init_priority就是你创建线程时为其指定的优先级。一般情况下这两个值相等。但RTT允许你动态改变线程的优先级,如果你这么做了,那么这两个值是不相等的。


numberhigh_masknumber_mask
这三个成员用于快速查找当前最高优先级的线程。后面我们分析线程调度时再回到这三个成员上来。


event_setevent_info
用于进程间的IPC。在IPC相关代码中再详细分析其作用。


init_tickremaining_tick
RTT允许多个线程使用同一优先级,在同一优先级下的线程使用时间片调度。init_tick就是分配给该线程的时间片。当某个优先级的线程刚被选中进入运行态时,remaining_tick将被赋予init_tick的值,并随着线程的执行而递减。当remaining_tick递减到0,表明该线程的时间片用完,同一优先级的下一个就绪线程将被选中进入运行态。


thread_timer
如果你在线程内调用sleep,或者在等待资源时指定了超时,RTT将使用thread_timer计算超时时间。

相关帖子

沙发
原野之狼| | 2012-12-9 00:13 | 只看该作者
rtt是个好东西

使用特权

评论回复
板凳
njchenmin| | 2012-12-9 06:29 | 只看该作者
紧跟学习。

使用特权

评论回复
地板
yuanxiaote| | 2012-12-16 22:51 | 只看该作者
必须的,马上开始用它,^_^。

使用特权

评论回复
5
wudonghua| | 2012-12-26 10:29 | 只看该作者
有机会用用

使用特权

评论回复
6
lhchen922| | 2013-11-17 20:14 | 只看该作者
RTT不错。。

使用特权

评论回复
7
楚地潮人| | 2014-1-13 08:47 | 只看该作者
“这是一款由国内RT-Thread工作室开发的开源实时操作系统。”RTT到底是不是国人们自己的操作系统呢?急于求知。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

37

主题

296

帖子

0

粉丝