第4章第3节 实时事件触发的实时抢…
来源:互联网 发布:中国程序员联合开发网 编辑:程序博客网 时间:2024/06/16 02:29
目前更新到5.3节,请在http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档
本节源代码请在http://dl.dbank.com/c0z9e2wbch下载
下面来看一下MDS_TaskDelay函数的代码:
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00196行,函数返回值分4种,RTN_SUCD:
入口参数uiDelayTick是需要delay的tick数。
00206~00209行,idle任务不能延迟。
00212行,对任务delay的时间进行判断,不是delay
00222行,当前任务需要切换到delay状态,从ready表拆除。
00225行,清除任务的ready状态。
00227行,更新当前任务的延迟时间。
00231行,对任务delay的时间进行判断,不是永久delay的情况走下面分支。
00233行,计算该任务需要delay到的tick数值,存入TCB中。
00236行,将当前任务的M_TCBQUE型ready节点指针强制转换为M_TCBQUE型指针。
00237行,从任务的ready节点找到delay节点指针。
00240行,将该任务加入delay表。
00243行,在该任务的TCB中的任务标志uiTaskFlag中设置标志,表明该任务已经处于delay表中。
00247行,增加任务的delay状态。
00251~00255行,delay
00258行,任务相关变量、ready表、delay表的操作已经完成,调用MDS_TaskSwiSched函数触发软中断,开始任务调度。
00263行,将strTaskOpt中的uiDelayTick变量作为返回值返回给上级父函数。uiDelayTick变量中的返回值会在248行仅发生任务切换时存入,或者在任务调度函数MDS_TaskDelayTabSched中delay时间耗尽时存入,或者在MDS_TaskWake函数中由其它任务唤醒时存入。
261行与258行在代码编写上是连在一起的,但在执行时可能会有时间间隔,258行会发生任务调度,中间可能会插入其它任务的执行过程。
MDS_TaskWake函数正好与MDS_TaskDelay函数相反,它将处于delay状态的任务从delay表拆除,添加到ready表,并修改任务的一些相关状态变量,代码如下,不再详细介绍。
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
现在我们已经拥有了ready和delay两种任务状态,那么在tick中断里就需要对这两个调度表进行操作。这个过程分为2步,先对delay表操作,将delay时间耗尽的任务从delay表拆除,挂入ready表,使之能参与到ready表的调度之中,然后再对ready表进行调度。
来看调度函数的代码:
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
有关ready表调度的代码被封装到了353行的MDS_TaskReadyTabSched函数里面,本节新增的delay表调度代码被封装到350行的MDS_TaskDelayTabSched函数里面,下面来看看MDS_TaskDelayTabSched函数的代码:
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00412行,从delay表中获取第一个子节点pstrDelayNode。
00415行,判断第一个子节点是否为空。
00418行,循环查询delay表中的任务。执行到此行说明delay链表不为空,说明有处于delay状态的任务。
000421行,将M_CHAIN型的指针pstrDelayNode强制转换为M_TCBQUE型的指针pstrDelayQue。
00422行,通过pstrDelayQue获取TCB指针。
00423行,通过TCB指针获取到任务delay状态耗尽时的tick数值。
00426行,被查询的任务delay状态在当前tick已经耗尽,需要从delay状态转换为ready状态,走下面分支。
00429行,将该任务从delay表中拆除。
00432行,从TCB中的任务标志uiTaskFlag中去除任务处于delay表的标志。
00435行,去除任务的delay状态。
00438行,将delay耗尽的返回值存入strTaskOpt中的uiDelayTick变量,供MDS_TaskDelay函数返回时使用。
00441~00451行,将该任务添加到ready表中。
00454~00461行,若下个节点为空,说明delay表已经遍历完毕,退出调度函数。若下个节点不为空则继续查询。
00463~00466行,走到此分支说明当前节点delay时间还没有耗尽,因为delay表是按照delay耗尽时间从少到多的顺序排列的,因此后面节点的时间也不会耗尽,不需要再遍历,直接返回。
下面介绍一下与软中断相关的函数。
Mindows中使用MDS_TaskSwiSched函数触发软中断,MDS_TaskSwiSched函数里面使用MDS_RunInInt函数对芯片当前的状态做了一个判断,避免在中断中触发软中断造成异常,实际触发软中断的函数是MDS_TaskOccurSwi函数。
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
MDS_RunInInt调用了汇编函数MDS_GetChipMode获取芯片的工作模式,若不是USR模式则表明当前是在中断中运行。
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
MDS_GetChipMode函数是一个汇编函数,CPSR寄存器中的bit4~bit0中保存的就是当前模式,它将CPSR寄存器的bit4~bit0作为函数返回值保存到R0中。
00114
00115
00116
00117
00118
00119
00120
00121
MDS_TaskOccurSwi函数也是一个汇编函数,它有一个入口参数,用来表明该软中断的功能,C语言的函数原型为
MDS_TaskOccurSwi(U32
汇编语言的源代码为:
00127
00128
00129
00130
00131
00132
00133
00130行,执行“SWI”汇编指令,该指令会触发软中断,将PC指针跳转到软中断向量表。在startup.s文件的软中断向量表里面使用MDS_SwiContextSwitch函数作为软中断的服务函数,它的功能与tick中断的MDS_TickContextSwitch函数功能非常相似,都是用来调度任务的,但还是有一些不同的地方。
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00058行,将返回的LR寄存器地址多加4字节,这是因为在进入MDS_TickContextSwitch函数时硬件会自动多加4字节,为了使MDS_SwiContextSwitch函数与MDS_TickContextSwitch函数的栈格式相同,这里先多加4字节,在MDS_SwiContextSwitch函数返回前会再多减去4字节。
00062~00064行,调用软中断处理函数MDS_SwiIsr。注意,这里不能使用R0寄存器,因为此时R0中保存的是MDS_TaskOccurSwi函数传递进来的入口参数。
00067~00085行,寄存器组备份还原过程,与MDS_TickContextSwitch函数完全一致。
00086行,函数返回前减去前面多加的4字节。
00087行,软中断调度完成,使用MOVS指令返回,这点与tick中断所使用的ISR中断不同。
MDS_SwiIsr函数才是真正的软中断处理过程,使用C语言编写,所有的软中断处理过程都在这个函数内实现。
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00094行,入口参数uiSwiNo从MDS_TaskOccurSwi函数开始,被保存在R0中,经历了MDS_SwiContextSwitch函数传递给MDS_SwiIsr函数。
00097行,软中断调度的中断走此分支。
00100行,在软中断中调度任务,只需要调度ready表。delay表的调度是以tick为周期的,在tick中断中才能调度。
00102行,非软中断调度产生的软中断走此分支。
00105行,更新调度中所使用的全局变量。尽管是非软中断调度,但由于该函数的上级函数MDS_SwiContextSwitch会对寄存器组进行备份、恢复,因此此处也需要更新一下调度中所使用的全局变量。
00107行,选择不同的软中断命令分支。
00109~00113行,解锁中断命令,调用MDS_IntEnable函数解锁中断。MDS_IntEnable函数是汇编函数,直接修改CPSR中的全局中断控制位允许中断产生。
00115~00119行,锁中断命令,调用MDS_IntDisable函数锁中断。MDS_IntDisable函数是汇编函数,直接修改CPSR中的全局中断控制位禁止中断产生。
00121~00127行,用户可以将自定义的软中断命令放在此处执行。
MDS_IntEnable和MDS_IntDisable函数直接操作的对象是SVC模式下SPSRSVC寄存器,当程序从SVC模式返回到USR模式时,SPSRSVC寄存器就会被恢复到CPSR中,达到修改CPSR寄存器控制中断产生的目的。
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
提供给用户使用的锁中断函数是MDS_IntLock,解锁中断函数是MDS_IntUnlock,它们同软中断调度函数一样,都是通过调用MDS_TaskOccurSwi函数触发软中断,通过入口参数区分功能,在软中断服务函数MDS_SwiIsr里实现自己的功能。
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00653~00656行,在还没有进入操作系统状态前不能执行此函数。
00659~00662行,在中断中不能执行此函数。
00665~00672行,guiIntLockCounter变量里存放的是锁中断、解锁中断的次数,初始化为0,当guiIntLockCounter为0时,说明是第一次执行该函数,只有第一次执行该函数时才操作硬件寄存器,执行锁中断动作。
需要注意一点,669行guiIntLockCounter变量自加需要在667行MDS_TaskOccurSwi函数之后执行,因为MDS_IntLock函数可能会重入,这样做在函数重入时,不会使guiIntLockCounter变量计数产生错误。
00674~00679行,guiIntLockCounter变量没有溢出则做自加操作,返回锁中断成功,是一个虚假的锁中断过程。
00680~00683行,guiIntLockCounter变量溢出,返回成功。
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
MDS_IntUnlock函数与MDS_IntLock函数,非常相似,只有当guiIntLockCounter变量为1时才操作硬件寄存器,执行解锁中断动作。
本节操作系统部分的内容就介绍到这里。
- 第4章第3节 实时事件触发的实时抢…
- 第4章第3节 实时事件触发的实时抢…
- 第4章第3节 实时事件触发的实时抢…
- 第4章第2节 定时器触发的实时抢占…
- 第4章第2节 定时器触发的实时抢占…
- Wireshark使用教程:第4章 实时捕捉数据包
- 第2章 实时系统概念
- 第2章 实时系统概念
- DataGridView DataGridViewCheckBoxColumn编辑时实时触发事件
- DataGridView DataGridViewCheckBoxColumn编辑时实时触发事件
- DataGridView DataGridViewCheckBoxColumn编辑时实时触发事件
- Dive into python 第4章 自省的威…
- 第2章第3节 ARM7芯片的函数调用标…
- 第3章第1节 两个固定任务之间的切…
- Linux 实时技术与典型实现分析, 第 2 部分: Ingo Molnar 的实时补丁
- 使用实时 Java 进行开发,第 1 部分: 探索实时 Java 的独特功能
- Linux 实时技术与典型实现分析, 第 2 部分: Ingo Molnar 的实时补丁
- 《嵌入式实时操作系统uC/OS-II》_第2章_实时系统概念
- 第4章 Mindows操作系统
- 第4章第1节 Mindows的文件组织结构
- 第4章第2节 定时器触发的实时抢占…
- 第4章第2节 定时器触发的实时抢占…
- 第4章第3节 实时事件触发的实时抢…
- 第4章第3节 实时事件触发的实时抢…
- MXNet的数据读取:data.py源码详解
- 第4章第3节 实时事件触发的实时抢…
- Vmware 将kalilinux装进 U盘
- cookie 和session 的区别详解
- JavaScript(jquery)写的像素游戏贪吃蛇
- zabbix使用sendEmail实现邮件报警
- 第4章第4节 任务切换钩子函数
- 第4章第5节 任务创建和任务删除钩…