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

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

[复制链接]
永不停息 发布时间:2018-12-24 23:34
本帖最后由 永不停息 于 2018-12-25 09:34 编辑 ! L, h; \$ [- }+ ^5 D

, i5 W8 x; A- z8 R* K【RT-Thread内核实现与应用开发实战指南】本书总共分为两个部分,第一部分主要剖析 RT-Thread 内核的实现机理,通过代码从操作系统最基本的线程创建和线程切换开始,一步一步增加代码功能(线程阻塞、时间片、优先级、临界区等)
9 f( K$ ?. Z6 B由浅入深从开发者的角度教读者怎么从零实现基本的操作系统内核。虽然内容不是很细致,但是能够帮助读者抓住重点,
1 S# `/ N" j  ~! x6 `1 D9 p让读者能够最快速的了解操作系统的核心,读完这部分然后再去阅读源码会比直接阅读源码事半功倍。第二部分内容着重/ G% X. B  n" z; Z, a
RT-Thread 的应用,分别介绍操作系统各种机制(信号量、互斥量、时间、邮箱等)的工作机理以及相关的接口函数,读者3 d- w1 n* p2 t; D1 X& v, Z
可以通过这部分去熟悉 RT-Thread 的应用。/ R. U$ ~1 v, Y" O9 ~* `2 N2 m
, r: Z3 s% @4 R" X' I' ~
由于本人之前对一些操作系统(FreeRTOS)也有所学习和应用,但是没有深入去学习源码,对于操作系统内核的实现机制( s, ?6 [* c; i- Q+ t; k
并不是很了解,因此这次也将学习重点放在第一部分,下面针对第一部分的线程创建和切换这部分进行总结。
5 M$ G7 F5 r( R( E( d" {, K' e8 T" N
对于操作系统而言,线程是最基本的概念,什么是线程呢?线程是程序执行的最小单元,每个线程都拥有独立的栈空间
7 C6 ^) Z; q8 z,是系统调度的基本单元。操作系统最核心的地方也在于线程的调度,系统为了方便线程调度,为每个线程都额外定义了
' B' J0 @4 W$ r2 f7 [线程控制块,线程控制块的定义如下:
" D* k& m: a9 A' t4 h: m( \- i
  1. /**; q  _0 M% `: v3 g
  2. * Thread structure
    & l- p7 @& {+ i5 f
  3. */1 ~. B; M- c' r% l/ z) f9 K* P( e
  4. struct rt_thread
    & a% W2 G4 N6 G; U* v. n& {9 @2 H! s
  5. {) T" p3 V4 V" d2 G, i; A
  6.     /* rt object */  B% O7 M0 P- L. T
  7.     char        name[RT_NAME_MAX];                      /**< the name of thread */# W) I: Z5 G4 ?$ v; h- H
  8.     rt_uint8_t  type;                                   /**< type of object */0 R' a/ z4 b: P0 v# G
  9.     rt_uint8_t  flags;                                  /**< thread's flags */- l( ?3 `" Q: O7 X6 V
  10. # M. w' P" c% A$ g* A: U
  11.     rt_list_t   list;                                   /**< the object list */
    8 o9 W1 N6 B6 W
  12.     rt_list_t   tlist;                                  /**< the thread list */
    . C* d, M+ o% X2 k+ ?
  13. ; A, k0 o& B+ J# O, C1 A9 M$ k
  14.     /* stack point and entry */
    - [  ~5 K2 O; O7 {- p
  15.     void       *sp;                                     /**< stack point */
    ( ]) u: j& k* [
  16.     void       *entry;                                  /**< entry */( g5 Q3 a% M. _- u, l& w0 z3 ]
  17.     void       *parameter;                              /**< parameter */
    8 l: J: m+ N# }* L  s  F. B
  18.     void       *stack_addr;                             /**< stack address */
    2 }) ^  Z+ I7 I2 k
  19.     rt_uint32_t stack_size;                             /**< stack size */
    3 Y1 {. m! m+ ~1 r6 Q

  20. 7 P4 o! J$ K5 J9 o3 w# s3 B- }
  21.     /* error code */
    9 Z0 K, B7 Z7 g0 `1 a- r
  22.     rt_err_t    error;                                  /**< error code */
    7 X6 t0 Y7 L! v$ f
  23. ; l7 E# [% u: ?- K$ `- l
  24.     rt_uint8_t  stat;                                   /**< thread status */
    4 ~1 B8 \& F; v+ W0 `, E

  25. 2 \" B( E( q- p- R( d" [3 C$ O
  26.     /* priority */4 P, T" m' {) A4 X
  27.     rt_uint8_t  current_priority;                       /**< current priority */2 O9 l7 B9 P4 V  L0 e: R/ q
  28.     rt_uint8_t  init_priority;                          /**< initialized priority */
复制代码
其中 tlist 成员是线程的链表节点,后面要把线程插入到各种双向链表中便是通过该链表节点实现,该链表节点定义如下:) U0 {3 u: P0 h
  1. struct rt_list_node& U' }% Q" U0 R% \3 k1 A
  2. {) w  d" C! l* Q- w) l4 Q% k
  3.     struct rt_list_node *next;                          /**< point to next node. */
    3 q3 F; s2 J! R2 z4 w
  4.     struct rt_list_node *prev;                          /**< point to prev node. */3 J% A( o+ C! ?6 h; k$ l
  5. };& K0 q1 a1 r) K: D! _
  6. typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */
复制代码
线程初始化通过函数 rt_thread_init(struct rt_thread *thread) 实现,主要进行线程控制块相关成员的初始化以及初始化线程栈$ o1 F4 Q# B/ [" J
具体实现如下所示:) S( y# u* u( t/ l+ y  V
  1. static rt_err_t _rt_thread_init(struct rt_thread *thread,' |! X: c: C: y) F, _
  2.                                 const char       *name,# z3 }/ r) X' v2 w$ ?" h9 V+ S0 J
  3.                                 void (*entry)(void *parameter),/ i* F& e7 O! g
  4.                                 void             *parameter,
    * ^. ~9 I: r( z5 X% V6 B4 P
  5.                                 void             *stack_start,
      U' K) E& Z/ q$ b! o3 Q7 M
  6.                                 rt_uint32_t       stack_size,3 K+ t8 P" r0 C1 I, ^1 S6 z8 n' g
  7.                                 rt_uint8_t        priority,
    $ ?9 z- w) v6 ?# C: W
  8.                                 rt_uint32_t       tick)
    2 J( E* I% f4 M% q# W7 k. z' S
  9. {
    ! ]0 }) \1 ~# `; E
  10.     /* init thread list */
    0 F1 D& f/ s' A" V& c; C/ i$ Q2 |
  11.     rt_list_init(&(thread->tlist));2 S, O7 O+ p/ _; X

  12. 7 x5 Z& K4 L7 D7 N0 o7 a% |8 j
  13.     thread->entry = (void *)entry;, x3 l3 ~9 D4 C! D/ M) Y' _! C, U
  14.     thread->parameter = parameter;' z- ~" S3 |2 U5 n
  15. & Q5 d. c2 I0 G; p+ h
  16.     /* stack init */7 W/ y) e. ~" e. Y: i' Q0 G
  17.     thread->stack_addr = stack_start;, \: u6 M; p% \% n- R/ z! K
  18.     thread->stack_size = stack_size;* x5 g4 _7 Z) Y, B- b% ?; _1 e

  19. & u8 q& ~+ z( _& c) z& T1 l
  20.     /* init thread stack */
    9 V! T! J: w7 P* g  Z) ?$ s3 o
  21.     rt_memset(thread->stack_addr, '#', thread->stack_size);- P5 `6 x7 C+ i  u) {
  22.     thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
    . O% T7 [2 W6 f5 G1 Q. s- e
  23.                                           (void *)((char *)thread->stack_addr + thread->stack_size - 4),
    1 W: d8 _3 Y  |* f7 L& m3 u5 p
  24.                                           (void *)rt_thread_exit);. z8 U8 a7 E% u) F( @# u
  25. ; D2 c% F" R6 d. f
  26.     /* priority init */
    * L  K/ x4 B# D, Y' o/ [: p
  27.     RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
    3 q  g3 O* f' Z: e" O$ N
  28.     thread->init_priority    = priority;
    0 {* c8 Q; @  C+ l7 T
  29.     thread->current_priority = priority;" R" E! B2 c. c. J! q1 k! E0 N# [

  30. ! C5 D- K: [& ~/ c4 `. U, e- z' p
  31.     thread->number_mask = 0;; H4 I/ S& T4 o& t* I  B
  32. . ^8 e/ B7 p2 D; U% B
  33.     /* tick init */
    6 k3 n) Z6 W- g/ I3 s, }2 t5 B
  34.     thread->init_tick      = tick;
    : g( w4 |1 J# \
  35.     thread->remaining_tick = tick;
    $ y. L. [$ L& T& H+ N/ R
  36. ( Y% U: H2 m; b2 Y$ I
  37.     /* error and flags */
    ! Z6 l2 }1 I* u# F
  38.     thread->error = RT_EOK;0 T, g* O' `% \7 H* L
  39.     thread->stat  = RT_THREAD_INIT;
    + X3 {! j+ A9 _6 W4 N- f

  40. 4 r% h, F" u6 ]) _, m) H# L
  41.     /* initialize cleanup function and user data */7 `$ ^/ }8 n( E- F) s( U# }! m) t
  42.     thread->cleanup   = 0;
      S. ?: X* l$ e6 k. ~
  43.     thread->user_data = 0;; \2 {$ B% ~8 }: S

  44. 4 p: H: m  H8 I2 T# m1 [" x
  45.     /* init thread timer */1 @  |$ x, B1 F" Q$ V
  46.     rt_timer_init(&(thread->thread_timer),3 v4 H7 x, c6 \9 ^1 {: y
  47.                   thread->name,
    / v5 J5 d. Q! u  C5 E2 c
  48.                   rt_thread_timeout," s+ G  W% p2 j$ N' `( [
  49.                   thread,
    9 W" g# ?  q3 }
  50.                   0,
    4 X+ X" j7 r1 g  r
  51.                   RT_TIMER_FLAG_ONE_SHOT);
    ( ?; P9 X- a* R# G) I; ]  P. b

  52. : w. v% \+ o7 o% `
  53.     RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));$ W7 l' O3 m& @6 Z; P2 I

  54. 4 F0 {' Y/ K; Z4 b, g
  55.     return RT_EOK;- g, W; ]' c# `. n8 |7 e# [9 e
  56. }
复制代码
从上面的函数中可以看出线程栈的初始化由函数 rt_hw_stack_init() 来完成,每个线程的栈由三部分组成:自动加载到 CPU 寄存器的部分、手动加载到 CPU 寄存器的部分以及空闲栈。如下图所示:
, M$ a* K" y" P, W! n5 L# n 1.jpg
! t( G* o& u) L6 i/ f  q初始化后除了空闲栈部分其他值都变成 0xdeadbeef,线程第一次运行时,自动加载到 CPU 部分的内容要预先设置好,
/ V! ]) u  i, O+ h包括 PC 指针、R0任务形参,其它设置为 0。/ ~7 [2 i- ]2 U. X' [
线程初始化后要插入到就绪列表中,通过函数 rt_list_insert_before() 实现,最后要运行线程则需要启动调度器,
% V+ |$ f9 I# O3 x- t3 u" g7 X1 |. R启用调度器通过函数 rt_system_scheduler_start() 实现,具体函数实现如下:
9 O7 @+ k1 [: H/ J$ W3 j) i
  1. <blockquote>void rt_system_scheduler_start(void)
复制代码
函数中 rt_hw_context_switch_to() 用于启动第一次线程切换,该函数通过触发 PendSV 中断来实现上下文切换,后面的" g1 T' |6 F1 v, {9 _3 b% s! d
上下文切换则通过函数 rt_hw_context_switch() 实现。最后系统调度通过 rt_scheduer() 函数实现,其核心内容也是通过
& O- Q7 ?: u( C2 g" V: L3 i获取下一个要执行的线程然后产生上下文切换,在此不详细说明。2 ?( a2 p' H, F5 D/ Z4 H7 A6 W
% S: B- C- Q; c! ]* Z. d- |* {4 R2 V
- {$ R8 d% j( _1 A  l% F
第一次分享帖子,写得不好多多见谅。帖子内容有限,只是说明一下我个人对于其中的一点理解,各位有兴趣的还是得亲/ b+ D; W$ g* _$ u( O
自去看书,个人觉得书是挺好的,由浅入深,循序渐进,但是看完书后最重要的还是得多实践,要想深入内核原理的还得
2 c& A( `$ C/ d/ ?慢慢啃源码。% e  p/ ?" {; L0 A
7 G$ m6 P; o, {. n; Q6 y* o
收藏 评论0 发布时间:2018-12-24 23:34

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版