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

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

[复制链接]
永不停息 发布时间:2018-12-24 23:34
本帖最后由 永不停息 于 2018-12-25 09:34 编辑 ! j5 I/ p# Q5 G$ o5 f

% m/ Y' g- h) i  h; m3 Y【RT-Thread内核实现与应用开发实战指南】本书总共分为两个部分,第一部分主要剖析 RT-Thread 内核的实现机理,通过代码从操作系统最基本的线程创建和线程切换开始,一步一步增加代码功能(线程阻塞、时间片、优先级、临界区等)
; F9 e* ^, e8 q由浅入深从开发者的角度教读者怎么从零实现基本的操作系统内核。虽然内容不是很细致,但是能够帮助读者抓住重点,9 @, X' ^3 q- |6 d3 I/ |
让读者能够最快速的了解操作系统的核心,读完这部分然后再去阅读源码会比直接阅读源码事半功倍。第二部分内容着重
3 `+ S4 C" |' L6 z) n! `RT-Thread 的应用,分别介绍操作系统各种机制(信号量、互斥量、时间、邮箱等)的工作机理以及相关的接口函数,读者
: ]1 _- v% V  s可以通过这部分去熟悉 RT-Thread 的应用。. A% D( F# S0 ^0 k" e% K
) k9 W/ o: l- L8 @0 ?- g' P3 V
由于本人之前对一些操作系统(FreeRTOS)也有所学习和应用,但是没有深入去学习源码,对于操作系统内核的实现机制
8 n; m+ c" Z5 E# f9 A  u2 ^/ \" t并不是很了解,因此这次也将学习重点放在第一部分,下面针对第一部分的线程创建和切换这部分进行总结。
: G' c% j! ], v2 y8 f! e& Y0 _/ x7 Q2 p
对于操作系统而言,线程是最基本的概念,什么是线程呢?线程是程序执行的最小单元,每个线程都拥有独立的栈空间
7 T4 R. {" D4 K, m' C2 L,是系统调度的基本单元。操作系统最核心的地方也在于线程的调度,系统为了方便线程调度,为每个线程都额外定义了# v/ X! ^' p% Q0 v4 c  D
线程控制块,线程控制块的定义如下:
5 I4 _# a6 y6 ]& V+ g0 d) D
  1. /**' I& q/ ?" A) o
  2. * Thread structure
    7 I- B) C& J" ~9 A1 ]
  3. *// c6 J- Z% O4 l7 U0 x5 n
  4. struct rt_thread( J" I' H  ?& t: o: G
  5. {
    ' {& r* k  Z  }2 C2 b
  6.     /* rt object */
    4 P" M8 j' \( t: o5 J6 A, S; n
  7.     char        name[RT_NAME_MAX];                      /**< the name of thread */
    1 x5 X$ {5 ]7 ^. f  I+ D
  8.     rt_uint8_t  type;                                   /**< type of object */
    & W# W: x5 `" A* K( Z. j
  9.     rt_uint8_t  flags;                                  /**< thread's flags */
    ; i% A6 ~( K# S

  10. , C. }# f2 K6 C' k4 ]2 d5 ~
  11.     rt_list_t   list;                                   /**< the object list */
    ! `3 a9 V$ l/ X" @9 l% ^
  12.     rt_list_t   tlist;                                  /**< the thread list */; c4 |" T) ~. F1 O3 c9 J4 ]8 b
  13. 6 U% a) \  x3 H3 Q1 J& H7 X
  14.     /* stack point and entry */! y2 z; d6 Q: a, v3 `* B
  15.     void       *sp;                                     /**< stack point */
    ) r3 h! D/ _' S$ n1 c
  16.     void       *entry;                                  /**< entry */+ S- _& O2 F5 ~/ @  Z( Y
  17.     void       *parameter;                              /**< parameter */! V- |; N( i2 k$ t) W9 i# q
  18.     void       *stack_addr;                             /**< stack address */
    ! P& N$ F# K- c) ?* ^' l
  19.     rt_uint32_t stack_size;                             /**< stack size */( K1 [3 @0 y6 c/ _/ }

  20. 9 t4 w& O! U- T4 r
  21.     /* error code */
    . y, c1 I/ o* P# h& @' q! O4 h) @
  22.     rt_err_t    error;                                  /**< error code */! J2 Z/ D# j: o% ]8 e6 S
  23. + p9 s+ Q# ]" V( q
  24.     rt_uint8_t  stat;                                   /**< thread status */0 l1 h2 D- S2 U: r

  25. " [6 B$ B" }" c# U# C
  26.     /* priority */
    * ]9 R% h) f5 b0 A# ]
  27.     rt_uint8_t  current_priority;                       /**< current priority */  \: e9 `3 y# a# q3 w" D3 a' v( a- Y
  28.     rt_uint8_t  init_priority;                          /**< initialized priority */
复制代码
其中 tlist 成员是线程的链表节点,后面要把线程插入到各种双向链表中便是通过该链表节点实现,该链表节点定义如下:* S- l5 G$ g2 H: l. S; m
  1. struct rt_list_node
    0 T  ]. \7 ^. ?
  2. {
    : S* l$ |+ i% l9 A9 m/ e2 _
  3.     struct rt_list_node *next;                          /**< point to next node. */3 o1 j' ]. p$ o  `
  4.     struct rt_list_node *prev;                          /**< point to prev node. */
    . s0 M) c+ E9 l, i# ~, l
  5. };
    ! n9 T- @3 {. [5 R
  6. typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */
复制代码
线程初始化通过函数 rt_thread_init(struct rt_thread *thread) 实现,主要进行线程控制块相关成员的初始化以及初始化线程栈
4 R1 ?6 |" l  {9 z具体实现如下所示:& B/ P) z6 N2 m; X
  1. static rt_err_t _rt_thread_init(struct rt_thread *thread,
    / C1 m* ~  r6 k3 K8 m; V, ?
  2.                                 const char       *name,. o) ]& V9 d* W: r' d& ?
  3.                                 void (*entry)(void *parameter),
    1 S& }' t" |" I
  4.                                 void             *parameter,
    4 U8 E! w# _1 k; X, {; z
  5.                                 void             *stack_start,* ~5 q6 D: h+ u1 m
  6.                                 rt_uint32_t       stack_size,% x7 d$ x8 l  x( y4 w' G
  7.                                 rt_uint8_t        priority,
    " S( f$ R6 J; G( y: J
  8.                                 rt_uint32_t       tick)
    7 q5 S' g+ U. O% I- }) T+ @
  9. {
    1 v; E8 D) s1 o2 I8 x' H# k2 a
  10.     /* init thread list */
    ; M" V; e7 x% O/ ^+ `
  11.     rt_list_init(&(thread->tlist));( M! v* N' M% F9 T8 \  r

  12.   H! B2 Q. O" K) T# M% {6 `
  13.     thread->entry = (void *)entry;
    , K' R3 n/ i2 Y$ v5 E
  14.     thread->parameter = parameter;
    6 z3 b! Z" l6 v) u( m

  15. 2 U$ F& |- B3 O3 G, o) {
  16.     /* stack init */
    & ^$ p2 v  G' @/ \, p: \9 d
  17.     thread->stack_addr = stack_start;1 s7 m; M' j3 C* ^
  18.     thread->stack_size = stack_size;
    . H! j- j! M; u; e

  19. / K% K, T# t7 b' D0 U4 v$ q
  20.     /* init thread stack */5 Q, C7 g2 c% |* x. U( A
  21.     rt_memset(thread->stack_addr, '#', thread->stack_size);
    " w2 v2 y# }$ W1 t" Y7 _
  22.     thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
    8 ^1 R( |8 S% h: ?- \% b
  23.                                           (void *)((char *)thread->stack_addr + thread->stack_size - 4),
    4 t, \8 d4 r/ e( m2 L4 |
  24.                                           (void *)rt_thread_exit);
    / ~( W7 o$ m% ~/ H) r/ O
  25. 2 p, j! ^5 p2 x$ ?; I$ }
  26.     /* priority init */
    ; ?: e  _; q: m6 n, y
  27.     RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);! A/ \0 D6 W5 t. M/ ^/ {
  28.     thread->init_priority    = priority;: E) v9 O, A5 o+ x$ p
  29.     thread->current_priority = priority;
    ; [4 \/ E+ m6 q- S. ~& g9 a
  30. # z* M9 k# j- E5 b
  31.     thread->number_mask = 0;1 a" \- l$ O. k4 U, U; _  ]
  32. $ Q1 z8 ~; r8 b( U% l8 T
  33.     /* tick init */
    ! h: P6 i, _. p, r  Q
  34.     thread->init_tick      = tick;
    ( `& ]* R: u' {/ \# k/ K3 o+ l; e
  35.     thread->remaining_tick = tick;
    ' R9 g4 v3 s- R- U: b. D8 c
  36. * M9 ?5 @: ]" q7 a! Y; W
  37.     /* error and flags */( l: n; w% S7 D+ h. \1 s7 {
  38.     thread->error = RT_EOK;1 r/ R- W' M) _! `
  39.     thread->stat  = RT_THREAD_INIT;
    6 T" t2 _) ?0 C$ V5 p: |0 q# s

  40. - H/ d# E, u/ l  n
  41.     /* initialize cleanup function and user data */* H7 D4 s( x' g
  42.     thread->cleanup   = 0;
    ! q$ _, x8 |1 Q4 y+ P; q+ V
  43.     thread->user_data = 0;9 n8 q" J8 I. q+ g; ^( V
  44. 2 _0 w' b' ?, @2 w& p3 X
  45.     /* init thread timer */
    & k6 Z# z. b. |3 [9 I: X
  46.     rt_timer_init(&(thread->thread_timer),
    $ I' g! u  l5 u# N2 V
  47.                   thread->name,
    7 [) q. m% ]9 Q/ ?5 U% Y
  48.                   rt_thread_timeout,2 A  ~' M/ B" h/ h5 I) d$ q
  49.                   thread,
    3 b; I% {4 j# D9 |* x" O5 c
  50.                   0,
    0 R, Z! t0 d- U
  51.                   RT_TIMER_FLAG_ONE_SHOT);
    : }  p3 r  U2 U/ y# ~* K3 W
  52. 4 v" i! P& X  A& h6 |
  53.     RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));
    ) X9 O3 M7 d5 ?# e' o

  54. # N6 q' \" m2 z, V) A1 i
  55.     return RT_EOK;
    $ }& V( T+ s9 Y: G1 F' |  ~
  56. }
复制代码
从上面的函数中可以看出线程栈的初始化由函数 rt_hw_stack_init() 来完成,每个线程的栈由三部分组成:自动加载到 CPU 寄存器的部分、手动加载到 CPU 寄存器的部分以及空闲栈。如下图所示:1 c- d2 q( q# I" H
1.jpg - Q- v; S/ O8 y; W- w2 g* r+ u
初始化后除了空闲栈部分其他值都变成 0xdeadbeef,线程第一次运行时,自动加载到 CPU 部分的内容要预先设置好,3 ^1 x! L7 l* l/ I) n# ?9 a
包括 PC 指针、R0任务形参,其它设置为 0。
8 f" y% ]' z/ B) J. n! R线程初始化后要插入到就绪列表中,通过函数 rt_list_insert_before() 实现,最后要运行线程则需要启动调度器,
; X+ X" I- k6 B启用调度器通过函数 rt_system_scheduler_start() 实现,具体函数实现如下:# a; j2 z* [2 g  J7 o. t! r
  1. <blockquote>void rt_system_scheduler_start(void)
复制代码
函数中 rt_hw_context_switch_to() 用于启动第一次线程切换,该函数通过触发 PendSV 中断来实现上下文切换,后面的
% O9 J0 }5 N7 R( J) x. h* B$ ?) n上下文切换则通过函数 rt_hw_context_switch() 实现。最后系统调度通过 rt_scheduer() 函数实现,其核心内容也是通过4 l( D* Z4 Z& m1 s
获取下一个要执行的线程然后产生上下文切换,在此不详细说明。
8 z. ], A& Q2 d; U- h- V' P: E, }$ K' P9 b6 Y8 v3 j4 y6 Q

$ M1 [' a1 Z/ S第一次分享帖子,写得不好多多见谅。帖子内容有限,只是说明一下我个人对于其中的一点理解,各位有兴趣的还是得亲
7 H- }% P; x3 F$ P0 }! q' f* G6 ^自去看书,个人觉得书是挺好的,由浅入深,循序渐进,但是看完书后最重要的还是得多实践,要想深入内核原理的还得
$ t; |, H+ [; ?慢慢啃源码。
+ n, o; V4 d; b: @0 W9 R# f0 {. l8 j
' w/ ^/ i) y& E% `+ n' V3 a
收藏 评论0 发布时间:2018-12-24 23:34

举报

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