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

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

[复制链接]
永不停息 发布时间:2018-12-24 23:34
本帖最后由 永不停息 于 2018-12-25 09:34 编辑 % f3 }" S: v8 z& p  }1 ~7 k1 U6 B/ I
7 G$ O* }- b1 Y$ ^) j. _3 L: U
【RT-Thread内核实现与应用开发实战指南】本书总共分为两个部分,第一部分主要剖析 RT-Thread 内核的实现机理,通过代码从操作系统最基本的线程创建和线程切换开始,一步一步增加代码功能(线程阻塞、时间片、优先级、临界区等)
# ?! M1 @+ F/ D  ?4 n; }由浅入深从开发者的角度教读者怎么从零实现基本的操作系统内核。虽然内容不是很细致,但是能够帮助读者抓住重点,
* |) N8 E% D0 T, S( Q# W让读者能够最快速的了解操作系统的核心,读完这部分然后再去阅读源码会比直接阅读源码事半功倍。第二部分内容着重' S9 O2 X+ D8 \3 @1 i/ P
RT-Thread 的应用,分别介绍操作系统各种机制(信号量、互斥量、时间、邮箱等)的工作机理以及相关的接口函数,读者% \4 }! d# B, T* i
可以通过这部分去熟悉 RT-Thread 的应用。
- q. ?. Y8 w' r+ S# E
* F( f- I+ f# U4 n% R/ Y, @由于本人之前对一些操作系统(FreeRTOS)也有所学习和应用,但是没有深入去学习源码,对于操作系统内核的实现机制4 n, h; }+ K8 ]  c3 |! E- C5 U
并不是很了解,因此这次也将学习重点放在第一部分,下面针对第一部分的线程创建和切换这部分进行总结。
( @- d+ J, j5 l% Z$ ~, G3 ?' k) n. |% i2 l1 e/ Z
对于操作系统而言,线程是最基本的概念,什么是线程呢?线程是程序执行的最小单元,每个线程都拥有独立的栈空间
# n9 d5 K# G. e,是系统调度的基本单元。操作系统最核心的地方也在于线程的调度,系统为了方便线程调度,为每个线程都额外定义了" T0 I" \, L6 y/ w% o0 ]
线程控制块,线程控制块的定义如下:( Q1 Q* a) C0 J7 v
  1. /**3 U% ?: F$ k5 C: i- r
  2. * Thread structure
    . T# |- B% w( Y0 J$ y1 V: _, n
  3. */& P: ~5 g! A" e; Z; E. f1 v
  4. struct rt_thread. N; X  q: p( K  s
  5. {
    ' b' {$ c+ h1 |
  6.     /* rt object */- w5 ~1 x" w% [* c% B5 a- E) s' E
  7.     char        name[RT_NAME_MAX];                      /**< the name of thread */
    0 n+ _& `, `: H1 d
  8.     rt_uint8_t  type;                                   /**< type of object */! K7 \# b/ b' L2 ?- c/ {
  9.     rt_uint8_t  flags;                                  /**< thread's flags */8 F0 r8 K6 g  x1 D1 D0 L: T5 x

  10. . r8 ~; n3 U1 V8 t0 l3 \
  11.     rt_list_t   list;                                   /**< the object list */2 o7 o; S  F5 J% i7 |
  12.     rt_list_t   tlist;                                  /**< the thread list */8 \2 ^7 f, ]1 Q3 g

  13. / O! [$ b/ w3 C0 @) D& _# @$ v& b
  14.     /* stack point and entry */
    # l, m$ }7 P( s: f' D+ g8 X: L9 F
  15.     void       *sp;                                     /**< stack point */
    9 n* m* b0 U4 q* e4 i
  16.     void       *entry;                                  /**< entry */) W3 X, O* x4 X- b8 J' U3 \
  17.     void       *parameter;                              /**< parameter */9 v1 L% f% ~2 l6 ^; D, e
  18.     void       *stack_addr;                             /**< stack address */
    ) {4 k" T+ J' r; B
  19.     rt_uint32_t stack_size;                             /**< stack size */6 T, b4 {; A' ?- `3 D; S
  20. & \1 S$ {* o# k- T" U( b/ L
  21.     /* error code */
    + S6 ~1 `' y. ~5 E
  22.     rt_err_t    error;                                  /**< error code */; A( i  t' ~7 g" ~
  23. * R0 ~' G0 C# v6 I' }  D
  24.     rt_uint8_t  stat;                                   /**< thread status */( M. I5 p0 s  {  J6 B# s
  25. 5 Y( H4 P% ^! e8 `
  26.     /* priority */
    6 e  M) n! z0 ~$ }+ ]3 W
  27.     rt_uint8_t  current_priority;                       /**< current priority */5 h1 U: q. J  A4 o& v2 ]$ D; s  B" B3 ]
  28.     rt_uint8_t  init_priority;                          /**< initialized priority */
复制代码
其中 tlist 成员是线程的链表节点,后面要把线程插入到各种双向链表中便是通过该链表节点实现,该链表节点定义如下:
2 n: A, E; H% q& ~* |9 n; _2 o- j! c
  1. struct rt_list_node
    3 a8 s) V7 x3 k; }. t
  2. {
    % y7 Z; c1 @9 X6 c  w
  3.     struct rt_list_node *next;                          /**< point to next node. */
    4 z3 F+ J& N- \2 r
  4.     struct rt_list_node *prev;                          /**< point to prev node. */
    ! v" a1 ^; R* q; D0 j
  5. };9 G& |0 m9 o" D4 @$ j
  6. typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */
复制代码
线程初始化通过函数 rt_thread_init(struct rt_thread *thread) 实现,主要进行线程控制块相关成员的初始化以及初始化线程栈
" |# G' c! F& L) U; L3 B具体实现如下所示:
% ]3 |6 g! C7 Y9 I
  1. static rt_err_t _rt_thread_init(struct rt_thread *thread,' y% \; u3 u6 r! x
  2.                                 const char       *name,; j0 V3 S6 N) V. l
  3.                                 void (*entry)(void *parameter),
    ( A! q" Y8 c1 P2 w! ?; X4 {
  4.                                 void             *parameter,
    # z% Q4 P9 Q, `2 O% ^. ^
  5.                                 void             *stack_start,
    % c9 p: H7 e6 R; @
  6.                                 rt_uint32_t       stack_size,% t3 Y3 B2 W- @1 A: ?0 c& Q1 v* G
  7.                                 rt_uint8_t        priority,
    / G4 i+ H' h$ _- a
  8.                                 rt_uint32_t       tick)9 t7 ~  j0 X0 n: X5 n) I) Z, {" E
  9. {
    1 |0 |2 B7 c7 ]/ k7 }5 m2 F
  10.     /* init thread list */
    . P) ^% b7 [" G# @, ?
  11.     rt_list_init(&(thread->tlist));+ `+ H! {% S+ T9 ]7 i

  12. . h$ X. }. Y; L9 D! [% C9 }/ R
  13.     thread->entry = (void *)entry;* F1 C4 ~& D! z; A+ e
  14.     thread->parameter = parameter;; l2 m# s& x3 Q
  15. . n. S* g3 `- k# V$ q4 U+ o, R$ [
  16.     /* stack init */8 L: W  }' v- J& C+ P* D
  17.     thread->stack_addr = stack_start;4 v' [7 I. J# l& }; ~( @5 I0 |
  18.     thread->stack_size = stack_size;: X6 B, p% V2 S8 p

  19. $ B6 l6 A& L1 a  a+ `, E
  20.     /* init thread stack */
    : R# \. q- L. O7 k
  21.     rt_memset(thread->stack_addr, '#', thread->stack_size);
    ; b# A  Q* P) M
  22.     thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
    1 y+ g4 d4 s- j# f% _
  23.                                           (void *)((char *)thread->stack_addr + thread->stack_size - 4),
    ; a' `2 ]  D& e& s9 h9 D6 C
  24.                                           (void *)rt_thread_exit);0 X, }: l* A. o

  25. 0 J5 m. P# y) h! Y) @
  26.     /* priority init */
    8 Z% {6 ~$ m) s0 d( B& X
  27.     RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);/ F2 o$ m" c* b$ ?5 u& l0 V. o* `
  28.     thread->init_priority    = priority;5 c: ^# _- \$ y; A1 E% e. ~/ k
  29.     thread->current_priority = priority;
    & W8 k, u' P6 D# a8 X
  30. / S  c1 E+ f' Y" B( P7 h
  31.     thread->number_mask = 0;# h" w# O$ K; Y( w
  32. ; f4 N8 K( i4 Z: [
  33.     /* tick init */$ L7 e# [" |4 O" m# c+ @2 ?( t& F
  34.     thread->init_tick      = tick;
    $ h7 K: F0 S: V
  35.     thread->remaining_tick = tick;
    $ s1 K" q: [# J

  36. 3 W6 g) n* T/ I) f* `& ]" O
  37.     /* error and flags */. N& G- {1 s' Z8 n1 T
  38.     thread->error = RT_EOK;
    / I; W$ z' I( f
  39.     thread->stat  = RT_THREAD_INIT;6 u% g6 o4 W1 Z+ k. d) `

  40. ) L# s* s0 G( J% z
  41.     /* initialize cleanup function and user data */
    9 Z" E- q9 {' v' V# `( Y1 N0 B
  42.     thread->cleanup   = 0;
    ( [* S; C6 u1 h/ J. y
  43.     thread->user_data = 0;# u# ^# s1 |; }; C3 l4 J6 g

  44. 8 j' q- H( c$ o8 @7 `
  45.     /* init thread timer */4 L5 E( t( d, M  i
  46.     rt_timer_init(&(thread->thread_timer),- c! o! `! A. O: R  N
  47.                   thread->name,7 M) `4 X- r8 U* F# L% }
  48.                   rt_thread_timeout,6 U* n& r/ R+ S% t7 b" ~+ B% N, a
  49.                   thread,
    ( c7 F% G3 j& A/ m
  50.                   0,
    5 P, s, |, O* b1 ?' w( ~$ q
  51.                   RT_TIMER_FLAG_ONE_SHOT);0 W7 J5 ^! G+ n2 h* U

  52. ( D' @' C: |7 Z( u) e' P5 D
  53.     RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));4 R/ e) H! r+ r6 g4 g( W

  54. $ c( ~+ b4 S$ e- v  A* R& a3 I
  55.     return RT_EOK;
    2 P6 _  B' y) v0 X/ M( h+ [) S
  56. }
复制代码
从上面的函数中可以看出线程栈的初始化由函数 rt_hw_stack_init() 来完成,每个线程的栈由三部分组成:自动加载到 CPU 寄存器的部分、手动加载到 CPU 寄存器的部分以及空闲栈。如下图所示:
( R& p9 t8 i0 j/ B3 v4 j$ E7 S 1.jpg ' l- b4 }0 i: R& \! e. Z* [6 _
初始化后除了空闲栈部分其他值都变成 0xdeadbeef,线程第一次运行时,自动加载到 CPU 部分的内容要预先设置好,
( k- f$ ~8 j' P4 ^+ l4 V) @包括 PC 指针、R0任务形参,其它设置为 0。
" c4 p% V7 C# y& D+ G4 s线程初始化后要插入到就绪列表中,通过函数 rt_list_insert_before() 实现,最后要运行线程则需要启动调度器,$ ]" r; e0 ?" \5 q  @
启用调度器通过函数 rt_system_scheduler_start() 实现,具体函数实现如下:
4 c# C5 v- V& e% W+ \
  1. <blockquote>void rt_system_scheduler_start(void)
复制代码
函数中 rt_hw_context_switch_to() 用于启动第一次线程切换,该函数通过触发 PendSV 中断来实现上下文切换,后面的4 s2 ^5 r5 a/ A% y0 y) ~. F
上下文切换则通过函数 rt_hw_context_switch() 实现。最后系统调度通过 rt_scheduer() 函数实现,其核心内容也是通过5 x1 K+ }6 Q$ ^" D1 L7 Y
获取下一个要执行的线程然后产生上下文切换,在此不详细说明。  L! f# \7 q& m
- Z8 ?& W/ V! N) }
7 I: B% y5 i4 X  |
第一次分享帖子,写得不好多多见谅。帖子内容有限,只是说明一下我个人对于其中的一点理解,各位有兴趣的还是得亲
! O1 ~7 W" t0 R* ~) u# H9 m7 B自去看书,个人觉得书是挺好的,由浅入深,循序渐进,但是看完书后最重要的还是得多实践,要想深入内核原理的还得. ^8 b/ r* C. D: t& A
慢慢啃源码。9 @4 Y% p: P" S, B/ H+ w

; T( l7 l- |, w$ y' G8 N, w
收藏 评论0 发布时间:2018-12-24 23:34

举报

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