嵌入式操作系统内核原理和开发(信号量)-1

上一篇 / 下一篇  2012-09-17 15:18:26 / 个人分类:杂谈

#P h6Cm^ l%[0  之前因为工作的原因,操作系统这 块一直没有继续写下去。一方面是自己没有这方面的经历,另外一方面就是操作系统比较复杂和琐碎,调试起来比较麻烦。目前在实际项目中,使用的实时操作系统 很多,很多国内的朋友也写过操作系统,有些项目现在还在维护和修改中,这是十分难得的。就我知道和熟悉的就有三个系统,比如51Testing软件测试网!l'S^.Y.KMJ

51Testing软件测试网EJc JO D I

  (1)RT-THREAD51Testing软件测试网yU2vfe ?t

.n s|)A#^ o$k^I0  (2)RAW-OS

f@ n\7l0

@T`9\Z3tv0  (3)ClearRTOS

7J;C-P(OC0

9rLtg2I0{1?^5~m0   这里有比较介绍一下,这三个系统是国内的三位朋友开发的。其中rt-thread时间比较久一点,模块也比较全,bsp、cpu、fs、lwip、 gui等辅助的代码也比较多,有兴趣的朋友可以到网站上面下载代码看一看。raw-os是我今年才发现的一个实时系统,从网站的注册时间和软件版本号上来 看,系统开发的时间不是很长,不过整个系统代码的结构非常清晰,是我重点推荐阅读的代码。如果朋友们自己download下来,好好看一下其中的代码,肯 定会有不少的收获。最后一个代码是作者李云在编写《专业嵌入式软件开发》这本书的时候,为了说明os的基本原理而开发的软件,前后设计了线程、互斥、内存、定时器、驱动框架等内容,值得一读。

hP$Z6@N:x/S0

d1C W!Nh8Q5F0  当然有了这么多优秀的代码,我觉得现在自己的工作就不是重新造一个车轮了,而是和大家分享这些优秀的代码是如何设计的。理解代码本身不是目的,关键是理解代码背后的基本思路。就我个人看过来,rt-thread和raw-os都可以用来学习, 不过raw-os更好一些,主要是因为作者将raw-os移植到的vc上面,学起来也十分方便,要是个人在使用过程中有什么疑问,可以通过邮件和作者及时 交流。不过由于raw-os的版本在一直在update之中,所以部分代码在前后稍微有点差别,不过这些都不是重点,暂时不了解的内容可以通过后面的了解 和学习逐步掌握,不会成为太大的障碍。

ct+f*J*\ R$f.nT*^v051Testing软件测试网2K$I{ i Q [

  就像今天的题目一样,我们重点介绍一下信号量的设计原理。首先看一下信号量的数据结构是怎么样的,

})Nk u"`/u{y.j5?0
typedef struct RAW_SEMAPHORE51Testing软件测试网 J#S6o4V^/G4d?
{
ekT&rLO~R s0 RAW_COMMON_BLOCK_OBJECT       common_block_obj;51Testing软件测试网 s FW4eU
 RAW_U32                       count;
H;YoB B9zp#J'y0 
|@8v {&x0} RAW_SEMAPHORE;

g6T4K'Zp9zRXZ r0   这些代码都是从raw-os上面摘抄下来的,这个版本是0.94版本,和最新的0.96版本有点差别。首先分析一下信号量的基本结构,其实非常简单,就 两个变量,其中comm_block_obj是一个通用类型,记录了当前结构的名称、类型和阻塞队列,而count就是计数,判断是否还有释放的资源。

;_5N9KQ&xz'C AB051Testing软件测试网&t nJ0PU#dP

   说到了信号量的操作,无非就是信号量的创建、获取、释放、删除操作,当然这里作者考虑的比较详细,在信号量释放的时候还分成了 WAKE_ONE_SEM和WAKE_ALL_SEM两种类型。意思很简单,就是当信号量来临的时候是唤醒一个等待线程呢,还是唤醒所有的等待线程呢,就 是这么回事。下面,我们就按照顺序介绍这几个函数,首先是创建函数,

SgK7B1VAt%mi*{m0

"rpX3MB#k3MCT0RAW_U16 raw_semaphore_create(RAW_SEMAPHORE *semaphore_ptr, RAW_U8 *name_ptr, RAW_U32 initial_count)
$g)h(j?rO?0{51Testing软件测试网^T"p7` Ymkr#t j
 #if (RAW_SEMA_FUNCTION_CHECK > 0)
9bO fm.hQ W5lt0 51Testing软件测试网6w F"{4K3E&XaV f t
 if (semaphore_ptr == 0) {51Testing软件测试网`L5I"bn^V1e_ cck
  
rkI ~ R9}n"|0  return RAW_NULL_OBJECT;
5J H ? ^6m1Kj${0 }
51Testing软件测试网&d0I"Q;|;L'V wd V

51Testing软件测试网 ].bq:R Kj

 if (initial_count == 0xffffffff) {

#t"{KV T L9} BtA051Testing软件测试网PJ&?C2t3dyzh

  return RAW_SEMOPHORE_OVERFLOW;

m)qF*O8hR051Testing软件测试网&y3[wPw4p+C

 }
nx&A+[ svY*W}~0 
%~:yX7_ gX|Zh0 #endif

,q:{/y2[v%_4e051Testing软件测试网.eN`*T(N6Yb;q

 /*Init the list*/
0V A:Q4Uzh0 list_init(&semaphore_ptr->common_block_obj.block_list);51Testing软件测试网J,{z Mw5Ec%f#c
 51Testing软件测试网/@%QP/o"`o6l-v
 /*Init resource*/
o:\4r(bCjn~v0 semaphore_ptr->count     = initial_count;                                51Testing软件测试网$l*zs*I PD"s K/sF
 51Testing软件测试网|.Sc4n6\(R JI5zC
 semaphore_ptr->common_block_obj.name = name_ptr; 51Testing软件测试网*Vb/[4tCV'ch|
 
n/Z$]Ne T0 semaphore_ptr->common_block_obj.block_way = 0;
?.`:kzCi yyB@Rr0 
\w.E*]MC%T0 return RAW_SUCCESS;
51Testing软件测试网2_z R,fS

51Testing软件测试网o&R[/~VL.x"S

}

6qE%S,hP])S7FWg0

8b h|Mf G Z0  看着初始化函数,我们发现信号量的初始化其实也非常简单,基本工作主要有:51Testing软件测试网4j1b.smv

51Testing软件测试网"z(xs/wC d6k8~em6T e

  (1)判断参数合法性;51Testing软件测试网`9lPEpG?

51Testing软件测试网8QP!nmj-lB]

  (2)初始化阻塞队列、名称等;

.PI Zmj,K @jr*{0

'hk#W$]$pe0  (3)初始化信号量的计数。

0bSmS!{u*w!s ?051Testing软件测试网x ? z,E$P7W
51Testing软件测试网"TMs:Z(G7k

  说完了这些,我们看看信号量的获取是怎么完成的,代码可能长度稍微长一些,不过也不用太紧张,51Testing软件测试网)i bhYJTs\z'^ { wt

E!Mz6[GnT&r4b0

{YPBcV0
51Testing软件测试网)?g,ya s7C"D

RAW_U16 raw_semaphore_get(RAW_SEMAPHORE *semaphore_ptr,  RAW_U32 wait_option)51Testing软件测试网.HW6ZdZ_
{
51Testing软件测试网5n4p"l[!JU

9ELrf;F%{9G2Ld0 RAW_U16 error_status;51Testing软件测试网/D(ZgE @w?'Mv

!kh:u&ZSL2t WL0 RAW_SR_ALLOC();

)N)p!f'k#SF$V },F-E0

"k H"L;Y?aMq0 #if (RAW_SEMA_FUNCTION_CHECK > 0)51Testing软件测试网mU r7u*ypf

Yq#Av:g0 if (semaphore_ptr == 0) {
u:mBs{C0  
)Zsw8\.l d)t$OL(c0  return RAW_NULL_OBJECT;51Testing软件测试网(X?HW x,nfS}
 }51Testing软件测试网3YmE/i j4v%k%[DB
 51Testing软件测试网ut"P6J^$QV
 if (raw_int_nesting) {

8d BTbL"F:n`%m051Testing软件测试网&Y `/f3~;i

  return RAW_NOT_CALLED_BY_ISR;51Testing软件测试网I~f"oY.i
 }
51Testing软件测试网t)@;Nc"eK.Gm

z-O&~:sO0 #endif51Testing软件测试网n#j.Yom%J[R
 
JGP^I0 51Testing软件测试网\wz.CT
 RAW_CRITICAL_ENTER();51Testing软件测试网vh$H9c%c Nq4f{
 if (semaphore_ptr->count) {                     
!Wp"_&P5~E+?&_y0  semaphore_ptr->count--;                                      

}et1ybP0

UV@l/Dv L+D0  RAW_CRITICAL_EXIT();51Testing软件测试网)MS)Fws!s
  
^*h-I8E#c.U0  return RAW_SUCCESS;51Testing软件测试网b!C7{cdi V3T
 }51Testing软件测试网Z'V6X }^*aR+x&RWp
 51Testing软件测试网RA6E:u{:JAmy;i
 /*Cann't get semphore, and return immediately if wait_option is  RAW_NO_WAIT*/51Testing软件测试网\ AamL
 if (wait_option == RAW_NO_WAIT) {

q:F!On3w-Dw'[#c[0hd0

#OSBU,BN}0  RAW_CRITICAL_EXIT();
az1~vU,_0  return RAW_NO_PEND_WAIT;
R8d;@)tX&I2F0 }     
:sZx,L(B2u0@,~0 51Testing软件测试网g6kgGx+Dy8~
 if (raw_sched_lock) {  
#T0Z:_^pu%f0  RAW_CRITICAL_EXIT(); 
wQ[,Vq0  return RAW_SCHED_DISABLE;51Testing软件测试网^@&x5oi L*D
 }

jr2N)z-^051Testing软件测试网V0Gz+H)__p.c9Y:w*J

 raw_pend_object(&semaphore_ptr->common_block_obj, raw_task_active, wait_option);51Testing软件测试网N2rC Ot$g m(Tu#W
 RAW_CRITICAL_EXIT();
51Testing软件测试网%kcI\ \L(g

51Testing软件测试网8c$T1z*p&@1j:wb

 raw_sched();
'DO!r0R:n%~ x*I&qT0 
J\A%fL8x0 error_status = block_state_post_process(raw_task_active, 0);51Testing软件测试网 `!?,s3Tmu8F B
 return error_status;
51Testing软件测试网|S4d+n}

51Testing软件测试网H4Y2h2n9K [)Y:~6C

}51Testing软件测试网;WF&K)bq

51Testing软件测试网s}8K-R#J2z

  信号量的获取情况比较复杂一些,这在长度上也体现出来了。不过没关系,我们一步一步看函数做了什么,

$?6l6}6f W051Testing软件测试网-x3`$iBQ,_h!eH9s

  (1)判断参数合法性;

.lV `-}/Z!j5Lz0

$z7wN0u Yy0  (2)判断当前函数是否处于中断处理的流程中,如果是选择返回;51Testing软件测试网6sE{'~3UjD @4~

51Testing软件测试网Cg[ J9T[l4\#g"@

  (3)判断当前count是否为0,如果不为 0,则减1返回;51Testing软件测试网 G$H:aSk oml

|!JxU$kDo0  (4)如果当前count是0,且线程不愿意等待,那么选择返回;

_"o?]p0

sFtOp?!h^H0  (5)如果当前禁止调度,那么依然选择返回;

9t6})rJ'e0?Q{051Testing软件测试网"@/Ry8DY/p!\]p-X

  (6)当前线程将自己挂起,从ready队列中删除,把自己pend到信号量的阻塞队列中;

d `G(Sw/@0

H(G4qR6F`T0  (7)阻塞的线程再次获得了运行的机会,我们从task数据结构获得返回结果,此时也不一定是因为获得了资源的缘故哦。51Testing软件测试网[$O$om2OP6e X,S


TAG:

 

评分:0

我来说两句

Open Toolbar