你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【RT-Thread内核实现与应用开发实战指南】读书笔记

[复制链接]
永不停息 发布时间:2018-12-24 23:34
本帖最后由 永不停息 于 2018-12-25 09:34 编辑
' s. K7 \9 \1 \/ m. b0 {) v1 N+ ]1 o0 p
【RT-Thread内核实现与应用开发实战指南】本书总共分为两个部分,第一部分主要剖析 RT-Thread 内核的实现机理,通过代码从操作系统最基本的线程创建和线程切换开始,一步一步增加代码功能(线程阻塞、时间片、优先级、临界区等)/ Q! N1 c4 e; y, U- d% T
由浅入深从开发者的角度教读者怎么从零实现基本的操作系统内核。虽然内容不是很细致,但是能够帮助读者抓住重点,
4 u" T+ [# X- I让读者能够最快速的了解操作系统的核心,读完这部分然后再去阅读源码会比直接阅读源码事半功倍。第二部分内容着重( h8 n+ A. D# t; P( I& s1 s
RT-Thread 的应用,分别介绍操作系统各种机制(信号量、互斥量、时间、邮箱等)的工作机理以及相关的接口函数,读者# \$ Z1 H8 L* ?# v$ O( i: _
可以通过这部分去熟悉 RT-Thread 的应用。
4 Z! N- y: I1 o* m& k4 i6 r, K/ E2 J( T' F( k
由于本人之前对一些操作系统(FreeRTOS)也有所学习和应用,但是没有深入去学习源码,对于操作系统内核的实现机制
; o0 ~9 ~# |9 B  a并不是很了解,因此这次也将学习重点放在第一部分,下面针对第一部分的线程创建和切换这部分进行总结。& X+ U4 q; i( p; D- i& l

/ A8 F" @: x9 v6 j. b! _% w6 H6 _对于操作系统而言,线程是最基本的概念,什么是线程呢?线程是程序执行的最小单元,每个线程都拥有独立的栈空间
6 f8 j2 D6 s+ W* M! \1 N+ w,是系统调度的基本单元。操作系统最核心的地方也在于线程的调度,系统为了方便线程调度,为每个线程都额外定义了3 {: s$ B% P5 I! s" M# ]" w
线程控制块,线程控制块的定义如下:
. d9 U/ e( ^! L
  1. /**
    " X8 @5 ]) E  O, U; N
  2. * Thread structure! T. r1 h, L3 [* A5 T: s
  3. */; x0 b- a* G+ b- ~
  4. struct rt_thread1 e) O* X6 Q/ V) X: l
  5. {9 K* W; K/ K# g4 }+ H
  6.     /* rt object */5 N1 B" S9 Y- I1 S$ |5 T% s
  7.     char        name[RT_NAME_MAX];                      /**< the name of thread */& B9 |+ a# M' v, q. @
  8.     rt_uint8_t  type;                                   /**< type of object */) l4 D, ^6 {% r
  9.     rt_uint8_t  flags;                                  /**< thread's flags */
    + e( U, F- t4 a: Q$ m

  10. " g" v/ z8 m3 a
  11.     rt_list_t   list;                                   /**< the object list */' i6 O9 s+ D( D7 R0 u: G7 S
  12.     rt_list_t   tlist;                                  /**< the thread list */% A' t/ M1 i: _* x9 P2 f" j4 N
  13. 0 `0 D4 Y0 K6 ~) F: M' z, ]8 ^
  14.     /* stack point and entry */
    . m9 _, k" j% s1 h0 b' H
  15.     void       *sp;                                     /**< stack point */$ G& p: B" U( K* Q$ Y9 U; a
  16.     void       *entry;                                  /**< entry */
    ' Y- J* K+ s$ Z2 M; o0 R
  17.     void       *parameter;                              /**< parameter */
    9 s8 O: [4 a4 c* k# T2 |
  18.     void       *stack_addr;                             /**< stack address */6 O9 a; E  `1 k' Y
  19.     rt_uint32_t stack_size;                             /**< stack size */: e: t# O8 a4 G6 ^6 K

  20. $ ~5 U* Y! C  `; x5 i7 V7 @9 o
  21.     /* error code */
    ! o0 n- o4 k: n( }5 g3 ~
  22.     rt_err_t    error;                                  /**< error code */) B1 c& C. J$ }, t, ~& i4 x
  23. 3 X$ A! {, s7 T# O! J# @1 o
  24.     rt_uint8_t  stat;                                   /**< thread status */
    8 V$ }! `+ X" X2 v4 U
  25. ! n# @( ^5 A# Q3 @1 T/ b
  26.     /* priority */
    5 ?& m* p( s6 \- g7 H' @3 t
  27.     rt_uint8_t  current_priority;                       /**< current priority */
    . n! d8 r4 g; D/ \9 X
  28.     rt_uint8_t  init_priority;                          /**< initialized priority */
复制代码
其中 tlist 成员是线程的链表节点,后面要把线程插入到各种双向链表中便是通过该链表节点实现,该链表节点定义如下:1 ~( E) O/ o7 A9 p  |
  1. struct rt_list_node
    , g5 U# m+ X, i$ |& y- D& e- h0 d- |- u
  2. {. ~7 s% T" L1 ]$ P2 ]
  3.     struct rt_list_node *next;                          /**< point to next node. */% f! e% v4 ]+ N! W0 Z
  4.     struct rt_list_node *prev;                          /**< point to prev node. */
    5 i8 b& U1 V! T, F0 u
  5. };
    ! p5 \. }/ b2 F" d* l5 ]% \
  6. typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */
复制代码
线程初始化通过函数 rt_thread_init(struct rt_thread *thread) 实现,主要进行线程控制块相关成员的初始化以及初始化线程栈
& \2 m3 D/ g6 a4 T具体实现如下所示:
5 N  Y- T( ?5 ~
  1. static rt_err_t _rt_thread_init(struct rt_thread *thread,& ^" x. ~8 `7 a; `
  2.                                 const char       *name,% n1 q" D* F+ M; g$ P* q6 C( M
  3.                                 void (*entry)(void *parameter),3 L  ]! k7 K4 R- s
  4.                                 void             *parameter,
      h# L: P3 x1 L8 i4 l
  5.                                 void             *stack_start,8 r6 m9 Y% \! r" P
  6.                                 rt_uint32_t       stack_size,
    , ~5 l6 f* G0 S% Q9 t
  7.                                 rt_uint8_t        priority,6 w4 ?% W3 F* A
  8.                                 rt_uint32_t       tick)$ A# U: ]( G6 d4 f1 ~6 M* I9 C2 v
  9. {
    2 Z6 o2 a) `" J5 V4 @1 F% ~5 w
  10.     /* init thread list */
    & I* ~; T  P3 t8 x- K2 b
  11.     rt_list_init(&(thread->tlist));
    7 G5 g/ @7 e0 r/ y
  12. 0 A/ [. m/ N& l! Y$ x
  13.     thread->entry = (void *)entry;% k0 Z  S1 g' z+ V- y& W4 _
  14.     thread->parameter = parameter;' E4 e' a  X) C# [% |

  15. 8 I. P. n* Q; U, H
  16.     /* stack init */
    $ T2 v" U7 ?5 l4 [( T- p
  17.     thread->stack_addr = stack_start;
    4 H9 ]& X/ r% g0 j+ @  X! u1 i
  18.     thread->stack_size = stack_size;6 _/ l/ `+ W" S
  19. 1 b/ a0 X& g% H4 X1 b
  20.     /* init thread stack */
    - J2 D# T( y  y. Y$ S+ N6 l5 @  P( Y
  21.     rt_memset(thread->stack_addr, '#', thread->stack_size);
    5 @# h2 K! _" L9 G9 `
  22.     thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,- Q( {$ c' J" J0 ^! L  T
  23.                                           (void *)((char *)thread->stack_addr + thread->stack_size - 4),
    . O; V$ j' R# L5 o5 Y0 j& j
  24.                                           (void *)rt_thread_exit);% F* y* p4 t, ^+ s9 N0 J8 l6 h+ r0 \

  25. ! d& b( J* N' |. d) ^. o
  26.     /* priority init */" G& {1 R7 A. E. e: ]
  27.     RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
    7 G: z2 F% y# @" L7 S; C" l. n
  28.     thread->init_priority    = priority;4 ]2 q  s' {3 G, x6 Y# m, l
  29.     thread->current_priority = priority;
    + `  _0 n' [3 u% z- x

  30. + F; ?; R4 `) A
  31.     thread->number_mask = 0;
    9 X( w3 N$ {5 d! A1 z

  32. 3 ~: l4 e0 }% G6 N' m6 H
  33.     /* tick init */$ X" |" w8 Q& N  O( J
  34.     thread->init_tick      = tick;
    5 O+ m7 x/ T/ G: m, G0 \7 d
  35.     thread->remaining_tick = tick;+ F! H/ f( f' d9 D
  36. - @# ]5 o6 }4 ~* l1 A4 m
  37.     /* error and flags */
      B) I" x5 w# y2 z" `
  38.     thread->error = RT_EOK;6 C! d5 F8 b+ n2 r8 o3 n
  39.     thread->stat  = RT_THREAD_INIT;) U# K2 f3 _4 h7 z# ]
  40. . E; o/ g2 h8 }0 Q8 b) a; Q! b
  41.     /* initialize cleanup function and user data */
      {& Z$ z0 G" D8 s
  42.     thread->cleanup   = 0;8 c- x4 q5 E6 A  [6 m) e8 ^
  43.     thread->user_data = 0;
    ( E& A( l: \  L, @/ R

  44. $ i' d! P; a2 v) n8 X& ^1 {# \: M  g7 w! i
  45.     /* init thread timer */
    . S. ?1 C0 D" L9 M7 I9 `3 E( @9 [* z
  46.     rt_timer_init(&(thread->thread_timer),
    ( E5 [7 K2 B1 d9 e
  47.                   thread->name," W6 A8 @; ]5 e# ^" I1 C* G
  48.                   rt_thread_timeout,/ Z4 e+ i; T) b
  49.                   thread,7 u3 A/ L5 t; ~6 q" ^% }1 r
  50.                   0,
      ^# X* N9 r6 Z$ u# e
  51.                   RT_TIMER_FLAG_ONE_SHOT);1 D$ n" ]& y! @  X5 Z& h2 g

  52. 7 b# M5 M4 A9 {
  53.     RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));2 s) z( b' l, T2 b$ D

  54. ! u( M' }: R  w9 |% }- K
  55.     return RT_EOK;- ?2 w; r* M  {- x5 N
  56. }
复制代码
从上面的函数中可以看出线程栈的初始化由函数 rt_hw_stack_init() 来完成,每个线程的栈由三部分组成:自动加载到 CPU 寄存器的部分、手动加载到 CPU 寄存器的部分以及空闲栈。如下图所示:7 c+ F5 G- L2 V1 W8 g; J3 r+ x
1.jpg 3 k! X3 ~0 N1 e% [
初始化后除了空闲栈部分其他值都变成 0xdeadbeef,线程第一次运行时,自动加载到 CPU 部分的内容要预先设置好,
( H# O3 ~7 Z# N4 l# G' E$ ^包括 PC 指针、R0任务形参,其它设置为 0。
: a$ y3 j) P0 k1 t9 U1 H线程初始化后要插入到就绪列表中,通过函数 rt_list_insert_before() 实现,最后要运行线程则需要启动调度器,
- X3 ?1 ?; T' d  o6 `启用调度器通过函数 rt_system_scheduler_start() 实现,具体函数实现如下:4 a0 D1 F) R& @$ b* h& |
  1. <blockquote>void rt_system_scheduler_start(void)
复制代码
函数中 rt_hw_context_switch_to() 用于启动第一次线程切换,该函数通过触发 PendSV 中断来实现上下文切换,后面的
$ N4 L0 t. O+ _1 h上下文切换则通过函数 rt_hw_context_switch() 实现。最后系统调度通过 rt_scheduer() 函数实现,其核心内容也是通过
. J- h2 H* {& D. @% F' ^获取下一个要执行的线程然后产生上下文切换,在此不详细说明。
7 v1 ?- H  v" k/ F: B* ?, j6 s( x0 ]6 Y' X0 \& |: ]  W
' P+ ?+ I% q* T8 t4 ]3 @7 D# h
第一次分享帖子,写得不好多多见谅。帖子内容有限,只是说明一下我个人对于其中的一点理解,各位有兴趣的还是得亲
1 l8 n8 m2 K7 j' Q% i; }自去看书,个人觉得书是挺好的,由浅入深,循序渐进,但是看完书后最重要的还是得多实践,要想深入内核原理的还得
3 d' t6 I% s. Y- I+ @2 \慢慢啃源码。
, a. W$ L, X" i- E0 i9 X4 Y- M
# w; d, n* r: m) q0 F, K/ [
赞 收藏 评论0 发布时间:2018-12-24 23:34

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版